From 3ef8209d2815321e4ab6d1ae851255c01a251d94 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 14 Apr 2021 10:44:05 +0100 Subject: [PATCH 1/2] explanation of FFT impact in (buf)audiotransport with fun sounds --- .../HelpSource/Classes/FluidAudioTransport.schelp | 9 +++++++++ .../HelpSource/Classes/FluidBufAudioTransport.schelp | 2 ++ 2 files changed, 11 insertions(+) diff --git a/release-packaging/HelpSource/Classes/FluidAudioTransport.schelp b/release-packaging/HelpSource/Classes/FluidAudioTransport.schelp index 8f629ea..d56c1c5 100644 --- a/release-packaging/HelpSource/Classes/FluidAudioTransport.schelp +++ b/release-packaging/HelpSource/Classes/FluidAudioTransport.schelp @@ -47,6 +47,15 @@ code:: //didactic - the mouse X axis interpolates between the two sinewaves {FluidAudioTransport.ar(SinOsc.ar(220,mul: 0.1),SinOsc.ar(440,mul: 0.02),MouseX.kr())}.play; +//notice how the interpolation quantizes to the FFT bins. Like most spectral processes, it benefits from oversampling the fft... at the cost of CPU power, obviously. +{FluidAudioTransport.ar(SinOsc.ar(220,mul: 0.1),SinOsc.ar(440,mul: 0.02),MouseX.kr(),fftSize: 8192)}.play; + +// when the signal is steady, larger hopSize can be accommodated to save back on the CPU +{FluidAudioTransport.ar(SinOsc.ar(220,mul: 0.1),SinOsc.ar(440,mul: 0.02),MouseX.kr(),windowSize: 8192)}.play; // here we get a default hop of half the window so 8 times less than above. + +//if you CPU can cope, try this setting, almost smooth, but attacks would smear (the Y axis mixes some in to hear the effect) +{var attacks = Impulse.ar(1,mul: MouseY.kr(-40,10).dbamp); FluidAudioTransport.ar(SinOsc.ar(220,mul: 0.1,add: attacks),SinOsc.ar(440,mul: 0.02,add: attacks),MouseX.kr(),windowSize: 16000)}.play; + //richer with complex spectra //load 2 files ( diff --git a/release-packaging/HelpSource/Classes/FluidBufAudioTransport.schelp b/release-packaging/HelpSource/Classes/FluidBufAudioTransport.schelp index a202579..a960987 100644 --- a/release-packaging/HelpSource/Classes/FluidBufAudioTransport.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufAudioTransport.schelp @@ -94,6 +94,8 @@ b.play c.play d.play +// note that the process is quantized by the spectral bins. For an example of the pros and cons of these settings on this given process, please see the real-time FluidAudioTransport helpfile. + // more interesting sources: two cardboard bowing gestures ( b = Buffer.read(s,File.realpath(FluidBufAudioTransport.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Green-Box641.wav"); From 04ee2dbbb7215e8856a3dc1e62a22fa11af65831 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 14 Apr 2021 10:44:56 +0100 Subject: [PATCH 2/2] bufstats: better example of usage of derivative. --- .../HelpSource/Classes/FluidBufStats.schelp | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidBufStats.schelp b/release-packaging/HelpSource/Classes/FluidBufStats.schelp index 0a6a0e3..39aae16 100644 --- a/release-packaging/HelpSource/Classes/FluidBufStats.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufStats.schelp @@ -129,43 +129,66 @@ STRONG::A musical example:: CODE:: // create some buffers ( -b = Buffer.read(s,File.realpath(FluidBufStats.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-ASWINE-ScratchySynth-M.wav"); +// a simple random sliding bell synth +b = { + var trig = Impulse.ar(1.5); + SinOsc.ar( + Lag.ar(TRand.ar(trig: trig), + TRand.ar(0.5, trig: trig)).exprange(333,666), + mul: Decay.ar( + trig * TRand.ar(0.1,10,trig), + TRand.ar(0.5,1.1,trig) + ) + ).atan * 0.1; +}.asBuffer(20); c = Buffer.new(s); d = Buffer.new(s); +i = Buffer.new(s); ) +//play the source +b.play; + //split in various chunks, collecting the indices in an array -FluidBufOnsetSlice.process(s,b, minSliceLength: 10, metric: 9, threshold: 0.4, filterSize: 7, indices: c, action:{c.loadToFloatArray(action: {|array| e = array.add(b.numFrames).addFirst(0);e.postln;})}); +FluidBufOnsetSlice.process(s,b, threshold: 0.01, indices: c, action:{c.loadToFloatArray(action: {|array| e = array.add(b.numFrames);e.size.postln;e.postln;})}); //describe the whole input too, here using pitch, and collecting the values in an array, dismissing the (interleaved) confidence. -FluidBufPitch.process(s,b,features:c, action:{c.loadToFloatArray(action: {|array| f = array.unlace(2)[0]; f.postln;})}); +FluidBufPitch.process(s,b,features:d, windowSize: 4096, hopSize: 512, padding:2, action:{d.loadToFloatArray(action: {|array| f = array.unlace(2)[0]; f.postln;})}); // iterate through each slice, taking the median of the first derivative of the pitch of each ( g= Array.new; Routine({ + var nb = e.size; e.doAdjacentPairs({ arg start,end; - FluidBufStats.processBlocking(s,c,(start/512).asInteger,((end-start)/512).max(2).asInteger,0,1,d,1, - action: {d.loadToFloatArray(action: { - arg array; - g = g.add(array[12]); - "% % %\n".postf((start/512).asInteger,((end-start)/512 ).max(2).asInteger, array[12]);}) - } - ).wait; -}); - "Done".postln; + FluidBufStats.processBlocking(s,d,(start/512).asInteger,((end-start)/512).asInteger + 3,0,1,i,1, action: { + i.loadToFloatArray( action: { + arg array; + g = g.add(array[12]); + "% % %\n".postf((start/512).asInteger,((end-start)/512).asInteger + 3, array[12]);//adding some of the overlap but not more to not capture too much of the next attack + nb = nb - 1; + if (nb == 1, {"Done".postln;});//check if we've done all the pairs + }) + }).wait; + }); }).play; ) -//obtain the order of indices that would sort the stats -h = g.order; +//play in loop the slice in order of pitch direction (the median of the slice's pitch variation) - mouse on the left should be descending, in the middle should be more stable, and it should be ascending on the right. -//play in loop the slice in order of pitch direction (the median of the slice's pitch variation) ( -var which = h[5]; -{BufRd.ar(1, b, Phasor.ar(0,1,e[which],e[which+1],e[which]))}.play; +Buffer.sendCollection(s,g.order,action: {|x| { + var which = BufRd.kr(1, x, MouseX.kr(0, BufFrames.kr(x) - 1), 0, 1); + BufRd.ar(1, b, + Phasor.ar(0,1, + BufRd.kr(1,c,which,0,1), + BufRd.kr(1,c,which + 1,0,1), + BufRd.kr(1,c,which,0,1))); + }.play; + };) ) + ::