TimeStretch
TimeStretch copied to clipboard
Real time usage
Hi!
Is the TimeStrech2 supposed to work in this way? or is it only allowed to worked on SC's NRT mode ? (NessWindow.ar substituted for debbuging)
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav"); // remember to free the buffer later.
//NessStretch (improved paulstretch version)
(
SynthDef(\pb_monoStretch2_Overlap2, { |out = 0, bufnum, stretch = 100, startPos = 0, fftSize = 8192, fftMax = 65536, hiPass = 0, lowPass=0, amp = 1, gate = 1|
var trigPeriod, sig, chain, trig, trig1, trig2, pos, jump, trigEnv, fftDelay, bigEnv, window0, window1, rVal, correlation, sum, localIn, rVal1, rVal2, outSig, analSig, fs0, fs1;
trigPeriod = (fftSize/SampleRate.ir);
trig = Impulse.ar(2/trigPeriod);
trig1 = PulseDivider.ar(trig, 2, 1);
trig2 = PulseDivider.ar(trig, 2, 0);
startPos = (startPos%1);
pos = Line.ar(startPos*BufFrames.kr(bufnum), BufFrames.kr(bufnum), BufDur.kr(bufnum)*stretch*(1-startPos));
jump = fftSize/stretch/2;
pos = [pos, pos + jump];
sig = PlayBuf.ar(1, bufnum, 1, trig1, pos, 1)*SinOsc.ar(1/(2*trigPeriod)).abs*0.5;
sig = sig.collect({ |item, i|
chain = FFT(LocalBuf(fftSize), item, hop: 1.0, wintype: 0);
chain = PV_Diffuser(chain, 1-trig1);
chain = PV_BrickWall(chain, hiPass);
chain = PV_BrickWall(chain, lowPass-1);
item = IFFT(chain, wintype: -1);
}).flatten;
//delay the signal so that all fftSizes line up (the will already be delayed by the fftSize
sig = DelayC.ar(sig, (3*fftMax/2)-(3*fftSize/2)+BlockSize.ir/SampleRate.ir, fftMax-fftSize+BlockSize.ir/SampleRate.ir);
sig[1] = DelayC.ar(sig[1], trigPeriod/2, trigPeriod/2);
sum = RunningSum.ar((sig[0]*sig[1]), fftSize/2)/RunningSum.ar((sig[0]*sig[0]), fftSize/2);
rVal = Latch.ar(sum, DelayC.ar(trig1+trig2, (3*fftMax/2)-(3*fftSize/2)+BlockSize.ir/SampleRate.ir, fftMax-fftSize+BlockSize.ir/SampleRate.ir)).clip(-1,1);
rVal = DelayC.ar(rVal, trigPeriod/2, trigPeriod/2);
localIn = LocalIn.ar(1).clip(-1,1);
localIn = DelayC.ar(localIn, trigPeriod/2-(BlockSize.ir/SampleRate.ir), trigPeriod/2-(BlockSize.ir/SampleRate.ir));
rVal1 = (Latch.ar(rVal, trig1)>=0).linlin(0,1,-1,1)*
Latch.ar(XFade2.ar(K2A.ar(1), localIn, EnvGen.kr(Env([-1,-1, 1], [trigPeriod, 0]), 1)), trig1);
rVal2 = (Latch.ar(rVal, trig2)>=0).linlin(0,1,-1,1)*
Latch.ar(XFade2.ar(K2A.ar(1), DelayC.ar(rVal1.clip(-1,1), trigPeriod/2, trigPeriod/2), EnvGen.kr(Env([-1,-1, 1], [trigPeriod, 0]), 1)), trig2);
LocalOut.ar(rVal2);
/* window0 = NessWindow.ar(trig1, rVal.abs, fftSize)*rVal1;
window1 = NessWindow.ar(trig2, rVal.abs, fftSize)*rVal2;*/
fs0 = (1-(Slew.ar(
1-Trig1.ar(trig1, fftSize/2/SampleRate.ir),
SampleRate.ir/(fftSize/2),
SampleRate.ir/(fftSize/2))));
fs0 = (fs0*pi/2).tan**2;
//fs0 = fs0*((1/(1+(2*fs0*(rVal.abs))+(fs0**2))).sqrt);
fs1 = (1-(Slew.ar(
1-Trig1.ar(trig2, fftSize/2/SampleRate.ir),
SampleRate.ir/(fftSize/2),
SampleRate.ir/(fftSize/2))));
fs1 = (fs1*pi/2).tan**2;
//fs1 = fs1*((1/(1+(2*fs1*(rVal.abs))+(fs1**2))).sqrt);
//window0 = fs0*rVal1;
//window1 = fs1*rVal2;
window0 = fs0*((1/(1+(2*fs0*(rVal.abs))+(fs0**2))).sqrt) * rVal1;
window1 = fs1*((1/(1+(2*fs1*(rVal.abs))+(fs1**2))).sqrt) * rVal2;
sig = DelayC.ar(sig, fftMax/SampleRate.ir, fftMax/SampleRate.ir);
outSig = [sig[0]*window0, sig[1]*window1];
bigEnv = EnvGen.kr(Env.asr(0,1,0), gate, doneAction:2);
hiPass = hiPass*SampleRate.ir/2;
lowPass = lowPass*SampleRate.ir/2;
outSig = HPF.ar(HPF.ar(outSig, (hiPass).clip(20, SampleRate.ir/2)), (hiPass).clip(20, SampleRate.ir/2));
outSig = LPF.ar(LPF.ar(outSig, (lowPass).clip(20, SampleRate.ir/2)), (lowPass).clip(20, SampleRate.ir/2));
Out.ar(out, Mix.new(outSig)*bigEnv*amp);
//Out.ar(out, [sig[0], sig[1], rVal1, window0, window1])
}).add;
)
Synth(\pb_monoStretch2_Overlap2, [\bufnum, b, \stretch, 2])
Hi!
Is the TimeStrech2 supposed to work in this way? or is it only allowed to worked on SC's NRT mode ? (NessWindow.ar substituted for debbuging)
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav"); // remember to free the buffer later. //NessStretch (improved paulstretch version) ( SynthDef(\pb_monoStretch2_Overlap2, { |out = 0, bufnum, stretch = 100, startPos = 0, fftSize = 8192, fftMax = 65536, hiPass = 0, lowPass=0, amp = 1, gate = 1| var trigPeriod, sig, chain, trig, trig1, trig2, pos, jump, trigEnv, fftDelay, bigEnv, window0, window1, rVal, correlation, sum, localIn, rVal1, rVal2, outSig, analSig, fs0, fs1; trigPeriod = (fftSize/SampleRate.ir); trig = Impulse.ar(2/trigPeriod); trig1 = PulseDivider.ar(trig, 2, 1); trig2 = PulseDivider.ar(trig, 2, 0); startPos = (startPos%1); pos = Line.ar(startPos*BufFrames.kr(bufnum), BufFrames.kr(bufnum), BufDur.kr(bufnum)*stretch*(1-startPos)); jump = fftSize/stretch/2; pos = [pos, pos + jump]; sig = PlayBuf.ar(1, bufnum, 1, trig1, pos, 1)*SinOsc.ar(1/(2*trigPeriod)).abs*0.5; sig = sig.collect({ |item, i| chain = FFT(LocalBuf(fftSize), item, hop: 1.0, wintype: 0); chain = PV_Diffuser(chain, 1-trig1); chain = PV_BrickWall(chain, hiPass); chain = PV_BrickWall(chain, lowPass-1); item = IFFT(chain, wintype: -1); }).flatten; //delay the signal so that all fftSizes line up (the will already be delayed by the fftSize sig = DelayC.ar(sig, (3*fftMax/2)-(3*fftSize/2)+BlockSize.ir/SampleRate.ir, fftMax-fftSize+BlockSize.ir/SampleRate.ir); sig[1] = DelayC.ar(sig[1], trigPeriod/2, trigPeriod/2); sum = RunningSum.ar((sig[0]*sig[1]), fftSize/2)/RunningSum.ar((sig[0]*sig[0]), fftSize/2); rVal = Latch.ar(sum, DelayC.ar(trig1+trig2, (3*fftMax/2)-(3*fftSize/2)+BlockSize.ir/SampleRate.ir, fftMax-fftSize+BlockSize.ir/SampleRate.ir)).clip(-1,1); rVal = DelayC.ar(rVal, trigPeriod/2, trigPeriod/2); localIn = LocalIn.ar(1).clip(-1,1); localIn = DelayC.ar(localIn, trigPeriod/2-(BlockSize.ir/SampleRate.ir), trigPeriod/2-(BlockSize.ir/SampleRate.ir)); rVal1 = (Latch.ar(rVal, trig1)>=0).linlin(0,1,-1,1)* Latch.ar(XFade2.ar(K2A.ar(1), localIn, EnvGen.kr(Env([-1,-1, 1], [trigPeriod, 0]), 1)), trig1); rVal2 = (Latch.ar(rVal, trig2)>=0).linlin(0,1,-1,1)* Latch.ar(XFade2.ar(K2A.ar(1), DelayC.ar(rVal1.clip(-1,1), trigPeriod/2, trigPeriod/2), EnvGen.kr(Env([-1,-1, 1], [trigPeriod, 0]), 1)), trig2); LocalOut.ar(rVal2); /* window0 = NessWindow.ar(trig1, rVal.abs, fftSize)*rVal1; window1 = NessWindow.ar(trig2, rVal.abs, fftSize)*rVal2;*/ fs0 = (1-(Slew.ar( 1-Trig1.ar(trig1, fftSize/2/SampleRate.ir), SampleRate.ir/(fftSize/2), SampleRate.ir/(fftSize/2)))); fs0 = (fs0*pi/2).tan**2; //fs0 = fs0*((1/(1+(2*fs0*(rVal.abs))+(fs0**2))).sqrt); fs1 = (1-(Slew.ar( 1-Trig1.ar(trig2, fftSize/2/SampleRate.ir), SampleRate.ir/(fftSize/2), SampleRate.ir/(fftSize/2)))); fs1 = (fs1*pi/2).tan**2; //fs1 = fs1*((1/(1+(2*fs1*(rVal.abs))+(fs1**2))).sqrt); //window0 = fs0*rVal1; //window1 = fs1*rVal2; window0 = fs0*((1/(1+(2*fs0*(rVal.abs))+(fs0**2))).sqrt) * rVal1; window1 = fs1*((1/(1+(2*fs1*(rVal.abs))+(fs1**2))).sqrt) * rVal2; sig = DelayC.ar(sig, fftMax/SampleRate.ir, fftMax/SampleRate.ir); outSig = [sig[0]*window0, sig[1]*window1]; bigEnv = EnvGen.kr(Env.asr(0,1,0), gate, doneAction:2); hiPass = hiPass*SampleRate.ir/2; lowPass = lowPass*SampleRate.ir/2; outSig = HPF.ar(HPF.ar(outSig, (hiPass).clip(20, SampleRate.ir/2)), (hiPass).clip(20, SampleRate.ir/2)); outSig = LPF.ar(LPF.ar(outSig, (lowPass).clip(20, SampleRate.ir/2)), (lowPass).clip(20, SampleRate.ir/2)); Out.ar(out, Mix.new(outSig)*bigEnv*amp); //Out.ar(out, [sig[0], sig[1], rVal1, window0, window1]) }).add; ) Synth(\pb_monoStretch2_Overlap2, [\bufnum, b, \stretch, 2])
I'm looking into making a realtime version of it.
Hi!
Is the TimeStrech2 supposed to work in this way? or is it only allowed to worked on SC's NRT mode ? (NessWindow.ar substituted for debbuging)
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav"); // remember to free the buffer later. //NessStretch (improved paulstretch version) ( SynthDef(\pb_monoStretch2_Overlap2, { |out = 0, bufnum, stretch = 100, startPos = 0, fftSize = 8192, fftMax = 65536, hiPass = 0, lowPass=0, amp = 1, gate = 1| var trigPeriod, sig, chain, trig, trig1, trig2, pos, jump, trigEnv, fftDelay, bigEnv, window0, window1, rVal, correlation, sum, localIn, rVal1, rVal2, outSig, analSig, fs0, fs1; trigPeriod = (fftSize/SampleRate.ir); trig = Impulse.ar(2/trigPeriod); trig1 = PulseDivider.ar(trig, 2, 1); trig2 = PulseDivider.ar(trig, 2, 0); startPos = (startPos%1); pos = Line.ar(startPos*BufFrames.kr(bufnum), BufFrames.kr(bufnum), BufDur.kr(bufnum)*stretch*(1-startPos)); jump = fftSize/stretch/2; pos = [pos, pos + jump]; sig = PlayBuf.ar(1, bufnum, 1, trig1, pos, 1)*SinOsc.ar(1/(2*trigPeriod)).abs*0.5; sig = sig.collect({ |item, i| chain = FFT(LocalBuf(fftSize), item, hop: 1.0, wintype: 0); chain = PV_Diffuser(chain, 1-trig1); chain = PV_BrickWall(chain, hiPass); chain = PV_BrickWall(chain, lowPass-1); item = IFFT(chain, wintype: -1); }).flatten; //delay the signal so that all fftSizes line up (the will already be delayed by the fftSize sig = DelayC.ar(sig, (3*fftMax/2)-(3*fftSize/2)+BlockSize.ir/SampleRate.ir, fftMax-fftSize+BlockSize.ir/SampleRate.ir); sig[1] = DelayC.ar(sig[1], trigPeriod/2, trigPeriod/2); sum = RunningSum.ar((sig[0]*sig[1]), fftSize/2)/RunningSum.ar((sig[0]*sig[0]), fftSize/2); rVal = Latch.ar(sum, DelayC.ar(trig1+trig2, (3*fftMax/2)-(3*fftSize/2)+BlockSize.ir/SampleRate.ir, fftMax-fftSize+BlockSize.ir/SampleRate.ir)).clip(-1,1); rVal = DelayC.ar(rVal, trigPeriod/2, trigPeriod/2); localIn = LocalIn.ar(1).clip(-1,1); localIn = DelayC.ar(localIn, trigPeriod/2-(BlockSize.ir/SampleRate.ir), trigPeriod/2-(BlockSize.ir/SampleRate.ir)); rVal1 = (Latch.ar(rVal, trig1)>=0).linlin(0,1,-1,1)* Latch.ar(XFade2.ar(K2A.ar(1), localIn, EnvGen.kr(Env([-1,-1, 1], [trigPeriod, 0]), 1)), trig1); rVal2 = (Latch.ar(rVal, trig2)>=0).linlin(0,1,-1,1)* Latch.ar(XFade2.ar(K2A.ar(1), DelayC.ar(rVal1.clip(-1,1), trigPeriod/2, trigPeriod/2), EnvGen.kr(Env([-1,-1, 1], [trigPeriod, 0]), 1)), trig2); LocalOut.ar(rVal2); /* window0 = NessWindow.ar(trig1, rVal.abs, fftSize)*rVal1; window1 = NessWindow.ar(trig2, rVal.abs, fftSize)*rVal2;*/ fs0 = (1-(Slew.ar( 1-Trig1.ar(trig1, fftSize/2/SampleRate.ir), SampleRate.ir/(fftSize/2), SampleRate.ir/(fftSize/2)))); fs0 = (fs0*pi/2).tan**2; //fs0 = fs0*((1/(1+(2*fs0*(rVal.abs))+(fs0**2))).sqrt); fs1 = (1-(Slew.ar( 1-Trig1.ar(trig2, fftSize/2/SampleRate.ir), SampleRate.ir/(fftSize/2), SampleRate.ir/(fftSize/2)))); fs1 = (fs1*pi/2).tan**2; //fs1 = fs1*((1/(1+(2*fs1*(rVal.abs))+(fs1**2))).sqrt); //window0 = fs0*rVal1; //window1 = fs1*rVal2; window0 = fs0*((1/(1+(2*fs0*(rVal.abs))+(fs0**2))).sqrt) * rVal1; window1 = fs1*((1/(1+(2*fs1*(rVal.abs))+(fs1**2))).sqrt) * rVal2; sig = DelayC.ar(sig, fftMax/SampleRate.ir, fftMax/SampleRate.ir); outSig = [sig[0]*window0, sig[1]*window1]; bigEnv = EnvGen.kr(Env.asr(0,1,0), gate, doneAction:2); hiPass = hiPass*SampleRate.ir/2; lowPass = lowPass*SampleRate.ir/2; outSig = HPF.ar(HPF.ar(outSig, (hiPass).clip(20, SampleRate.ir/2)), (hiPass).clip(20, SampleRate.ir/2)); outSig = LPF.ar(LPF.ar(outSig, (lowPass).clip(20, SampleRate.ir/2)), (lowPass).clip(20, SampleRate.ir/2)); Out.ar(out, Mix.new(outSig)*bigEnv*amp); //Out.ar(out, [sig[0], sig[1], rVal1, window0, window1]) }).add; ) Synth(\pb_monoStretch2_Overlap2, [\bufnum, b, \stretch, 2])
The way this is designed, you need to set a value for lowpass and highpass. Each of these Synth instances are a slice of the spectrum as far as I understand. And by default it's fraom 0 to 0 hz in the above.
It will work in real-time. It probably isn’t making sound because the hiPass and lowpass are both 0. If you set lowpass to 1 it works. See the calculations in TimeStretch2.sc file to get the values for each band of the NessStretch algorithm.
I fear there is a bug in this code somewhere having to do with the windowing…hopefully not.
Sam
From: mads kjeldgaard @.> Date: Monday, January 31, 2022 at 10:22 AM To: spluta/TimeStretch @.> Cc: Subscribed @.***> Subject: Re: [spluta/TimeStretch] Real time usage (#15)
Hi!
Is the TimeStrech2 supposed to work in this way? or is it only allowed to worked on SC's NRT mode ? (NessWindow.ar substituted for debbuging)
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav"); // remember to free the buffer later.
//NessStretch (improved paulstretch version)
(
SynthDef(\pb_monoStretch2_Overlap2, { |out = 0, bufnum, stretch = 100, startPos = 0, fftSize = 8192, fftMax = 65536, hiPass = 0, lowPass=0, amp = 1, gate = 1|
var trigPeriod, sig, chain, trig, trig1, trig2, pos, jump, trigEnv, fftDelay, bigEnv, window0, window1, rVal, correlation, sum, localIn, rVal1, rVal2, outSig, analSig, fs0, fs1;
trigPeriod = (fftSize/SampleRate.ir);
trig = Impulse.ar(2/trigPeriod);
trig1 = PulseDivider.ar(trig, 2, 1);
trig2 = PulseDivider.ar(trig, 2, 0);
startPos = (startPos%1);
pos = Line.ar(startPos*BufFrames.kr(bufnum), BufFrames.kr(bufnum), BufDur.kr(bufnum)stretch(1-startPos));
jump = fftSize/stretch/2;
pos = [pos, pos + jump];
sig = PlayBuf.ar(1, bufnum, 1, trig1, pos, 1)SinOsc.ar(1/(2trigPeriod)).abs*0.5;
sig = sig.collect({ |item, i|
chain = FFT(LocalBuf(fftSize), item, hop: 1.0, wintype: 0);
chain = PV_Diffuser(chain, 1-trig1);
chain = PV_BrickWall(chain, hiPass);
chain = PV_BrickWall(chain, lowPass-1);
item = IFFT(chain, wintype: -1);
}).flatten;
//delay the signal so that all fftSizes line up (the will already be delayed by the fftSize
sig = DelayC.ar(sig, (3fftMax/2)-(3fftSize/2)+BlockSize.ir/SampleRate.ir, fftMax-fftSize+BlockSize.ir/SampleRate.ir);
sig[1] = DelayC.ar(sig[1], trigPeriod/2, trigPeriod/2);
sum = RunningSum.ar((sig[0]*sig[1]), fftSize/2)/RunningSum.ar((sig[0]*sig[0]), fftSize/2);
rVal = Latch.ar(sum, DelayC.ar(trig1+trig2, (3fftMax/2)-(3fftSize/2)+BlockSize.ir/SampleRate.ir, fftMax-fftSize+BlockSize.ir/SampleRate.ir)).clip(-1,1);
rVal = DelayC.ar(rVal, trigPeriod/2, trigPeriod/2);
localIn = LocalIn.ar(1).clip(-1,1);
localIn = DelayC.ar(localIn, trigPeriod/2-(BlockSize.ir/SampleRate.ir), trigPeriod/2-(BlockSize.ir/SampleRate.ir));
rVal1 = (Latch.ar(rVal, trig1)>=0).linlin(0,1,-1,1)*
Latch.ar(XFade2.ar(K2A.ar(1), localIn, EnvGen.kr(Env([-1,-1, 1], [trigPeriod, 0]), 1)), trig1);
rVal2 = (Latch.ar(rVal, trig2)>=0).linlin(0,1,-1,1)*
Latch.ar(XFade2.ar(K2A.ar(1), DelayC.ar(rVal1.clip(-1,1), trigPeriod/2, trigPeriod/2), EnvGen.kr(Env([-1,-1, 1], [trigPeriod, 0]), 1)), trig2);
LocalOut.ar(rVal2);
/* window0 = NessWindow.ar(trig1, rVal.abs, fftSize)*rVal1;
window1 = NessWindow.ar(trig2, rVal.abs, fftSize)rVal2;/
fs0 = (1-(Slew.ar(
1-Trig1.ar(trig1, fftSize/2/SampleRate.ir),
SampleRate.ir/(fftSize/2),
SampleRate.ir/(fftSize/2))));
fs0 = (fs0*pi/2).tan**2;
//fs0 = fs0*((1/(1+(2fs0(rVal.abs))+(fs0**2))).sqrt);
fs1 = (1-(Slew.ar(
1-Trig1.ar(trig2, fftSize/2/SampleRate.ir),
SampleRate.ir/(fftSize/2),
SampleRate.ir/(fftSize/2))));
fs1 = (fs1*pi/2).tan**2;
//fs1 = fs1*((1/(1+(2fs1(rVal.abs))+(fs1**2))).sqrt);
//window0 = fs0*rVal1;
//window1 = fs1*rVal2;
window0 = fs0*((1/(1+(2fs0(rVal.abs))+(fs0**2))).sqrt) * rVal1;
window1 = fs1*((1/(1+(2fs1(rVal.abs))+(fs1**2))).sqrt) * rVal2;
sig = DelayC.ar(sig, fftMax/SampleRate.ir, fftMax/SampleRate.ir);
outSig = [sig[0]*window0, sig[1]*window1];
bigEnv = EnvGen.kr(Env.asr(0,1,0), gate, doneAction:2);
hiPass = hiPass*SampleRate.ir/2;
lowPass = lowPass*SampleRate.ir/2;
outSig = HPF.ar(HPF.ar(outSig, (hiPass).clip(20, SampleRate.ir/2)), (hiPass).clip(20, SampleRate.ir/2));
outSig = LPF.ar(LPF.ar(outSig, (lowPass).clip(20, SampleRate.ir/2)), (lowPass).clip(20, SampleRate.ir/2));
Out.ar(out, Mix.new(outSig)bigEnvamp);
//Out.ar(out, [sig[0], sig[1], rVal1, window0, window1])
}).add;
)
Synth(\pb_monoStretch2_Overlap2, [\bufnum, b, \stretch, 2])
The way this is designed, you need to set a value for lowpass and highpass. Each of these Synth instances are a slice of the spectrum as far as I understand. And by default it's fraom 0 to 0 hz in the above.
— Reply to this email directly, view it on GitHubhttps://github.com/spluta/TimeStretch/issues/15#issuecomment-1025882894, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAWN2RTPVXEHGP5GBT4OIR3UY2SKPANCNFSM5D2AFSDA. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you are subscribed to this thread.Message ID: @.***>
There's a pull request here that makes it easier to use in realtime (at least for me). It includes an example:
https://github.com/spluta/TimeStretch/pull/17