diff --git a/release-packaging/Classes/FluidAmpSlice.sc b/release-packaging/Classes/FluidAmpSlice.sc index 998545a..d39e1af 100644 --- a/release-packaging/Classes/FluidAmpSlice.sc +++ b/release-packaging/Classes/FluidAmpSlice.sc @@ -1,7 +1,7 @@ FluidAmpSlice : UGen { - *ar { arg in = 0, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, highPassFreq = 85, minSliceLength = 2; + *ar { arg in = 0, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85; - ^this.multiNew('audio', in.asAudioRateInput(this), fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, highPassFreq, minSliceLength) + ^this.multiNew('audio', in.asAudioRateInput(this), fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq) } checkInputs { ^this.checkValidInputs; diff --git a/release-packaging/Classes/FluidBufAmpSlice.sc b/release-packaging/Classes/FluidBufAmpSlice.sc index aa6f287..d2ceae4 100644 --- a/release-packaging/Classes/FluidBufAmpSlice.sc +++ b/release-packaging/Classes/FluidBufAmpSlice.sc @@ -1,6 +1,6 @@ FluidBufAmpSlice : UGen { - *new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, highPassFreq = 85, minSliceLength = 2, doneAction = 0, blocking| + *new1 { |rate, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, doneAction = 0, blocking| source = source.asUGenInput; indices = indices.asUGenInput; @@ -8,29 +8,29 @@ FluidBufAmpSlice : UGen { source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw}; indices.isNil.if {"FluidBufAmpSlice: Invalid features buffer".throw}; - ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, highPassFreq, minSliceLength, doneAction, blocking); + ^super.new1(rate, source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq, doneAction, blocking); } - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, highPassFreq = 85, minSliceLength = 2, doneAction = 0| + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, doneAction = 0| - ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, highPassFreq, minSliceLength, doneAction,blocking:0); + ^this.multiNew(\control, source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq, doneAction,blocking:0); } - *process { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, highPassFreq = 85, minSliceLength = 2, action | + *process { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, action | ^FluidNRTProcess.new( server, this, action, [indices] ).process( - source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, highPassFreq, minSliceLength + source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq ); } - *processBlocking { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, highPassFreq = 85, minSliceLength = 2, action| + *processBlocking { |server,source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, fastRampUp = 1, fastRampDown = 1, slowRampUp = 100, slowRampDown = 100, onThreshold = -144, offThreshold = -144, floor = -144, minSliceLength = 2, highPassFreq = 85, action| ^FluidNRTProcess.new( server, this, action, [indices], blocking: 1 ).process( - source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, highPassFreq, minSliceLength + source, startFrame, numFrames, startChan, numChans, indices, fastRampUp, fastRampDown, slowRampUp, slowRampDown, onThreshold, offThreshold, floor, minSliceLength, highPassFreq ); } } diff --git a/release-packaging/HelpSource/Classes/FluidAmpGate.schelp b/release-packaging/HelpSource/Classes/FluidAmpGate.schelp index d83c8f8..8635a2a 100644 --- a/release-packaging/HelpSource/Classes/FluidAmpGate.schelp +++ b/release-packaging/HelpSource/Classes/FluidAmpGate.schelp @@ -1,5 +1,5 @@ TITLE:: FluidAmpGate -SUMMARY:: Amplitude-based Slicer +SUMMARY:: Amplitude-based Gating Slicer CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition @@ -126,10 +126,10 @@ code:: //drum slicing, many ways //load a buffer b = Buffer.read(s,File.realpath(FluidAmpGate.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); -//have fun with a gate (explore lookahead and lookback, but correct for latency) +//have fun with a gate (explore lookahead and lookback, but correct for latency, which will be the greatest of the lookahead and lookback) ( {var env, source = PlayBuf.ar(1,b); - env = FluidAmpGate.ar(source, rampUp:1103, rampDown:2205, onThreshold:-27, offThreshold: -31, minSilenceLength:1100, lookBack:441, highPassFreq:40); + env = FluidAmpGate.ar(source, rampUp:441, rampDown:2205, onThreshold:-27, offThreshold: -31, minSilenceLength:1100, lookBack:441, highPassFreq:20); [DelayN.ar(source,delaytime:441/44100), env] }.plot(2, separately:true); ) diff --git a/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp index f1098d0..82a742b 100644 --- a/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidAmpSlice.schelp @@ -1,5 +1,5 @@ TITLE:: FluidAmpSlice -SUMMARY:: Amplitude-based Slicer +SUMMARY:: Amplitude-based Detrending Slicer CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition @@ -39,12 +39,12 @@ ARGUMENT:: offThreshold ARGUMENT:: floor The level in dB the slowRamp needs to be above to consider a detected difference valid, allowing to ignore the slices in the noise floor. -ARGUMENT:: highPassFreq - The frequency of the fourth-order Linkwitz–Riley high-pass filter (https://en.wikipedia.org/wiki/Linkwitz%E2%80%93Riley_filter). This is done first on the signal to minimise low frequency intermodulation with very fast ramp lengths. - ARGUMENT:: minSliceLength The length in samples that the Slice will stay ON. Changes of states during that period will be ignored. +ARGUMENT:: highPassFreq + The frequency of the fourth-order Linkwitz–Riley high-pass filter (https://en.wikipedia.org/wiki/Linkwitz%E2%80%93Riley_filter). This is done first on the signal to minimise low frequency intermodulation with very fast ramp lengths. + RETURNS:: An audio stream with square envelopes around the slices. The latency between the input and the output is dependant on the relation between the two envelope followers. @@ -52,23 +52,23 @@ EXAMPLES:: code:: // detrending explained -// the source is a sinewave that does not go to silence and has sharp-ish amplitude bumps as onsets we try to track +// Our source here is a sinewave that does not go to silence and has sharp-ish amplitude bumps as onsets we try to track ( -{var env, source = SinOsc.ar(320,0,LFSaw.ar(20,0, -0.4, 0.6)); +{var env, source = SinOsc.ar(320,0,LFSaw.ar(20, 0, -0.4, 0.6)); env = FluidAmpSlice.ar(source,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 10,floor: -60); [source, env] }.plot(0.08); ) //beware of double trigger at the begining of the 2nd cycle above). A solution: Schmidth triggers ( -{var env, source = SinOsc.ar(320,0,LFSaw.ar(20,0, -0.4, 0.6)); +{var env, source = SinOsc.ar(320,0,LFSaw.ar(20, 0, -0.4, 0.6)); env = FluidAmpSlice.ar(source,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 7,floor: -60); [source, env] }.plot(0.08); ) // another solution: minslicelength ( -{var env, source = SinOsc.ar(320,0,LFSaw.ar(20,0, -0.4, 0.6)); +{var env, source = SinOsc.ar(320,0,LFSaw.ar(20, 0, -0.4, 0.6)); env = FluidAmpSlice.ar(source,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 7,floor: -60, minSliceLength: 220); [source, env] }.plot(0.08); diff --git a/release-packaging/HelpSource/Classes/FluidBufAmpGate.schelp b/release-packaging/HelpSource/Classes/FluidBufAmpGate.schelp index e91b817..82f5d4c 100644 --- a/release-packaging/HelpSource/Classes/FluidBufAmpGate.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufAmpGate.schelp @@ -1,5 +1,5 @@ TITLE:: FluidBufAmpGate -SUMMARY:: Amplitude-based Slicer for Buffers +SUMMARY:: Amplitude-based Gating Slicer for Buffers CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading @@ -145,7 +145,7 @@ c = Buffer.new(s); ) // slice the samples -FluidBufAmpGate.process(s, b, indices:c, rampUp:1103, rampDown:2205, onThreshold:-27, offThreshold: -31, minSilenceLength:1100, lookBack:441, highPassFreq:40) +FluidBufAmpGate.process(s, b, indices:c, rampUp:110, rampDown:2205, onThreshold:-27, offThreshold: -31, minSilenceLength:1100, lookBack:441, highPassFreq:40) c.query c.getn(0,c.numFrames*2,{|item|item.postln;}) //reformatting to read the onsets and offsets as pairs @@ -184,13 +184,13 @@ c = Buffer.new(s); // with basic params Routine{ t = Main.elapsedTime; - FluidBufAmpGate.process(s, b, indices: c, rampUp:1, rampDown:20); + FluidBufAmpGate.process(s, b, indices: c, rampUp:1, rampDown:10, onThreshold: -30); (Main.elapsedTime - t).postln; }.play ) // list the indicies of detected attacks - the two input channels have been summed. The two channels of the output, respectively onset and offset indices, are interleaved as this is the SuperCollider buffer data formatting -c.getn(0,c.numFrames*2,{|item|item.postln;}) +c.getn(0,c.numFrames*2,{|item|(item*2).postln;}) // a more readable version: deinterleave onsetand offset -c.getn(0,c.numFrames*2,{|items|items.reshape(c.numFrames,2).do({|x| x.postln});}) +c.getn(0,c.numFrames*2,{|items|items.reshape(c.numFrames,2).do({|x| (x*2).postln});}) :: diff --git a/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp index 7221343..9eed6e9 100644 --- a/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufAmpSlice.schelp @@ -1,5 +1,5 @@ TITLE:: FluidBufAmpSlice -SUMMARY:: Amplitude-based Slicer for Buffers +SUMMARY:: Amplitude-based Detrending Slicer for Buffers CATEGORIES:: Libraries>FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading @@ -61,12 +61,12 @@ ARGUMENT:: offThreshold ARGUMENT:: floor The level in dB the slowRamp needs to be above to consider a detected difference valid, allowing to ignore the slices in the noise floor. -ARGUMENT:: highPassFreq - The frequency of the fourth-order Linkwitz–Riley high-pass filter (https://en.wikipedia.org/wiki/Linkwitz%E2%80%93Riley_filter). This is done first on the signal to minimise low frequency intermodulation with very fast ramp lengths. - ARGUMENT:: minSliceLength The length in samples that the Slice will stay ON. Changes of states during that period will be ignored. +ARGUMENT:: highPassFreq + The frequency of the fourth-order Linkwitz–Riley high-pass filter (https://en.wikipedia.org/wiki/Linkwitz%E2%80%93Riley_filter). This is done first on the signal to minimise low frequency intermodulation with very fast ramp lengths. + ARGUMENT:: action A Function to be evaluated once the offline process has finished and indices instance variables have been updated on the client side. The metric will be passed indices as an argument. @@ -79,7 +79,7 @@ code:: // detrending explained // define a test signal and a destination buffer ( -b = Buffer.sendCollection(s, Array.fill(44100,{|i| sin(i*pi/ (44100/640)) * ((((35000-i)/30000)%0.8) + 0.2)})); +b = Buffer.sendCollection(s, Array.fill(44100,{|i| sin(i*pi/ (44100/640)) * ((((79000-i) % 22050).abs / 28000.0) + 0.2)})); c = Buffer.new(s); ) // the source is a sinewave that does not go to silence and has sharp-ish amplitude bumps as onsets we try to track @@ -153,5 +153,5 @@ Routine{ ) // list the indicies of detected attacks - the two input channels have been summed. -c.getn(0,c.numFrames,{|item|item.postln;}) +c.getn(0,c.numFrames,{|item|(item * 2).postln;}) :: diff --git a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp index 80993ad..ef6134c 100644 --- a/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufNoveltySlice.schelp @@ -125,15 +125,15 @@ FluidBufNoveltySlice.process(s,b, indices: c, kernelSize:31, threshold:0.1, filt //check the number of slices: it is the number of frames in the transBuf minus the boundary index. c.query; -//play slice number 2 +//play slice number 3 ( { - BufRd.ar(1, b, - Line.ar( - BufRd.kr(1, c, DC.kr(2), 0, 1), - BufRd.kr(1, c, DC.kr(3), 0, 1), - (BufRd.kr(1, c, DC.kr(3)) - BufRd.kr(1, c, DC.kr(2), 0, 1) + 1) / s.sampleRate), - 0,1); + BufRd.ar(1, b, + Line.ar( + BufRd.kr(1, c, DC.kr(3), 0, 1), + BufRd.kr(1, c, DC.kr(4), 0, 1), + (BufRd.kr(1, c, DC.kr(4)) - BufRd.kr(1, c, DC.kr(3), 0, 1) + 1) / s.sampleRate), + 0,1); }.play; ) diff --git a/release-packaging/HelpSource/Guides/FluCoMa.schelp b/release-packaging/HelpSource/Guides/FluCoMa.schelp index fe14906..c6ec417 100644 --- a/release-packaging/HelpSource/Guides/FluCoMa.schelp +++ b/release-packaging/HelpSource/Guides/FluCoMa.schelp @@ -4,8 +4,8 @@ categories:: Libraries>FluidDecomposition related:: Classes/FluidBufNMF description:: -This is my description of the FluCoMa project. footnote:: -This was made possible thanks to the FluCoMa project (http://www.flucoma.org/) funded by the European Research Council (https://erc.europa.eu/) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899).:: +The Fluid Corpus Manipulation project (FluCoMA) instigates new musical ways of exploiting ever-growing banks of sound and gestures within the digital composition process, by bringing breakthroughs of signal decomposition DSP and machine learning to the toolset of techno-fluent computer composers, creative coders and digital artists. -subsection:: stuff -This is my subsection +This was made possible thanks to a grant by the European Research Council ( https://erc.europa.eu/ ) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No 725899). + +For more information, including a forum and learning material, please visit the FluCoMa project website at http://www.flucoma.org/ \ No newline at end of file diff --git a/release-packaging/HelpSource/Guides/FluidDecomposition.schelp b/release-packaging/HelpSource/Guides/FluidDecomposition.schelp index fa4d288..bfe55a0 100644 --- a/release-packaging/HelpSource/Guides/FluidDecomposition.schelp +++ b/release-packaging/HelpSource/Guides/FluidDecomposition.schelp @@ -10,6 +10,9 @@ subsection:: Slices LINK:: Classes/FluidAmpSlice:: & LINK:: Classes/FluidBufAmpSlice:: +LINK:: Classes/FluidAmpGate:: & +LINK:: Classes/FluidBufAmpGate:: + Slice by amplitude envelope LINK:: Classes/FluidOnsetSlice:: & diff --git a/release-packaging/ignore/Examples/nmf/JiT-NMF-classifier.scd b/release-packaging/ignore/Examples/nmf/JiT-NMF-classifier.scd index e1c00c0..b76c08d 100644 --- a/release-packaging/ignore/Examples/nmf/JiT-NMF-classifier.scd +++ b/release-packaging/ignore/Examples/nmf/JiT-NMF-classifier.scd @@ -52,7 +52,7 @@ Routine { audioin = In.ar(input,1); BufWr.ar(audioin,bufnum,head,0); BufWr.ar(audioin,bufnum,head+duration,0); - trig = FluidAmpSlice.ar(audioin,2205,2205,-47,-47,4410,4410,relRampUp: 10, relRampDown:1666, relThreshOn:12, relThreshOff: 9, highPassFreq: 85); + trig = FluidAmpSlice.ar(audioin, 10, 1666, 2205, 2205, 12, 9, -47,4410, 85); // cue the calculations via the language SendReply.ar(trig, '/attack',head); @@ -148,9 +148,9 @@ Routine { if (activation_vals[1] >= thresholds[1], {Synth(\fluidsn,[\out,1])}); if (activation_vals[2] >= thresholds[2], {Synth(\fluidhh,[\out,1])}); defer{ - activations_disps[0].string_("A: " ++ activation_vals[0].round(0.001)); - activations_disps[1].string_("B: " ++ activation_vals[1].round(0.001)); - activations_disps[2].string_("C: " ++ activation_vals[2].round(0.001)); + activations_disps[0].string_("A:" ++ activation_vals[0].round(0.01)); + activations_disps[1].string_("B:" ++ activation_vals[1].round(0.01)); + activations_disps[2].string_("C:" ++ activation_vals[2].round(0.01)); }; }); }; @@ -163,35 +163,35 @@ Routine { // GUI for control { - var win = Window("Control", Rect(100,100,590,100)).front; + var win = Window("Control", Rect(100,100,610,100)).front; Button(win, Rect(10,10,80, 80)).states_([["bd",Color.black,Color.white]]).mouseDownAction_({Synth(\fluidbd, [\out, input_bus], analysis_synth, \addBefore)}); Button(win, Rect(100,10,80, 80)).states_([["sn",Color.black,Color.white]]).mouseDownAction_({Synth(\fluidsn, [\out, input_bus], analysis_synth, \addBefore)}); Button(win, Rect(190,10,80, 80)).states_([["hh",Color.black,Color.white]]).mouseDownAction_({Synth(\fluidhh, [\out, input_bus], analysis_synth,\addBefore)}); - StaticText(win, Rect(280,7,75,25)).string_("Select").align_(\center); - PopUpMenu(win, Rect(280,32,75,25)).items_(["learn","classify"]).action_({|value| + StaticText(win, Rect(280,7,85,25)).string_("Select").align_(\center); + PopUpMenu(win, Rect(280,32,85,25)).items_(["learn","classify"]).action_({|value| classifying = value.value; if(classifying == 0, { train_base.fill(0,65,0.1) }); }); - PopUpMenu(win, Rect(280,65,75,25)).items_(["classA","classB","classC"]).action_({|value| + PopUpMenu(win, Rect(280,65,85,25)).items_(["classA","classB","classC"]).action_({|value| cur_training_class = value.value; train_base.fill(0,65,0.1); }); - Button(win, Rect(365,65,65,25)).states_([["transfer",Color.black,Color.white]]).mouseDownAction_({ + Button(win, Rect(375,65,85,25)).states_([["transfer",Color.black,Color.white]]).mouseDownAction_({ if(classifying == 0, { // if training FluidBufCompose.process(s, train_base, numChans:1, destination:~classify_bases, destStartChan:cur_training_class); }); }); - StaticText(win, Rect(440,7,75,25)).string_("Activations"); + StaticText(win, Rect(470,7,75,25)).string_("Acts"); activations_disps = Array.fill(3, {arg i; - StaticText(win, Rect(440,((i+1) * 20 )+ 7,75,25)); + StaticText(win, Rect(470,((i+1) * 20 )+ 7,80,25)); }); - StaticText(win, Rect(520,7,55,25)).string_("Thresh").align_(\center); + StaticText(win, Rect(540,7,55,25)).string_("Thresh").align_(\center); 3.do {arg i; - TextField(win, Rect(520,((i+1) * 20 )+ 7,55,25)).string_("0.5").action_({|x| thresholds[i] = x.value.asFloat;}); + TextField(win, Rect(540,((i+1) * 20 )+ 7,55,25)).string_("0.5").action_({|x| thresholds[i] = x.value.asFloat;}); }; win.onClose_({circle_buf.free;input_bus.free;osc_func.clear;analysis_synth.free;}); diff --git a/release-packaging/ignore/Examples/segmenting/size_of_slices.scd b/release-packaging/ignore/Examples/segmenting/size_of_slices.scd deleted file mode 100644 index 4135cba..0000000 --- a/release-packaging/ignore/Examples/segmenting/size_of_slices.scd +++ /dev/null @@ -1,81 +0,0 @@ -( -b = Buffer.read(s,File.realpath(FluidBufNoveltySlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); -c = Buffer.new(s); -) - -( -// with basic params -Routine{ - var startTime, target, tolerance, startThresh, prevThresh, curThresh, curVal, prevVal, iters, maxIters, dVal, dThresh; - startTime = Main.elapsedTime; - prevThresh = 0.1; //initial threshold (between 0.00001 and 0.99999 - target = 0.3 * s.sampleRate; //average of slices desired - tolerance = 0.01 * s.sampleRate; // the acceptable error in the number of slices yield - maxIters = 100; //max number of iterations acceptable - - //makes a first iteration and checks the average of slight lenght - FluidBufNoveltySlice.process(s,b, indices: c, threshold: prevThresh,action:{|x|x.getn(0,x.numFrames,{|y|var out; out = Array.new; y.doAdjacentPairs({|a,b|out = out ++ (b - a);});prevVal = out.mean;})}); - //makes a second iteration - s.sync; // OWEN: why is this needed??? - "1: % % %\n".postf(prevThresh, prevVal, c.numFrames); - if ( (prevVal > target), { - curThresh = (prevThresh * 0.5).max(0.000001); - }, { - curThresh = (prevThresh * 2).min(0.999999); - }); - FluidBufNoveltySlice.process(s,b, indices: c, threshold: curThresh,action:{|x|x.getn(0,x.numFrames,{|y|var out; out = Array.new; y.doAdjacentPairs({|a,b|out = out ++ (b - a);});curVal = out.mean;})}); - s.sync; - "2: % % %\n".postf(curThresh, curVal, c.numFrames); - //makes further iterations until the result is achieved, or the maximum of acceptable iterations is reached - iters = 2; - while ( { - (iters < maxIters) && ((curVal - target).abs > tolerance) - }, { - iters = iters + 1; - dVal = curVal - prevVal; - dThresh = curThresh - prevThresh; - - prevThresh = curThresh; - prevVal = curVal; - - if ( (dVal == 0), { - //if we have not change results between the last 2 passes, make the variation of threshold bigger - curThresh = (dThresh + curThresh).min(0.999999).max(0.000001); - },{ - //if we have - curThresh = (((dThresh / dVal) * (target - curVal)) + curThresh).min(0.999999).max(0.000001); - }); - FluidBufNoveltySlice.process(s,b, indices: c, threshold: curThresh,action:{|x|x.getn(0,x.numFrames,{|y|var out; out = Array.new; y.doAdjacentPairs({|a,b|out = out ++ (b - a);});curVal = out.mean;})}); - s.sync; - "%: % % %\n".postf(iters, curThresh, curVal, c.numFrames); - } - ); - //depending on the outcome, gives the right info back - - if ( iters >= maxIters, { - // failed - "Failed to find a suitable threshold in % seconds.\n".postf((Main.elapsedTime - startTime).round(0.01)); - }, { - // succeeded - "Found % as a suitable threshold for an average lenght of % samples per slices (% of target) in % seconds and % iterations.\n".postf(curThresh.round(0.001), curVal.asInt, (curVal/target).round(0.01), (Main.elapsedTime - startTime).round(0.01), iters); - } - ); -}.play -) - - - - -//sanity check -c.getn(0,c.numFrames,{|x|a=x}) - -a -d = Array.new; -a.doAdjacentPairs({|a,b|d = d ++ (b - a);}) -d.median -d.mean -{e=0;d.do({|x|e = e + (x - d.mean).squared});e = e / d.size; e = e.sqrt;}.value -f = d.sort -f.first -f.last -(f.blendAt((f.size-1) * 0.75) - f.blendAt((f.size-1) * 0.25))