final tweaks of alpha08 helpfiles and examples

nix
Pierre Alexandre Tremblay 7 years ago
parent b4ddab8cac
commit 51193f7444

@ -1,6 +1,6 @@
FluidAmpSlice : UGen {
*ar { arg in = 0, absRampUp = 10, absRampDown = 10, absThreshOn = -90, absThreshOff = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 85, maxSize = 88200, outputType = 0;
^this.multiNew('audio', in.asAudioRateInput(this), absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq, maxSize, outputType)
*ar { arg in = 0, absRampUp = 10, absRampDown = 10, absThreshOn = -90, absThreshOff = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 85, maxSize = 88200;
^this.multiNew('audio', in.asAudioRateInput(this), absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq, maxSize, 0)
}
checkInputs {
if(inputs.at(16).rate != 'scalar') {

@ -1,5 +1,5 @@
FluidBufAmpSlice{
*process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, absRampUp = 10, absRampDown = 10, absThreshOn = -90, absThreshOff = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 85, outputType = 0, action;
*process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, indices, absRampUp = 10, absRampDown = 10, absThreshOn = -90, absThreshOff = -90, minSliceLength = 1, minSilenceLength = 1, minLengthAbove = 1, minLengthBelow = 1, lookBack = 0, lookAhead = 0, relRampUp = 1, relRampDown = 1, relThreshOn = 144, relThreshOff = -144, highPassFreq = 85, action;
var maxSize = max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead));
@ -12,7 +12,7 @@ FluidBufAmpSlice{
server = server ? Server.default;
forkIfNeeded{
server.sendMsg(\cmd, \BufAmpSlice, source, startFrame, numFrames, startChan, numChans, indices, absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq, maxSize, outputType);
server.sendMsg(\cmd, \BufAmpSlice, source, startFrame, numFrames, startChan, numChans, indices, absRampUp, absRampDown, absThreshOn, absThreshOff, minSliceLength, minSilenceLength, minLengthAbove, minLengthBelow, lookBack, lookAhead, relRampUp, relRampDown, relThreshOn, relThreshOff, highPassFreq, maxSize, 0);
server.sync;
indices = server.cachedBufferAt(indices); indices.updateInfo; server.sync;
action.value(indices);

@ -66,135 +66,118 @@ ARGUMENT:: highPassFreq
ARGUMENT:: maxSize
How large can the buffer be for time-critical conditions, by allocating memory at instantiation time. This cannot be modulated.
ARGUMENT:: outputType
(describe argument here)
RETURNS::
An audio stream with square envelopes around the slices. The latency between the input and the output is STRONG::max(minLengthAbove + lookBack, max(minLengthBelow,lookAhead))::.
EXAMPLES::
code::
//basic tests: highPass sanity
(
{var env, source = SinOsc.ar(320,0,0.5);
env = FluidAmpSlice.ar(source,highPassFreq:250, outputType:1);
[source, env]
}.plot(0.03);
)
//basic tests: absRampUp-Down sanity
(
{var env, source = SinOsc.ar(320,0,0.5);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:1000, outputType:2);
[source.abs, env]
}.plot(0.03);
)
/////////////////////////////
//basic tests: absThresh sanity
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12);
[source, env]
}.plot(0.1);
[source, env]
}.plot(0.1);
)
//basic tests: absThresh hysteresis
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -16);
[source, env]
}.plot(0.1);
[source, env]
}.plot(0.1);
)
//basic tests: absThresh min slice
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minSliceLength:441);
[source, env]
}.plot(0.1);
[source, env]
}.plot(0.1);
)
//basic tests: absThresh min silence
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minSilenceLength:441);
[source, env]
}.plot(0.1);
[source, env]
}.plot(0.1);
)
//mid tests: absThresh time hysteresis on
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthAbove:441, outputType:0);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthAbove:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//mid tests: absThresh time hysteresis off
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12, minLengthBelow:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//mid tests: absThresh with lookBack
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12,lookBack:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//mid tests: absThresh with lookAhead
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12,lookAhead:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//mid tests: absThresh with asymetrical lookBack and lookAhead
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:100, absThreshOn:-12, absThreshOff: -12,lookBack:221, lookAhead:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//advanced tests: absThresh hysteresis, long tail
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16);
[source, env]
}.plot(0.1);
[source, env]
}.plot(0.1);
)
//solution: have to recut with relThresh
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-12);
[source, env]
}.plot(0.1);
[source, env]
}.plot(0.1);
)
//beware of double trig
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-1);
[source, env]
}.plot(0.05);
[source, env]
}.plot(0.05);
)
//a solution: minSliceLength
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:10, absRampDown:2000, absThreshOn:-12, absThreshOff: -16, relRampUp:5, relRampDown:200, relThreshOn:-1, relThreshOff:-1, minSliceLength:441);
[source, env]
}.plot(0.05);
[source, env]
}.plot(0.05);
)
//drum slicing, many ways
//load a buffer
b = Buffer.read(s,File.realpath(FluidAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav");
//have fun with a gate (explore lookahead and lookback, but correct for latency)
(
{var env, source = PlayBuf.ar(1,b);
env = FluidAmpSlice.ar(source,absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:441, relThreshOn:14, relThreshOff:12, minSliceLength:4410, outputType:0);
[source, env]
}.plot(2,maxval:[1,1],separately:true);
{var env, source = PlayBuf.ar(1,b);
env = FluidAmpSlice.ar(source,absRampUp:44, absRampDown:2205, absThreshOn:-20, absThreshOff: -23, minSilenceLength:1100, lookBack:441);
[DelayN.ar(source,delaytime:441/44100), env]
}.plot(2,separately:true);
)
(
{var env, source = PlayBuf.ar(1,b);
env = FluidAmpSlice.ar(source,highPassFreq:120, absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:2205, relThreshOn:12, relThreshOff:8, minSliceLength:441);
[source, env]
}.play);
{var env, source = PlayBuf.ar(1,b);
env = FluidAmpSlice.ar(source,highPassFreq:120, absRampUp:4410, absRampDown:4410, absThreshOn:-60, absThreshOff: -60, relRampUp:10, relRampDown:2205, relThreshOn:13, relThreshOff:10, minSilenceLength:4410, highPassFreq:20);
[source, Trig.ar(env,0)]
}.play;
)
::

@ -81,9 +81,6 @@ ARGUMENT:: relThreshOff
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:: outputType
(describe argument here)
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.
@ -95,8 +92,8 @@ EXAMPLES::
code::
// define a test signal and a destination buffer
(
b = Buffer.sendCollection(s, Array.fill(44100,{|i| sin(i*pi/ (44100/640)) * (sin(i*pi/ 22050)).abs}));
c = Buffer.new(s);
b = Buffer.sendCollection(s, Array.fill(44100,{|i| sin(i*pi/ (44100/640)) * (sin(i*pi/ 22050)).abs}));
c = Buffer.new(s);
)
b.play
b.plot
@ -160,24 +157,36 @@ c.getn(0,c.numFrames*2,{|item|item.postln;})
FluidBufAmpSlice.process(s,b,indices:c, absRampUp:2205, absRampDown:2205, absThreshOn:-60, absThreshOff: -60, relRampUp:5, relRampDown:220, relThreshOn:2, relThreshOff:1, minSliceLength:4410)
c.query
c.getn(0,c.numFrames*2,{|item|item.postln;})
::
/////////////////////////
//drum slicing, many ways
STRONG::A musical example.::
CODE::
//load a buffer
(
b = Buffer.read(s,File.realpath(FluidBufAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav");
c = Buffer.new(s);
)
// slice the samples
FluidBufAmpSlice.process(s,b,indices:c, absRampUp:2205, absRampDown:2205, absThreshOn:-70, absThreshOff: -80, relRampUp:10, relRampDown:441, relThreshOn:14, relThreshOff:12, minSliceLength:4410)
c.query
c.getn(0,c.numFrames*2,{|item|item.postln;})
//AGAIN STRANGE OFFSET ADDRESSES
//loops over a splice with the MouseX
(
{
BufRd.ar(1, b,
Phasor.ar(0,1,
BufRd.kr(1, c,
MouseX.kr(0, BufFrames.kr(c) - 1), 0, 1),
BufRd.kr(1, c,
MouseX.kr(1, BufFrames.kr(c)), 0, 1),
BufRd.kr(1,c,
MouseX.kr(0, BufFrames.kr(c) - 1), 0, 1)), 0, 1);
}.play;
)
::
/// //TO TROUBLESHOOT
STRONG::A stereo buffer example.::
CODE::
// make a stereo buffer
@ -194,9 +203,9 @@ c = Buffer.new(s);
(
// with basic params
Routine{
t = Main.elapsedTime;
FluidBufAmpSlice.process(s,b, indices: c, absRampUp:1, absRampDown:1, absThreshOn:-60, absThreshOff:-60);
(Main.elapsedTime - t).postln;
t = Main.elapsedTime;
FluidBufAmpSlice.process(s,b, indices: c, absRampUp:1, absRampDown:1, absThreshOn:-60, absThreshOff:-60);
(Main.elapsedTime - t).postln;
}.play
)

@ -235,49 +235,77 @@ CODE::
//set some buffers
(
b = Buffer.read(s,File.realpath(FluidBufNMF.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav");
c = Buffer.new(s);
x = Buffer.new(s);
e = Buffer.new(s);
y = Buffer.new(s);
~originalNMF = Buffer.new(s);
~bases = Buffer.new(s);
~trainedBases = Buffer.new(s);
~activations = Buffer.new(s);
~final = Buffer.new(s);
~spectralshapes = Buffer.new(s);
~stats = Buffer.new(s);
~sortedNMF = Buffer.new(s);
)
// train only 2 seconds
b.play
// train using the first 2 seconds of the sound file
(
Routine {
FluidBufNMF.process(s,b,0,88200,0,1, c, x, components:10);
c.query;
FluidBufNMF.process(s,b,0,44100*5,0,1, ~originalNMF, ~bases, components:10);
~originalNMF.query;
}.play;
)
// find the component that has the picking sound by changing which channel to listen to
// listen to the 10 components across the stereo image
{Splay.ar(PlayBuf.ar(10, ~originalNMF))}.play
// plot the bases
~bases.plot
// find the component that has the picking sound checking the median spectral centroid
(
~element = 4;
{PlayBuf.ar(10,c)[~element]}.play
FluidBufSpectralShape.process(s, ~originalNMF, features: ~spectralshapes, action:{
|shapes|FluidBufStats.process(s,shapes,stats:~stats, action:{
|stats|stats.getn(0, (stats.numChannels * stats.numFrames) ,{
|x| ~centroids = x.select({
|item, index| (index.mod(7) == 0) && (index.div(70) == 5);
})
})
})
});
)
// copy all the other components on itself and the picking basis as the sole component of the 1st channel
//what is happening there? We run the spectralshapes on the buffer of 10 components from the nmf. See the structure of that buffer:
~originalNMF.query
//10 channel are therefore giving 70 channels: the 7 shapes of component0, then 7 shapes of compoenent1, etc
~spectralshapes.query
// we then run the bufstats on them. Each channel, which had a time series (an envelop) of each descriptor, is reduced to 7 frames
~stats.query
// we then need to retrieve the values that are where we want: the first of every 7 for the centroid, and the 6th frame of them as we want the median. Because we retrieve the values in an interleave format, the select function gets a bit tricky but we get the following values:
~centroids.postln
// we then copy the basis with the highest median centroid to a channel, and all the other bases to the other channel, of a 2-channel bases for decomposition
(
Routine{
z = (0..9);
FluidBufCompose.process(s, x, startChan: z.removeAt(~element), numChans: 1, destination: e);
z.do({|chan| FluidBufCompose.process(s, x, startChan:chan, numChans: 1, destStartChan: 1, destination: e, destGain:1)});
e.query;
}.play;
z = (0..9);
[z.removeAt(~centroids.maxIndex)].do{|chan|FluidBufCompose.process(s, ~bases, startChan: chan, numChans: 1, destination: ~trainedBases, destGain:1)};
z.postln;
z.do({|chan| FluidBufCompose.process(s, ~bases, startChan:chan, numChans: 1, destStartChan: 1, destination: ~trainedBases, destGain:1)});
)
~trainedBases.plot
//process the whole file, splitting it with the 2 trained bases
(
Routine{
FluidBufNMF.process(s, b, destination: c, bases: e, basesMode: 2, activations: y, components:2);
c.query;
FluidBufNMF.process(s, b, destination: ~sortedNMF, bases: ~trainedBases, basesMode: 2, components:2);
~originalNMF.query;
}.play;
)
// play the result: pick on the left, rest on the right.
c.play
// play the result: pick on the left, sustain on the right!
{PlayBuf.ar(2,~sortedNMF)}.play
// it even null-sums
{(PlayBuf.ar(2,c,doneAction:2).sum)-(PlayBuf.ar(1,b,doneAction:2))}.play
{(PlayBuf.ar(2,~sortedNMF,doneAction:2).sum)-(PlayBuf.ar(1,b,doneAction:2))}.play
::
STRONG::Updating Bases: The process can update bases provided as seed.::

@ -61,7 +61,6 @@ a.reference_(Array.fill(13,{0.5})); //make a center line to show 0
//run the window updating routine.
(
~winRange = 500;
r = Routine {

@ -104,36 +104,44 @@ CODE::
(
b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav");
c = Buffer.new(s);
x = Buffer.new(s);
e = Buffer.new(s);
~bases = Buffer.new(s);
~spectralshapes = Buffer.new(s);
~stats = Buffer.new(s);
~centroids = Buffer.new(s);
~trainedBases = Buffer.new(s);
)
// train only 2 seconds
(
Routine {
FluidBufNMF.process(s,b,0,88200,0,1, c, x, components:10,fftSize:2048);
FluidBufNMF.process(s,b,0,88200,0,1, c, ~bases, components:10,fftSize:2048);
c.query;
}.play;
)
// wait for the query to print
// then find the component that has more sustain pitch than pick (TODO: use descriptors with stats)
// find the component that has the picking sound checking the median spectral centroid
(
~element = 4;
{PlayBuf.ar(10,c)[~element]}.play;
FluidBufSpectralShape.process(s, c, features: ~spectralshapes, action:{
|shapes|FluidBufStats.process(s,shapes,stats:~stats, action:{
|stats|stats.getn(0, (stats.numChannels * stats.numFrames) ,{
|x| ~centroids = x.select({
|item, index| (index.mod(7) == 0) && (index.div(70) == 5);
})
})
})
});
)
// copy all the other components on itself and the picking basis as the sole component of the 1st channel
// we then copy the basis with the lowest median centroid to a channel, and all the other bases to the other channel, of a 2-channel bases for decomposition
(
Routine{
z = (0..9);
FluidBufCompose.process(s, x, startChan: z.removeAt(~element), numChans: 1, destination: e);
z.do({|chan| FluidBufCompose.process(s, x, startChan:chan, numChans: 1, destStartChan: 1, destination: e, destGain:1)});
e.query;
}.play;
z = (0..9);
[z.removeAt(~centroids.minIndex)].do{|chan|FluidBufCompose.process(s, ~bases, startChan: chan, numChans: 1, destination: ~trainedBases, destGain:1)};
z.postln;
z.do({|chan| FluidBufCompose.process(s, ~bases, startChan:chan, numChans: 1, destStartChan: 1, destination: ~trainedBases, destGain:1)});
)
e.plot;
~trainedBases.plot;
//we can then use the resynthesised signal to sent in a delay
(
@ -149,7 +157,7 @@ e.plot;
mod4 = SinOsc.ar(((613 * 191) / (463 * 601)), 0, 0.001);
// compress the signal to send to the delays
todelay = FluidNMFFilter.ar(source,e,2,fftSize:2048)[0]; //reading the channel of the activations on the pick basis
todelay = FluidNMFFilter.ar(source,~trainedBases,2,fftSize:2048)[0]; //reading the channel of the activations on the pick basis
// delay network
feedback = LocalIn.ar(3);// take the feedback in for the delays

@ -104,39 +104,47 @@ CODE::
(
b = Buffer.read(s,File.realpath(FluidNMFMatch.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav");
c = Buffer.new(s);
x = Buffer.new(s);
e = Buffer.new(s);
~bases = Buffer.new(s);
~spectralshapes = Buffer.new(s);
~stats = Buffer.new(s);
~centroids = Buffer.new(s);
~trainedBases = Buffer.new(s);
)
// train only 2 seconds
(
Routine {
FluidBufNMF.process(s,b,0,88200,0,1, c, x, components:10,fftSize:2048);
FluidBufNMF.process(s,b,0,88200,0,1, c, ~bases, components:10,fftSize:2048);
c.query;
}.play;
)
// wait for the query to print
// then find the component that has the picking sound by changing which channel to listen to
// find the component that has the picking sound checking the median spectral centroid
(
~element = 6;
{PlayBuf.ar(10,c)[~element]}.play;
FluidBufSpectralShape.process(s, c, features: ~spectralshapes, action:{
|shapes|FluidBufStats.process(s,shapes,stats:~stats, action:{
|stats|stats.getn(0, (stats.numChannels * stats.numFrames) ,{
|x| ~centroids = x.select({
|item, index| (index.mod(7) == 0) && (index.div(70) == 5);
})
})
})
});
)
// copy all the other components on itself and the picking basis as the sole component of the 1st channel
// we then copy the basis with the highest median centroid to a channel, and all the other bases to the other channel, of a 2-channel bases for decomposition
(
Routine{
z = (0..9);
FluidBufCompose.process(s, x, startChan: z.removeAt(~element), numChans: 1, destination: e);
z.do({|chan| FluidBufCompose.process(s, x, startChan:chan, numChans: 1, destStartChan: 1, destination: e, destGain:1)});
e.query;
}.play;
z = (0..9);
[z.removeAt(~centroids.maxIndex)].do{|chan|FluidBufCompose.process(s, ~bases, startChan: chan, numChans: 1, destination: ~trainedBases, destGain:1)};
z.postln;
z.do({|chan| FluidBufCompose.process(s, ~bases, startChan:chan, numChans: 1, destStartChan: 1, destination: ~trainedBases, destGain:1)});
)
e.plot;
~trainedBases.plot;
//using this trained basis we can see the envelop (activations) of each component
{FluidNMFMatch.kr(PlayBuf.ar(1,b),e,2,fftSize:2048)}.plot(1);
{FluidNMFMatch.kr(PlayBuf.ar(1,b),~trainedBases,2,fftSize:2048)}.plot(1);
// the left/top activations are before, the pick before the sustain.
//we can then use the activation value to sidechain a compression patch that is sent in a delay
@ -154,7 +162,7 @@ e.plot;
// compress the signal to send to the delays
todelay = DelayN.ar(source,0.1, 800/44100, //delaying it to compensate for FluidNMFMatch's latency
LagUD.ar(K2A.ar(FluidNMFMatch.kr(source,e,2,fftSize:2048)[0]), //reading the channel of the activations on the pick basis
LagUD.ar(K2A.ar(FluidNMFMatch.kr(source,~trainedBases,2,fftSize:2048)[0]), //reading the channel of the activations on the pick basis
80/44100, // lag uptime (compressor's attack)
1000/44100, // lag downtime (compressor's decay)
(1/(2.dbamp) // compressor's threshold inverted
@ -195,7 +203,7 @@ Routine {
// wait for the query to print
// then find a component for each item you want to find. You could also sum them. Try to find a component with a good object-to-rest ratio
(
~dog =2;
~dog =4;
{PlayBuf.ar(10,c)[~dog]}.play
)

Loading…
Cancel
Save