Go Back   Cockos Incorporated Forums > REAPER Forums > REAPER Bug Reports

Reply
 
Thread Tools Display Modes
Old 05-09-2022, 07:36 AM   #1
Phazma
Human being with feelings
 
Join Date: Jun 2019
Posts: 2,918
Default Simple windowed stretching algorithm broken?

I assume that Reaper's "simple windowed" algorithm is intended to be what is often referred to as "cyclic stretching" algorithm. But compared to similar algorithms in other software it sounds.. rather odd.

Here a video where I compare a breakbeat sample stretched with TAL's, Akaizer's and Logic's cyclic stretching modes (in this order) to Reaper's simple windowed stretching (last one) and you will hear what I mean:

https://vimeo.com/707819983

As you can hear in Reaper the stretched sample sounds totally crushed. I bet some bug has sneaked into the implementation of this algorithm which makes it sound so low quality? I hope this can be fixed so that the "simple windowed" algorithm can become a useful "cyclic" stretching algorithm.

Last edited by Phazma; 09-14-2022 at 03:29 AM.
Phazma is online now   Reply With Quote
Old 09-14-2022, 03:29 AM   #2
Phazma
Human being with feelings
 
Join Date: Jun 2019
Posts: 2,918
Default

Bump.
Phazma is online now   Reply With Quote
Old 09-14-2022, 04:50 AM   #3
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 16,009
Default

If it sounds different to other algorithms that's expected -- if you can point to a project using this mode that sounds different to a previous REAPER version, then that would be helpful. It may have always been "broken."
Justin is offline   Reply With Quote
Old 09-14-2022, 06:47 AM   #4
Phazma
Human being with feelings
 
Join Date: Jun 2019
Posts: 2,918
Default

I think in REAPER it always sounded like this and my guess was that it always has been "broken".

As the "granularization" (for lack of a better word) itself sounds pretty much identical to all these algorithms from other software, but the sound quality is somehow much worse (lacking high frequencies and sounding noisy as if heavy sample rate reduction and bitcrushing are going on), I thought something had gone wrong with the implementation. I believed that it was meant to sound like the other algorithms in my video but some line of code regarding resampling has an error and nobody reported it before because everybody thought it was intentional.

But if what you are hearing from the last audio in my demo video is how the algorithm is meant to sound then probably this should rather be a feature request for an actual, proper "cyclic time stretching" mode like the other audios in my video.
Phazma is online now   Reply With Quote
Old 12-07-2022, 07:05 AM   #5
mozart999uk
Human being with feelings
 
Join Date: Nov 2010
Posts: 1,853
Default

Quote:
Originally Posted by Phazma View Post
I think in REAPER it always sounded like this and my guess was that it always has been "broken".

As the "granularization" (for lack of a better word) itself sounds pretty much identical to all these algorithms from other software, but the sound quality is somehow much worse (lacking high frequencies and sounding noisy as if heavy sample rate reduction and bitcrushing are going on), I thought something had gone wrong with the implementation. I believed that it was meant to sound like the other algorithms in my video but some line of code regarding resampling has an error and nobody reported it before because everybody thought it was intentional.

But if what you are hearing from the last audio in my demo video is how the algorithm is meant to sound then probably this should rather be a feature request for an actual, proper "cyclic time stretching" mode like the other audios in my video.
Did you get any further with a FR for this?

I found this video on YT: https://www.youtube.com/watch?v=RUmOOFg0UNE

Last edited by mozart999uk; 12-07-2022 at 07:07 AM. Reason: thought of something else
mozart999uk is online now   Reply With Quote
Old 12-07-2022, 03:20 PM   #6
Phazma
Human being with feelings
 
Join Date: Jun 2019
Posts: 2,918
Default

Quote:
Originally Posted by mozart999uk View Post
Did you get any further with a FR for this?

I found this video on YT: https://www.youtube.com/watch?v=RUmOOFg0UNE
I don't remember if I have created a FR already and currently I am too busy to search or deal with it (maybe I find time this weekend).

But I definitely still very much wish for a proper cyclic time stretch algorithm.
Phazma is online now   Reply With Quote
Old 12-22-2022, 03:16 AM   #7
lewloiwc
Human being with feelings
 
Join Date: Aug 2021
Posts: 134
Default

By first pitch shifting with Simple windowed and then resampling with Linear Interpolation, I was able to reproduce 100% of the current REAPER algorithm.
In other words, to solve this problem, I believe that the order of pitch shifting and resampling should simply be swapped.

Translated with www.DeepL.com/Translator (free version)
lewloiwc is offline   Reply With Quote
Old 12-22-2022, 03:39 AM   #8
mozart999uk
Human being with feelings
 
Join Date: Nov 2010
Posts: 1,853
Default

I'm guessing from Justin's comment above that it's not considered a bug, which is fair enough. Maybe we should create a FR for this instead?
mozart999uk is online now   Reply With Quote
Old 12-22-2022, 03:00 PM   #9
Phazma
Human being with feelings
 
Join Date: Jun 2019
Posts: 2,918
Default

Give me a little more time guys, I will create a proper FR in the next days (before 2023).
Phazma is online now   Reply With Quote
Old 12-23-2022, 07:00 AM   #10
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 16,009
Default

Quote:
Originally Posted by lewloiwc View Post
By first pitch shifting with Simple windowed and then resampling with Linear Interpolation, I was able to reproduce 100% of the current REAPER algorithm.
In other words, to solve this problem, I believe that the order of pitch shifting and resampling should simply be swapped.

Translated with www.DeepL.com/Translator (free version)
Correct, here is the code:

https://github.com/justinfrankel/WDL...e_pitchshift.h

Hmm, perhaps we should use the current mode when speeding up content (pitch shifting down, then resampling to speed up), and the reverse when slowing down (resampling to slow down, then pitch adjusting up)
Justin is offline   Reply With Quote
Old 12-23-2022, 09:28 AM   #11
Phazma
Human being with feelings
 
Join Date: Jun 2019
Posts: 2,918
Default

Quote:
Originally Posted by Justin View Post
Correct, here is the code:

https://github.com/justinfrankel/WDL...e_pitchshift.h

Hmm, perhaps we should use the current mode when speeding up content (pitch shifting down, then resampling to speed up), and the reverse when slowing down (resampling to slow down, then pitch adjusting up)
Can the code be tried out somehow?

If you decide to update the algorithm as described and include it in an upcoming dev build I would be very happy to test it and give feedback/opinions
Phazma is online now   Reply With Quote
Old 12-23-2022, 03:16 PM   #12
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 16,009
Default

A new mode is coming in the next +dev series...
Justin is offline   Reply With Quote
Old 12-23-2022, 03:50 PM   #13
lewloiwc
Human being with feelings
 
Join Date: Aug 2021
Posts: 134
Default

I checked Texture Mode, which is Simple windowed in Ableton Live, and it seems that resampling is not actually used for time stretching.

I found it difficult to explain in words, so I would like to explain by posting the jsfx I created and a video of it.

The simplest possible code to express this is as follows.
Code:
spl0 = 0[b += pitch];
c === 3000 ? (
    c = 0;
    b = a
) : (
    c += 1;
);
a += rate;
spl1 *= post;
The "a" always advances along the time axis at the rate speed, and the "b = a" periodically executed determines the starting position of memory reading and advances the time of the "b" to perform time stretching.

Full Version Code
Code:
desc:math_exp_26 Texture Mode 0.0.4

slider1:size_slider=50<1,1000,0.1>Size (ms)
slider2:flux_slider=0<0,100,0.1>Flux (%)
slider3:rate_slider=1<0.01,10,0.01>Rate
slider4:pitch_slider=0<-24,24,1>Pitch (st)



@init //----------------------------------------------------------------

function fc(n)
(
    floor(n+0.5)
);

function lerp(a,b,t)
(
    (1 - t)*a + t*b;
);

function mem_lerp2(mem,x)
(
    lerp(
        mem[floor(x)*2],
        mem[floor(x)*2 + 2],
        x - floor(x)
    );
);

function fade(x)
(
    cos($pi*(x - 0.5));
);



mem = 0;

file_handle = file_open(#file);
file_nch = 'rqsr';
file_riff(file_handle,file_nch,srate);
file_len = file_avail(file_handle)/file_nch; 
file_mem(file_handle,mem,file_len*file_nch);
file_close(file_handle);



pitch = 2^(pitch_slider/12);
size = fc(size_slider*(srate/1000)/pitch);

cnt_mem_global = -size*4;

cnt_mem_a = 0;
pitch_a = 0;
cnt_fade_a = 0;

cnt_mem_b = 0;
pitch_b = 0;
cnt_fade_b = 0.5;

size_lock = 0;
fade_lock = 0;

cnt_switch = 0;
switch = 0;
switch_ = 0;



@slider //----------------------------------------------------------------

pitch = 2^(pitch_slider/12);
size = fc(size_slider*(srate/1000)/pitch);

flux = flux_slider*0.01;



@sample //----------------------------------------------------------------

switch === 0 ? (
    cnt_mem_a = cnt_mem_global;
    pitch_a = pitch;
    cnt_fade_a = 0;
);

switch === 1 ? (
    cnt_mem_b = cnt_mem_global;
    pitch_b = pitch;
    cnt_fade_b = 0;
);

switch === 0 || switch === 1 ? (
    size_lock = size2;
    fade_lock = 0.5/size_lock;
);

spl0 =
    mem_lerp2(mem    ,cnt_mem_a)*fade(cnt_fade_a) +
    mem_lerp2(mem    ,cnt_mem_b)*fade(cnt_fade_b);
spl1 =
    mem_lerp2(mem + 1,cnt_mem_a)*fade(cnt_fade_a) +
    mem_lerp2(mem + 1,cnt_mem_b)*fade(cnt_fade_b);

cnt_switch < size_lock - 1 ? (
    cnt_switch += 1;
    switch = -1;
) : (
    cnt_switch = 0;
    switch = switch_ = !switch_;
);

cnt_mem_a += pitch_a;
cnt_mem_b += pitch_b;

cnt_fade_a += fade_lock;
cnt_fade_b += fade_lock;

cnt_mem_global += rate_slider;



size2 = size*lerp(1,rand(2),flux);



@serialize //----------------------------------------------------------------

file_string(0,#file);



@gfx //----------------------------------------------------------------

gfx_getdropfile(0,#file);

gfx_set(0.4);
gfx_rect(3,3,gfx_w - 6,gfx_h - 6,0);
gfx_x = 0;
gfx_y = 0;
gfx_drawstr("Drag and drop audio files here",5,gfx_w,gfx_h);
Texture Mode is only 50% fade, so I did not know if other % fade settings are possible.

lewloiwc is offline   Reply With Quote
Old 12-23-2022, 04:30 PM   #14
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 16,009
Default

yeah simple windowed is pitch-shifting + optional resampling. If you want timestretch + optional resampling, try SoundTouch, that's what it does. Though I guess it tries to make everything fit, which might not be what you're looking for. Maybe it's time to do a new timestretch + optional resample mode, using the higher quality resample modes we have, too. Can actually base it somewhat on Rrreeeaaa (replacing the polyphase synthesis component with window overlapping), mmm.

Last edited by Justin; 12-23-2022 at 04:58 PM.
Justin is offline   Reply With Quote
Old 12-24-2022, 07:17 AM   #15
mozart999uk
Human being with feelings
 
Join Date: Nov 2010
Posts: 1,853
Default

Does anyone here have the facility to compare any new modes to the original cyclic / akai timestretch? Unfortunately not got access to a s series sampler any more 🙁
mozart999uk is online now   Reply With Quote
Old 12-24-2022, 05:56 PM   #16
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 12,203
Default

Quote:
Originally Posted by mozart999uk View Post
Does anyone here have the facility to compare any new modes to the original cyclic / akai timestretch? Unfortunately not got access to a s series sampler any more ��
https://the-akaizer-project.blogspot.com/
(if you don't know it yet)
nofish is offline   Reply With Quote
Old 12-24-2022, 03:06 PM   #17
Vagelis
Human being with feelings
 
Vagelis's Avatar
 
Join Date: Oct 2017
Location: Larisa, Greece
Posts: 3,911
Default

Quote:
Originally Posted by Justin View Post
Maybe it's time to do a new timestretch + optional resample mode, using the higher quality resample modes we have, too. Can actually base it somewhat on Rrreeeaaa (replacing the polyphase synthesis component with window overlapping), mmm.
That would be amazing! Also it would be really useful if we could change the window size with a slider to any window size we want instead of the premade values from the dropdown menu. In ableton it's possible to automate it with an envelope which is super useful for precise time stretching by changing the size in realtime.
Vagelis is offline   Reply With Quote
Old 12-24-2022, 07:10 AM   #18
Phazma
Human being with feelings
 
Join Date: Jun 2019
Posts: 2,918
Default

Quote:
Originally Posted by lewloiwc View Post

Full Version Code
Code:
desc:math_exp_26 Texture Mode 0.0.4

slider1:size_slider=50<1,1000,0.1>Size (ms)
slider2:flux_slider=0<0,100,0.1>Flux (%)
slider3:rate_slider=1<0.01,10,0.01>Rate
slider4:pitch_slider=0<-24,24,1>Pitch (st)



@init //----------------------------------------------------------------

function fc(n)
(
    floor(n+0.5)
);

function lerp(a,b,t)
(
    (1 - t)*a + t*b;
);

function mem_lerp2(mem,x)
(
    lerp(
        mem[floor(x)*2],
        mem[floor(x)*2 + 2],
        x - floor(x)
    );
);

function fade(x)
(
    cos($pi*(x - 0.5));
);



mem = 0;

file_handle = file_open(#file);
file_nch = 'rqsr';
file_riff(file_handle,file_nch,srate);
file_len = file_avail(file_handle)/file_nch; 
file_mem(file_handle,mem,file_len*file_nch);
file_close(file_handle);



pitch = 2^(pitch_slider/12);
size = fc(size_slider*(srate/1000)/pitch);

cnt_mem_global = -size*4;

cnt_mem_a = 0;
pitch_a = 0;
cnt_fade_a = 0;

cnt_mem_b = 0;
pitch_b = 0;
cnt_fade_b = 0.5;

size_lock = 0;
fade_lock = 0;

cnt_switch = 0;
switch = 0;
switch_ = 0;



@slider //----------------------------------------------------------------

pitch = 2^(pitch_slider/12);
size = fc(size_slider*(srate/1000)/pitch);

flux = flux_slider*0.01;



@sample //----------------------------------------------------------------

switch === 0 ? (
    cnt_mem_a = cnt_mem_global;
    pitch_a = pitch;
    cnt_fade_a = 0;
);

switch === 1 ? (
    cnt_mem_b = cnt_mem_global;
    pitch_b = pitch;
    cnt_fade_b = 0;
);

switch === 0 || switch === 1 ? (
    size_lock = size2;
    fade_lock = 0.5/size_lock;
);

spl0 =
    mem_lerp2(mem    ,cnt_mem_a)*fade(cnt_fade_a) +
    mem_lerp2(mem    ,cnt_mem_b)*fade(cnt_fade_b);
spl1 =
    mem_lerp2(mem + 1,cnt_mem_a)*fade(cnt_fade_a) +
    mem_lerp2(mem + 1,cnt_mem_b)*fade(cnt_fade_b);

cnt_switch < size_lock - 1 ? (
    cnt_switch += 1;
    switch = -1;
) : (
    cnt_switch = 0;
    switch = switch_ = !switch_;
);

cnt_mem_a += pitch_a;
cnt_mem_b += pitch_b;

cnt_fade_a += fade_lock;
cnt_fade_b += fade_lock;

cnt_mem_global += rate_slider;



size2 = size*lerp(1,rand(2),flux);



@serialize //----------------------------------------------------------------

file_string(0,#file);



@gfx //----------------------------------------------------------------

gfx_getdropfile(0,#file);

gfx_set(0.4);
gfx_rect(3,3,gfx_w - 6,gfx_h - 6,0);
gfx_x = 0;
gfx_y = 0;
gfx_drawstr("Drag and drop audio files here",5,gfx_w,gfx_h);
This jsfx is EXACTLY the stretching that I hope we will get in Reaper! I best like it with the size parameter at 25ms. If Reaper gets this stretching algorithm it would be amazing if it also allows us to set the window size to any number, perhaps via a number input box (rather than just some presets as simple windowed currently has).


Quote:
Originally Posted by Justin View Post
Maybe it's time to do a new timestretch + optional resample mode, using the higher quality resample modes we have, too. Can actually base it somewhat on Rrreeeaaa (replacing the polyphase synthesis component with window overlapping), mmm.
Wow this sounds interesting! So would it be 2 new modes, a new/updated pitchshift(+resampling) mode and a new timestretch(+resampling) mode, the latter based on Rrreeeaaa?

Would the window overlapping Rrreeeaaa sound somewhat like this?

https://streamable.com/jur5dk

That would be very cool because as much as Rrreeeaaa is a nice tool for sounddesign, sometimes it would be useful to have its smooth stretching sound applied in a way that is more true to the original audio without completely smearing transients. I can see that be useful not just for creative but also corrective time stretching.

Last edited by Phazma; 12-25-2022 at 08:15 AM.
Phazma is online now   Reply With Quote
Old 12-25-2022, 01:19 AM   #19
lewloiwc
Human being with feelings
 
Join Date: Aug 2021
Posts: 134
Default

I'm almost done with jsfx, so I'm posting it anyway.
I'm sleepy, so I'll do the explanation and minor code fixes next time I wake up, but one thing I want to mention is that I checked and Akaizer and Ableton Live's Texture Mode is 99% the same.

Code:
desc:math_exp_26 Texture Mode 0.1.1

slider1:size_slider=50<1,1000,0.1>Size (ms)
slider2:flux_slider=0<0,100,0.1>Flux (%)
slider3:rate_slider=1<0.01,10,0.01>Rate
slider4:pitch_slider=0<-24,24,1>Pitch (st)



@init //----------------------------------------------------------------

function frac(n)
(
    n - floor(n)
);

function fc(n)
(
    floor(n+0.5)
);

function lerp(a,b,t)
(
    (1 - t)*a + t*b;
);

function mem_lim(offset)
(
    floor(offset) < 0 ? 0 : floor(offset)[];
);

function mem_lerp_1ch(offset)
(
    lerp(
        mem_lim(offset),
        mem_lim(offset + 1),
        frac(offset)
    );
);

function mem_lagrange3_1ch(offset)
local(
    a,b,c,d,x
)
(
    a = mem_lim(offset - 1);
    b = mem_lim(offset);
    c = mem_lim(offset + 1);
    d = mem_lim(offset + 2);
    
    x = 1 + frac(offset);
    a - x*((a - b) + (1 - x)*0.5*((a - 2*b + c) + (2 - x)*0.3333333333333333*(a - 3*b + 3*c - d)));
);

function mem_lerp_2ch(mem,x)
(
    lerp(
        mem_lim(mem + floor(x)*2),
        mem_lim(mem + floor(x)*2 + 2),
        frac(x)
    );
);

function mem_lagrange3_2ch(mem,x)
local(
    a,b,c,d,x
)
(
    a = mem_lim(mem + floor(x)*2 - 2);
    b = mem_lim(mem + floor(x)*2);
    c = mem_lim(mem + floor(x)*2 + 2);
    d = mem_lim(mem + floor(x)*2 + 4);
    
    x = 1 + frac(x);
    a - x*((a - b) + (1 - x)*0.5*((a - 2*b + c) + (2 - x)*0.3333333333333333*(a - 3*b + 3*c - d)));
);

function fade(x)
(
    cos($pi*(x - 0.5));
);



mem = 0;

file_handle = file_open(#file);
file_nch = 'rqsr';
file_riff(file_handle,file_nch,srate);
file_len = file_avail(file_handle)/file_nch; 
file_mem(file_handle,mem,file_len*file_nch);
file_close(file_handle);



pitch = 2^(pitch_slider/12);



cnt_mem_global = 0;

size_lock = 0;
fade_lock = 0;

pitch_lock_a = 0;
cnt_mem_a = 0;
cnt_fade_a = 0;

pitch_lock_b = pitch;
cnt_mem_b = 0;
cnt_fade_b = 0.5;

cnt_switch = 0;
switch = 0;
switch_ = 0;



@slider //----------------------------------------------------------------

pitch = 2^(pitch_slider/12);
size = fc(size_slider*(srate/1000)/pitch);



@sample //----------------------------------------------------------------

switch === 0 || switch === 1 ? (
    size_lock = size*lerp(1,rand(2),flux_slider*0.01);
    fade_lock = 0.5/size_lock;
);

switch === 0 ? (
    pitch_lock_a = pitch;
    cnt_mem_a = cnt_mem_global - size_lock*pitch_lock_a + size_lock*rate_slider;
    cnt_fade_a = 0;
);

switch === 1 ? (
    pitch_lock_b = pitch;
    cnt_mem_b = cnt_mem_global - size_lock*pitch_lock_b + size_lock*rate_slider;
    cnt_fade_b = 0;
);

file_nch === 1 ? (
    spl1 = spl0 =
        mem_lagrange3_1ch(mem +   cnt_mem_a)*fade(cnt_fade_a) +
        mem_lagrange3_1ch(mem +   cnt_mem_b)*fade(cnt_fade_b);
) :
file_nch === 2 ? (
    spl0 =
        mem_lagrange3_2ch(mem    ,cnt_mem_a)*fade(cnt_fade_a) +
        mem_lagrange3_2ch(mem    ,cnt_mem_b)*fade(cnt_fade_b);
    spl1 =
        mem_lagrange3_2ch(mem + 1,cnt_mem_a)*fade(cnt_fade_a) +
        mem_lagrange3_2ch(mem + 1,cnt_mem_b)*fade(cnt_fade_b);
);

cnt_switch < size_lock - 1 ? (
    cnt_switch += 1;
    switch = -1;
) : (
    cnt_switch = 0;
    switch = switch_ = !switch_;
);

cnt_mem_a += pitch_lock_a;
cnt_mem_b += pitch_lock_b;

cnt_fade_a += fade_lock;
cnt_fade_b += fade_lock;

cnt_mem_global += rate_slider;



@serialize //----------------------------------------------------------------

file_string(0,#file);



@gfx //----------------------------------------------------------------

gfx_getdropfile(0,#file);

gfx_set(0.4);
gfx_rect(3,3,gfx_w - 6,gfx_h - 6,0);
gfx_x = 0;
gfx_y = 0;
gfx_drawstr("Drag and drop audio files here",5,gfx_w,gfx_h);
Translated with www.DeepL.com/Translator (free version)
lewloiwc is offline   Reply With Quote
Old 12-25-2022, 08:16 AM   #20
Vagelis
Human being with feelings
 
Vagelis's Avatar
 
Join Date: Oct 2017
Location: Larisa, Greece
Posts: 3,911
Default

Quote:
Originally Posted by lewloiwc View Post
I'm almost done with jsfx, so I'm posting it anyway.
I'm sleepy, so I'll do the explanation and minor code fixes next time I wake up, but one thing I want to mention is that I checked and Akaizer and Ableton Live's Texture Mode is 99% the same.
Sounds pretty good!

Another important function is the window types. Depending on the audio source and what we want to achieve, different windows types can change how the transients sound which is very useful for better sound quality.
A problem in Simple windowed is that there is only one window type with different fade values.

@Justin
Would it be possible to include different window types for this new mode just like in Rrreeeaaa?
Vagelis is offline   Reply With Quote
Old 12-27-2022, 07:20 PM   #21
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 16,009
Default

Thanks lewloiwc, that is incredibly instructive!

Check the latest +dev build

(here's what our stretcher does: http://1014.org/_/overlap.h.txt )

Last edited by Justin; 12-27-2022 at 08:23 PM.
Justin is offline   Reply With Quote
Old 12-28-2022, 12:46 AM   #22
Phazma
Human being with feelings
 
Join Date: Jun 2019
Posts: 2,918
Default

Thanks Justin for adressing this and thanks to lewloiwc for putting in the work and providing the script which made this possible!
Phazma is online now   Reply With Quote
Old 12-28-2022, 02:30 AM   #23
Vagelis
Human being with feelings
 
Vagelis's Avatar
 
Join Date: Oct 2017
Location: Larisa, Greece
Posts: 3,911
Default

Quote:
Originally Posted by Justin View Post
Thanks lewloiwc, that is incredibly instructive!

Check the latest +dev build

(here's what our stretcher does: http://1014.org/_/overlap.h.txt )

Thank you very much it's amazing, you guys rock!
Vagelis is offline   Reply With Quote
Old 12-28-2022, 04:27 AM   #24
mozart999uk
Human being with feelings
 
Join Date: Nov 2010
Posts: 1,853
Default

This is great. Thanks all 👍
mozart999uk is online now   Reply With Quote
Old 02-21-2023, 04:59 PM   #25
djtt
Human being with feelings
 
Join Date: Sep 2014
Posts: 9
Default

I would love to play with this myself, however I'm a blind guy that use a screen reader and keybord commands to use Reaper, so wonder, is it possible to rewrite this plugin with a standard open file window instead of drag and drop?
Quote:
Originally Posted by lewloiwc View Post
I'm almost done with jsfx, so I'm posting it anyway.
I'm sleepy, so I'll do the explanation and minor code fixes next time I wake up, but one thing I want to mention is that I checked and Akaizer and Ableton Live's Texture Mode is 99% the same.

Code:
desc:math_exp_26 Texture Mode 0.1.1

slider1:size_slider=50<1,1000,0.1>Size (ms)
slider2:flux_slider=0<0,100,0.1>Flux (%)
slider3:rate_slider=1<0.01,10,0.01>Rate
slider4:pitch_slider=0<-24,24,1>Pitch (st)



@init //----------------------------------------------------------------

function frac(n)
(
    n - floor(n)
);

function fc(n)
(
    floor(n+0.5)
);

function lerp(a,b,t)
(
    (1 - t)*a + t*b;
);

function mem_lim(offset)
(
    floor(offset) < 0 ? 0 : floor(offset)[];
);

function mem_lerp_1ch(offset)
(
    lerp(
        mem_lim(offset),
        mem_lim(offset + 1),
        frac(offset)
    );
);

function mem_lagrange3_1ch(offset)
local(
    a,b,c,d,x
)
(
    a = mem_lim(offset - 1);
    b = mem_lim(offset);
    c = mem_lim(offset + 1);
    d = mem_lim(offset + 2);
    
    x = 1 + frac(offset);
    a - x*((a - b) + (1 - x)*0.5*((a - 2*b + c) + (2 - x)*0.3333333333333333*(a - 3*b + 3*c - d)));
);

function mem_lerp_2ch(mem,x)
(
    lerp(
        mem_lim(mem + floor(x)*2),
        mem_lim(mem + floor(x)*2 + 2),
        frac(x)
    );
);

function mem_lagrange3_2ch(mem,x)
local(
    a,b,c,d,x
)
(
    a = mem_lim(mem + floor(x)*2 - 2);
    b = mem_lim(mem + floor(x)*2);
    c = mem_lim(mem + floor(x)*2 + 2);
    d = mem_lim(mem + floor(x)*2 + 4);
    
    x = 1 + frac(x);
    a - x*((a - b) + (1 - x)*0.5*((a - 2*b + c) + (2 - x)*0.3333333333333333*(a - 3*b + 3*c - d)));
);

function fade(x)
(
    cos($pi*(x - 0.5));
);



mem = 0;

file_handle = file_open(#file);
file_nch = 'rqsr';
file_riff(file_handle,file_nch,srate);
file_len = file_avail(file_handle)/file_nch; 
file_mem(file_handle,mem,file_len*file_nch);
file_close(file_handle);



pitch = 2^(pitch_slider/12);



cnt_mem_global = 0;

size_lock = 0;
fade_lock = 0;

pitch_lock_a = 0;
cnt_mem_a = 0;
cnt_fade_a = 0;

pitch_lock_b = pitch;
cnt_mem_b = 0;
cnt_fade_b = 0.5;

cnt_switch = 0;
switch = 0;
switch_ = 0;



@slider //----------------------------------------------------------------

pitch = 2^(pitch_slider/12);
size = fc(size_slider*(srate/1000)/pitch);



@sample //----------------------------------------------------------------

switch === 0 || switch === 1 ? (
    size_lock = size*lerp(1,rand(2),flux_slider*0.01);
    fade_lock = 0.5/size_lock;
);

switch === 0 ? (
    pitch_lock_a = pitch;
    cnt_mem_a = cnt_mem_global - size_lock*pitch_lock_a + size_lock*rate_slider;
    cnt_fade_a = 0;
);

switch === 1 ? (
    pitch_lock_b = pitch;
    cnt_mem_b = cnt_mem_global - size_lock*pitch_lock_b + size_lock*rate_slider;
    cnt_fade_b = 0;
);

file_nch === 1 ? (
    spl1 = spl0 =
        mem_lagrange3_1ch(mem +   cnt_mem_a)*fade(cnt_fade_a) +
        mem_lagrange3_1ch(mem +   cnt_mem_b)*fade(cnt_fade_b);
) :
file_nch === 2 ? (
    spl0 =
        mem_lagrange3_2ch(mem    ,cnt_mem_a)*fade(cnt_fade_a) +
        mem_lagrange3_2ch(mem    ,cnt_mem_b)*fade(cnt_fade_b);
    spl1 =
        mem_lagrange3_2ch(mem + 1,cnt_mem_a)*fade(cnt_fade_a) +
        mem_lagrange3_2ch(mem + 1,cnt_mem_b)*fade(cnt_fade_b);
);

cnt_switch < size_lock - 1 ? (
    cnt_switch += 1;
    switch = -1;
) : (
    cnt_switch = 0;
    switch = switch_ = !switch_;
);

cnt_mem_a += pitch_lock_a;
cnt_mem_b += pitch_lock_b;

cnt_fade_a += fade_lock;
cnt_fade_b += fade_lock;

cnt_mem_global += rate_slider;



@serialize //----------------------------------------------------------------

file_string(0,#file);



@gfx //----------------------------------------------------------------

gfx_getdropfile(0,#file);

gfx_set(0.4);
gfx_rect(3,3,gfx_w - 6,gfx_h - 6,0);
gfx_x = 0;
gfx_y = 0;
gfx_drawstr("Drag and drop audio files here",5,gfx_w,gfx_h);
Translated with www.DeepL.com/Translator (free version)
djtt is offline   Reply With Quote
Old 02-11-2024, 05:03 PM   #26
Suzuki
Human being with feelings
 
Suzuki's Avatar
 
Join Date: Jul 2022
Location: Japan
Posts: 882
Default

lewloiwc's Texture Mode JSFX is now in my ReaPack.
https://forum.cockos.com/showthread.php?t=285649
Suzuki is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 09:05 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.