Gerard Roma 6 years ago
commit 22429f6a1f

@ -1,7 +1,7 @@
FluidAmpSlice : UGen { 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 { checkInputs {
^this.checkValidInputs; ^this.checkValidInputs;

@ -1,6 +1,6 @@
FluidBufAmpSlice : UGen { 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; source = source.asUGenInput;
indices = indices.asUGenInput; indices = indices.asUGenInput;
@ -8,29 +8,29 @@ FluidBufAmpSlice : UGen {
source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw}; source.isNil.if {"FluidBufAmpSlice: Invalid source buffer".throw};
indices.isNil.if {"FluidBufAmpSlice: Invalid features 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( ^FluidNRTProcess.new(
server, this, action, [indices] server, this, action, [indices]
).process( ).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( ^FluidNRTProcess.new(
server, this, action, [indices], blocking: 1 server, this, action, [indices], blocking: 1
).process( ).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
); );
} }
} }

@ -1,5 +1,5 @@
TITLE:: FluidAmpGate TITLE:: FluidAmpGate
SUMMARY:: Amplitude-based Slicer SUMMARY:: Amplitude-based Gating Slicer
CATEGORIES:: Libraries>FluidDecomposition CATEGORIES:: Libraries>FluidDecomposition
RELATED:: Guides/FluCoMa, Guides/FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition
@ -126,10 +126,10 @@ code::
//drum slicing, many ways //drum slicing, many ways
//load a buffer //load a buffer
b = Buffer.read(s,File.realpath(FluidAmpGate.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); 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); {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] [DelayN.ar(source,delaytime:441/44100), env]
}.plot(2, separately:true); }.plot(2, separately:true);
) )

@ -1,5 +1,5 @@
TITLE:: FluidAmpSlice TITLE:: FluidAmpSlice
SUMMARY:: Amplitude-based Slicer SUMMARY:: Amplitude-based Detrending Slicer
CATEGORIES:: Libraries>FluidDecomposition CATEGORIES:: Libraries>FluidDecomposition
RELATED:: Guides/FluCoMa, Guides/FluidDecomposition RELATED:: Guides/FluCoMa, Guides/FluidDecomposition
@ -39,12 +39,12 @@ ARGUMENT:: offThreshold
ARGUMENT:: floor 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. 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 LinkwitzRiley 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 ARGUMENT:: minSliceLength
The length in samples that the Slice will stay ON. Changes of states during that period will be ignored. 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 LinkwitzRiley 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:: 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. 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:: code::
// detrending explained // 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); env = FluidAmpSlice.ar(source,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 10,floor: -60);
[source, env] [source, env]
}.plot(0.08); }.plot(0.08);
) )
//beware of double trigger at the begining of the 2nd cycle above). A solution: Schmidth triggers //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); env = FluidAmpSlice.ar(source,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 7,floor: -60);
[source, env] [source, env]
}.plot(0.08); }.plot(0.08);
) )
// another solution: minslicelength // 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); env = FluidAmpSlice.ar(source,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 7,floor: -60, minSliceLength: 220);
[source, env] [source, env]
}.plot(0.08); }.plot(0.08);

@ -1,5 +1,5 @@
TITLE:: FluidBufAmpGate TITLE:: FluidBufAmpGate
SUMMARY:: Amplitude-based Slicer for Buffers SUMMARY:: Amplitude-based Gating Slicer for Buffers
CATEGORIES:: Libraries>FluidDecomposition CATEGORIES:: Libraries>FluidDecomposition
RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading
@ -145,7 +145,7 @@ c = Buffer.new(s);
) )
// slice the samples // 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.query
c.getn(0,c.numFrames*2,{|item|item.postln;}) c.getn(0,c.numFrames*2,{|item|item.postln;})
//reformatting to read the onsets and offsets as pairs //reformatting to read the onsets and offsets as pairs
@ -184,13 +184,13 @@ c = Buffer.new(s);
// with basic params // with basic params
Routine{ Routine{
t = Main.elapsedTime; 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; (Main.elapsedTime - t).postln;
}.play }.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 // 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 // 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});})
:: ::

@ -1,5 +1,5 @@
TITLE:: FluidBufAmpSlice TITLE:: FluidBufAmpSlice
SUMMARY:: Amplitude-based Slicer for Buffers SUMMARY:: Amplitude-based Detrending Slicer for Buffers
CATEGORIES:: Libraries>FluidDecomposition CATEGORIES:: Libraries>FluidDecomposition
RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Guides/FluidBufMultiThreading
@ -61,12 +61,12 @@ ARGUMENT:: offThreshold
ARGUMENT:: floor 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. 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 LinkwitzRiley 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 ARGUMENT:: minSliceLength
The length in samples that the Slice will stay ON. Changes of states during that period will be ignored. 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 LinkwitzRiley 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 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. 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 // detrending explained
// define a test signal and a destination buffer // 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); 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 // 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. // 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;})
:: ::

@ -125,14 +125,14 @@ 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. //check the number of slices: it is the number of frames in the transBuf minus the boundary index.
c.query; c.query;
//play slice number 2 //play slice number 3
( (
{ {
BufRd.ar(1, b, BufRd.ar(1, b,
Line.ar( 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), 0, 1),
(BufRd.kr(1, c, DC.kr(3)) - BufRd.kr(1, c, DC.kr(2), 0, 1) + 1) / s.sampleRate), 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); 0,1);
}.play; }.play;
) )

@ -4,8 +4,8 @@ categories:: Libraries>FluidDecomposition
related:: Classes/FluidBufNMF related:: Classes/FluidBufNMF
description:: description::
This is my description of the FluCoMa project. footnote:: 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.
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 Unions Horizon 2020 research and innovation programme (grant agreement No 725899).::
subsection:: stuff This was made possible thanks to a grant by the European Research Council ( https://erc.europa.eu/ ) under the European Unions Horizon 2020 research and innovation programme (grant agreement No 725899).
This is my subsection
For more information, including a forum and learning material, please visit the FluCoMa project website at http://www.flucoma.org/

@ -10,6 +10,9 @@ subsection:: Slices
LINK:: Classes/FluidAmpSlice:: & LINK:: Classes/FluidAmpSlice:: &
LINK:: Classes/FluidBufAmpSlice:: LINK:: Classes/FluidBufAmpSlice::
LINK:: Classes/FluidAmpGate:: &
LINK:: Classes/FluidBufAmpGate::
Slice by amplitude envelope Slice by amplitude envelope
LINK:: Classes/FluidOnsetSlice:: & LINK:: Classes/FluidOnsetSlice:: &

@ -52,7 +52,7 @@ Routine {
audioin = In.ar(input,1); audioin = In.ar(input,1);
BufWr.ar(audioin,bufnum,head,0); BufWr.ar(audioin,bufnum,head,0);
BufWr.ar(audioin,bufnum,head+duration,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 // cue the calculations via the language
SendReply.ar(trig, '/attack',head); SendReply.ar(trig, '/attack',head);
@ -148,9 +148,9 @@ Routine {
if (activation_vals[1] >= thresholds[1], {Synth(\fluidsn,[\out,1])}); if (activation_vals[1] >= thresholds[1], {Synth(\fluidsn,[\out,1])});
if (activation_vals[2] >= thresholds[2], {Synth(\fluidhh,[\out,1])}); if (activation_vals[2] >= thresholds[2], {Synth(\fluidhh,[\out,1])});
defer{ defer{
activations_disps[0].string_("A: " ++ activation_vals[0].round(0.001)); activations_disps[0].string_("A:" ++ activation_vals[0].round(0.01));
activations_disps[1].string_("B: " ++ activation_vals[1].round(0.001)); activations_disps[1].string_("B:" ++ activation_vals[1].round(0.01));
activations_disps[2].string_("C: " ++ activation_vals[2].round(0.001)); activations_disps[2].string_("C:" ++ activation_vals[2].round(0.01));
}; };
}); });
}; };
@ -163,35 +163,35 @@ Routine {
// GUI for control // 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(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(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)}); 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); StaticText(win, Rect(280,7,85,25)).string_("Select").align_(\center);
PopUpMenu(win, Rect(280,32,75,25)).items_(["learn","classify"]).action_({|value| PopUpMenu(win, Rect(280,32,85,25)).items_(["learn","classify"]).action_({|value|
classifying = value.value; classifying = value.value;
if(classifying == 0, { if(classifying == 0, {
train_base.fill(0,65,0.1) 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; cur_training_class = value.value;
train_base.fill(0,65,0.1); 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(classifying == 0, {
// if training // if training
FluidBufCompose.process(s, train_base, numChans:1, destination:~classify_bases, destStartChan:cur_training_class); 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; 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; 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;}); win.onClose_({circle_buf.free;input_bus.free;osc_func.clear;analysis_synth.free;});

@ -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))
Loading…
Cancel
Save