// title: experiments in detecting fast onsets with Amplitude UGens // author: julian.rohrhuber // description: // A series of consecutive experiments (all results visualised as plots) that try to detect onsets in a noisy signal. // code: // single Amplitude UGen // attackTime:0.01, releaseTime:0.01 // too soft to follow ( { var sig, amp, gate, trig; sig = LFSaw.ar(-200) * SinOsc.kr(20).range(0, 1); amp = Amplitude.ar(sig, attackTime:0.01, releaseTime:0.01); gate = amp > 0.2; trig = Trig1.ar(HPZ1.ar(gate), 0.001); // create a trigger signal [sig, amp, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) ) // attackTime:0, releaseTime:0.0002 // follows well ( { var sig, amp, gate, trig; sig = LFSaw.ar(-200) * SinOsc.kr(20).range(0, 1); amp = Amplitude.ar(sig, attackTime:0, releaseTime:0.0002); gate = amp > 0.1; trig = Trig1.ar(HPZ1.ar(gate), 0.001); [sig, amp, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) ) // attackTime:0, releaseTime:0.0002 // follows well, but: for a bit of noise causes false positives ... ( { var sig, amp, gate, trig; sig = LFSaw.ar(-200) * SinOsc.kr(20).range(0, 1) + LFNoise2.ar(4000, 0.2); amp = Amplitude.ar(sig, attackTime:0, releaseTime:0.0002); gate = amp > 0.2; trig = Trig1.ar(HPZ1.ar(gate), 0.001); [sig, amp, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) ) // ... comparison of multiple time scales may help // attackTime:0.001, releaseTime:0.0002 // attackTime:0.01, releaseTime:0.01 ( { var sig, amp1, amp2, gate, trig; sig = LFSaw.ar(-200) * SinOsc.kr(20).range(0, 1) + LFNoise2.ar(4000, 0.2); amp1 = Amplitude.ar(sig, attackTime:0.0002, releaseTime:0.0002); amp2 = Amplitude.ar(sig, attackTime:0.01, releaseTime:0.01); gate = (amp2 - amp1) > 0.2; trig = Trig1.ar(HPZ1.ar(gate), 0.001); [sig, amp1, amp2, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) ) // with slowly increasing noise // attackTime:0.001, releaseTime:0.0002 // attackTime:0.01, releaseTime:0.01 ( { var sig, amp1, amp2, gate, trig; sig = LFSaw.ar(-200) * SinOsc.kr(20).range(0, 1) + LFNoise2.ar(4000, Line.kr(0.1, 0.6, 0.1)); amp1 = Amplitude.ar(sig, attackTime:0.0002, releaseTime:0.0002); amp2 = Amplitude.ar(sig, attackTime:0.01, releaseTime:0.01); gate = (amp2 - amp1) > 0.2; trig = Trig1.ar(HPZ1.ar(gate), 0.001); [sig, amp1, amp2, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) ) // for a lagged and little bit noisy signal // attackTime:0.001, releaseTime:0.0002 // attackTime:0.01, releaseTime:0.01 // loses the first peaks ( { var sig, amp1, amp2, gate, trig; sig = LFSaw.ar(-200).range(0, 1).lag(0.01) * SinOsc.kr(20).range(0, 1) + LFNoise2.ar(4000, 0.02); amp1 = Amplitude.ar(sig, attackTime:0.0002, releaseTime:0.0002); amp2 = Amplitude.ar(sig, attackTime:0.01, releaseTime:0.01); gate = (amp2 - amp1) > 0.1; trig = Trig1.ar(HPZ1.ar(gate), 0.001); [sig, amp1, amp2, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) ) // with slowly increasing noise // attackTime:0.001, releaseTime:0.0002 // attackTime:0.01, releaseTime:0.01 ( { var sig, amp1, amp2, gate, trig; sig = LFSaw.ar(-200).range(0, 1).lag(0.01) * SinOsc.kr(20).range(0, 1) + LFNoise2.ar(4000, Line.kr(0.01, 0.2, 0.1)); amp1 = Amplitude.ar(sig, attackTime:0.0002, releaseTime:0.0002); amp2 = Amplitude.ar(sig, attackTime:0.01, releaseTime:0.01); gate = (amp2 - amp1) > 0.1; trig = Trig1.ar(HPZ1.ar(gate), 0.001); [sig, amp1, amp2, amp2 - amp1, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) ) // with slowly increasing noise // attackTime:0.001, releaseTime:0.0002 // attackTime:0.01, releaseTime:0.01 ( { var sig, amp1, amp2, floor, floorThresh, gate, trig; sig = LFSaw.ar(-200).range(0, 1).lag(0.01) * SinOsc.kr(20).range(0, 1) + LFNoise2.ar(4000, Line.kr(0.01, 0.2, 0.1)); amp1 = Amplitude.ar(sig, attackTime:0.0002, releaseTime:0.0002); amp2 = Amplitude.ar(sig, attackTime:0.001, releaseTime:0.01); floor = Amplitude.ar(sig, attackTime:0.01, releaseTime:0.03); floorThresh = amp2 > 0.3; gate = (amp1 - amp2) > 0.01 * floorThresh; trig = Trig1.ar(HPZ1.ar(gate), 0.001); [sig, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) ) // different randomly chosen time scales ( { var sig, amp1, amp2, floor, floorThresh, gate, trig; var f0 = rrand(40, 540); var tmul = 200/f0; var noiseLevel = Line.kr(0.01, 0.2, 0.1); "********* frequency: % **********".format(f0).postln; sig = LFSaw.ar(f0.neg).range(0, 1).lag(0.5/f0) * SinOsc.kr(20).range(0, 1); sig = sig + LFNoise2.ar(f0 * 20, noiseLevel); amp1 = Amplitude.ar(sig, attackTime:0.0002 * tmul, releaseTime:0.0002 * tmul); amp2 = Amplitude.ar(sig, attackTime:0.001 * tmul, releaseTime:0.01 * tmul); floor = Amplitude.ar(sig, attackTime:0.01 * tmul, releaseTime:0.03 * tmul); floorThresh = amp2 > 0.3; gate = (amp1 - amp2) > 0.01 * floorThresh; trig = Trig1.ar(HPZ1.ar(gate), 0.001); [sig, amp1, amp2, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) ) // sweep ( { var sig, amp1, amp2, floor, floorThresh, gate, trig; var f0 = XLine.kr(40, 1540); var noiseLevel = 0.1; var tmul = 200/f0; sig = LFSaw.ar(f0.neg).range(0, 1).lag(0.5/f0) * SinOsc.kr(20).range(0, 1); sig = sig + LFNoise2.ar(f0 * 15, noiseLevel); amp1 = Amplitude.ar(sig, attackTime:0.0002 * tmul, releaseTime:0.0002 * tmul); amp2 = Amplitude.ar(sig, attackTime:0.001 * tmul, releaseTime:0.01 * tmul); floor = Amplitude.ar(sig, attackTime:0.01 * tmul, releaseTime:0.03 * tmul); floorThresh = amp2 > 0.3; gate = (amp1 - amp2) > 0.01 * floorThresh; trig = Trig1.ar(HPZ1.ar(gate), 0.001); [sig, amp1, amp2, trig] }.plot(0.5, bounds:Rect(0, 0, 1200, 800), maxval:1.1) ) // postscript: // for a lagged and little bit noisy signal // trying out the Onsets UGen: not good at all for what we are trying, however other settings may help. ( { var sig, fft, gate, trig; sig = LFSaw.ar(-200).range(0, 1).lag(0.01) * SinOsc.kr(20).range(0, 1) + LFNoise2.ar(4000, 0.02); gate = Onsets.kr(FFT(LocalBuf(1024), sig),threshold:0.2,relaxtime:0.01,floor:0.01, mingap:0.001); trig = Trig1.kr(HPZ1.kr(gate), 0.001); [sig, trig] }.plot(0.1, bounds:Rect(0, 0, 800, 800), maxval:1.1) )