Merge branch 'clients/inter_client_comms' of https://bitbucket.org/flucoma/flucoma-supercollider into clients/inter_client_comms

nix
Gerard 6 years ago
commit 913933943c

@ -1213,6 +1213,12 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
using IndexList =
typename Client::MessageSetType::template MessageDescriptorAt<
N>::IndexList;
if(!x->init)
{
std::cout << "ERROR: Synth constructor not yet called" << std::endl;
return;
}
launchMessageImpl<N>(x, args, IndexList());
}
@ -1421,6 +1427,7 @@ class FluidSCWrapper : public impl::FluidSCWrapperBase<C>
<< std::endl;
}
bool init{false};
public:
using Client = C;
@ -1432,6 +1439,7 @@ public:
{
client().setParams(params()); //<-IMPORTANT: client's ref to params is by address, and this has just changed
impl::FluidSCWrapperBase<Client>::init();
init = true;
}
~FluidSCWrapper()

@ -39,7 +39,11 @@ public:
if (auto datasetPtr = dataset.lock())
{
std::stringstream ss;
ss << get<1>() << get<2>() + (mCounter++);
ss << get<1>();
index labelOffset = get<2>();
if(labelOffset >= 0) ss << labelOffset + (mCounter++);
auto buf = get<3>();
return datasetPtr->addPoint(ss.str(), buf);
}

@ -1,59 +1,40 @@
FluidBufAudioTransport : UGen{
var <>synth, <>server;
*kr { |source1, startFrame1 = 0, numFrames1 = -1, startChan1 = 0, numChans1 = -1, source2, startFrame2 = 0, numFrames2 = -1, startChan2 = 0, numChans2 = -1, destination, interpolation=0.0, bandwidth=255, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1|
*new1 { |rate, source1, startFrame1 = 0, numFrames1 = -1, startChan1 = 0, numChans1 = -1, source2, startFrame2 = 0, numFrames2 = -1, startChan2 = 0, numChans2 = -1, destination, interpolation=0.0, bandwidth=255, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking=0|
var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize};
var blocking = 0;
source1.isNil.if {"FluidAudioTransport: Invalid source 1 buffer".throw};
source2.isNil.if {"FluidAudioTransport: Invalid source 2 buffer".throw};
source2.isNil.if {"FluidAudioTransport: Invalid source 2 buffer".throw};
source1 = source1.asUGenInput;
source2 = source2.asUGenInput;
source2 = source2.asUGenInput;
destination.isNil.if {"FluidAudioTransport: Invalid destination buffer".throw};
destination = destination.asUGenInput;
destination.isNil.if {"FluidAudioTransport: Invalid destination buffer".throw};
destination = destination.asUGenInput;
//NB For wrapped versions of NRT classes, we set the params for maxima to
//whatever has been passed in language-side (e.g maxFFTSize still exists as a parameter for the server plugin, but makes less sense here: it just needs to be set to a legal value)
^super.new1(rate,source1, startFrame1, numFrames1, startChan1, numChans1, source2, startFrame1, numFrames1, startChan2, numChans2, destination, interpolation, bandwidth, windowSize, hopSize, fftSize, maxFFTSize, trig,blocking)
^this.multiNew(\control, source1, startFrame1, numFrames1, startChan1, numChans1, source2, startFrame1, numFrames1, startChan2, numChans2, destination, interpolation, bandwidth, windowSize, hopSize, fftSize,maxFFTSize, trig,blocking);
}
*process { |server, source1, startFrame1 = 0, numFrames1 = -1, startChan1 = 0, numChans1 = -1, source2, startFrame2 = 0, numFrames2 = -1, startChan2 = 0, numChans2 = -1, destination, interpolation=0.0, bandwidth=255, windowSize = 1024, hopSize = -1, fftSize = -1, action|
var synth, instance;
source1.isNil.if {"FluidAudioTransport: Invalid source 1 buffer".throw};
source2.isNil.if {"FluidAudioTransport: Invalid source 2 buffer".throw};
destination.isNil.if {"FluidAudioTransport: Invalid destination buffer".throw};
*kr { |source1, startFrame1 = 0, numFrames1 = -1, startChan1 = 0, numChans1 = -1, source2, startFrame2 = 0, numFrames2 = -1, startChan2 = 0, numChans2 = -1, destination, interpolation=0.0, bandwidth=255, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1|
^this.new1(\control, source1, startFrame1, numFrames1, startChan1, numChans1, source2, startFrame1, numFrames1, startChan2, numChans2, destination, interpolation, bandwidth, windowSize, hopSize, fftSize, trig);
}
source1 = source1.asUGenInput;
source2 = source2.asUGenInput;
destination = destination.asUGenInput;
server = server ? Server.default;
server.ifNotRunning({
"WARNING: Server not running".postln;
^nil;
});
synth = { instance = FluidBufAudioTransport.kr(source1, startFrame1, numFrames1, startChan1, numChans1, source2, startFrame1, numFrames1, startChan2, numChans2, destination, interpolation, bandwidth, windowSize, hopSize, fftSize, trig:1)}.play(server);
forkIfNeeded{
synth.waitForFree;
server.sync;
if (destination != -1) {destination = server.cachedBufferAt(destination); destination.updateInfo; server.sync;} {destination = nil};
action.value(destination);
};
instance.synth = synth;
instance.server = server;
^instance;
*process { |server, source1, startFrame1 = 0, numFrames1 = -1, startChan1 = 0, numChans1 = -1, source2, startFrame2 = 0, numFrames2 = -1, startChan2 = 0, numChans2 = -1, destination, interpolation=0.0, bandwidth=255, windowSize = 1024, hopSize = -1, fftSize = -1, action|
^FluidNRTProcess.new(
server, this, action, [destination]
).process(
source1, startFrame1, numFrames1, startChan1, numChans1, source2, startFrame2, numFrames2, startChan2, numChans2, destination, interpolation, bandwidth, windowSize, hopSize, fftSize
)
}
cancel{
if(this.server.notNil)
{this.server.sendMsg("/u_cmd", this.synth.nodeID, this.synthIndex, "cancel")};
}
*processBlocking { |server, source1, startFrame1 = 0, numFrames1 = -1, startChan1 = 0, numChans1 = -1, source2, startFrame2 = 0, numFrames2 = -1, startChan2 = 0, numChans2 = -1, destination, interpolation=0.0, bandwidth=255, windowSize = 1024, hopSize = -1, fftSize = -1, action|
^FluidNRTProcess.new(
server, this, action, [destination],blocking:1
).process(
source1, startFrame1, numFrames1, startChan1, numChans1, source2, startFrame2, numFrames2, startChan2, numChans2, destination, interpolation, bandwidth, windowSize, hopSize, fftSize
)
}
}

@ -83,14 +83,13 @@ FluidSliceCorpus {
var rawPoints = Array.newFrom(a).asInteger;
if(rawPoints[0] != [v[\bounds][0]]){rawPoints = [v[\bounds][0]] ++ rawPoints};
if(rawPoints.last != [v[\bounds][1]]){rawPoints=rawPoints ++ [v[\bounds][1]]};
rawPoints.doAdjacentPairs{|a,b|
var dict;
if ((b - a) >= 1){
dict = IdentityDictionary();
dict.putAll(v);
dict[\bounds] = [a,b];
dict[\prefix] = k;
dict[\index] = sliceindex;
index.add(((k ++ "-" ++sliceindex).asSymbol)->dict);
sliceindex = sliceindex + 1;
}
@ -141,7 +140,7 @@ FluidProcessSlices{
counter = counter + 1;
("Processing" + counter ++ "/" ++ total).postln;
idx = counter;
v[\allindex] = counter;
v[\index] = counter;
v[\voice] = jobID;
OSCFunc({
completed = completed + 1;

@ -23,7 +23,7 @@
mfcc = FluidBufMFCC.kr(src,startFrame:start,numFrames:num,numChans:1,features:~mfccbuf[voice],trig:1);
stats = FluidBufStats.kr(~mfccbuf[voice],stats:~statsbuf[voice],trig:Done.kr(mfcc));
flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats));
writer = FluidDataSetWr.kr(~ds,label,buf: ~flatbuf[voice],trig:Done.kr(flatten))
writer = FluidDataSetWr.kr(~ds,label, -1, ~flatbuf[voice], Done.kr(flatten))
});
)

@ -19,16 +19,16 @@ ARGUMENT:: in
The audio to be processed.
ARGUMENT:: rampUp
The number of samples the absolute envelope follower will take to reach the next value when raising.
The number of samples the envelope follower will take to reach the next value when raising.
ARGUMENT:: rampDown
The number of samples the absolute envelope follower will take to reach the next value when falling.
The number of samples the envelope follower will take to reach the next value when falling.
ARGUMENT:: onThreshold
The threshold in dB of the absolute envelope follower to trigger an onset, aka to go ON when in OFF state.
The threshold in dB of the envelope follower to trigger an onset, aka to go ON when in OFF state.
ARGUMENT:: offThreshold
The threshold in dB of the absolute envelope follower to trigger an offset, , aka to go ON when in OFF state.
The threshold in dB of the envelope follower to trigger an offset, , aka to go ON when in OFF state.
ARGUMENT:: minSliceLength
The length in samples that the Slice will stay ON. Changes of states during that period will be ignored.
@ -37,10 +37,10 @@ ARGUMENT:: minSilenceLength
The length in samples that the Slice will stay OFF. Changes of states during that period will be ignored.
ARGUMENT:: minLengthAbove
The length in samples that the absolute envelope have to be above the threshold to consider it a valid transition to ON. The Slice will start at the first sample when the condition is met. Therefore, this affects the latency.
The length in samples that the envelope have to be above the threshold to consider it a valid transition to ON. The Slice will start at the first sample when the condition is met. Therefore, this affects the latency.
ARGUMENT:: minLengthBelow
The length in samples that the absolute envelope have to be below the threshold to consider it a valid transition to OFF. The Slice will end at the first sample when the condition is met. Therefore, this affects the latency.
The length in samples that the envelope have to be below the threshold to consider it a valid transition to OFF. The Slice will end at the first sample when the condition is met. Therefore, this affects the latency.
ARGUMENT:: lookBack
The length of the buffer kept before an onset to allow the algorithm, once a new Slice is detected, to go back in time (up to that many samples) to find the minimum amplitude as the Slice onset point. This affects the latency of the algorithm.
@ -49,7 +49,7 @@ ARGUMENT:: lookAhead
The length of the buffer kept after an offset to allow the algorithm, once the Slice is considered finished, to wait further in time (up to that many samples) to find a minimum amplitude as the Slice offset point. This affects the latency of the algorithm.
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.
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. A frequency of 0 bypasses the filter.
ARGUMENT:: maxSize
How large can the buffer be for time-critical conditions, by allocating memory at instantiation time. This cannot be modulated.
@ -129,7 +129,7 @@ b = Buffer.read(s,File.realpath(FluidAmpGate.class.filenameSymbol).dirname.withT
//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:441, rampDown:2205, onThreshold:-27, offThreshold: -31, minSilenceLength:1100, lookBack:441, highPassFreq:20);
env = FluidAmpGate.ar(source, rampUp:441, rampDown:2205, onThreshold:-27, offThreshold: -31, minSilenceLength:4410, lookBack:441, highPassFreq:20);
[DelayN.ar(source,delaytime:441/44100), env]
}.plot(2, separately:true);
)

@ -43,7 +43,7 @@ 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 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.
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. A frequency of 0 bypasses the filter.
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.

@ -44,5 +44,5 @@ EXAMPLES::
code::
//the mouse X axis interpolates between the two sinewaves
{FluidAudioTransport.ar(SinOsc.ar(220),SinOsc.ar(440),MouseX.kr())}.play;
{FluidAudioTransport.ar(SinOsc.ar(220,mul: 0.1),SinOsc.ar(440,mul: 0.02),MouseX.kr())}.play;
::

@ -41,16 +41,16 @@ ARGUMENT:: indices
The index of the buffer where the indices (in sample) of the estimated starting points of slices will be written. The first and last points are always the boundary points of the analysis.
ARGUMENT:: rampUp
The number of samples the absolute envelope follower will take to reach the next value when raising.
The number of samples the envelope follower will take to reach the next value when raising.
ARGUMENT:: rampDown
The number of samples the absolute envelope follower will take to reach the next value when falling.
The number of samples the envelope follower will take to reach the next value when falling.
ARGUMENT:: onThreshold
The threshold in dB of the absolute envelope follower to trigger an onset, aka to go ON when in OFF state.
The threshold in dB of the envelope follower to trigger an onset, aka to go ON when in OFF state.
ARGUMENT:: offThreshold
The threshold in dB of the absolute envelope follower to trigger an offset, , aka to go ON when in OFF state.
The threshold in dB of the envelope follower to trigger an offset, , aka to go ON when in OFF state.
ARGUMENT:: minSliceLength
The length in samples that the Slice will stay ON. Changes of states during that period will be ignored.
@ -59,10 +59,10 @@ ARGUMENT:: minSilenceLength
The length in samples that the Slice will stay OFF. Changes of states during that period will be ignored.
ARGUMENT:: minLengthAbove
The length in samples that the absolute envelope have to be above the threshold to consider it a valid transition to ON. The Slice will start at the first sample when the condition is met. Therefore, this affects the latency.
The length in samples that the envelope have to be above the threshold to consider it a valid transition to ON. The Slice will start at the first sample when the condition is met. Therefore, this affects the latency.
ARGUMENT:: minLengthBelow
The length in samples that the absolute envelope have to be below the threshold to consider it a valid transition to OFF. The Slice will end at the first sample when the condition is met. Therefore, this affects the latency.
The length in samples that the envelope have to be below the threshold to consider it a valid transition to OFF. The Slice will end at the first sample when the condition is met. Therefore, this affects the latency.
ARGUMENT:: lookBack
The length of the buffer kept before an onset to allow the algorithm, once a new Slice is detected, to go back in time (up to that many samples) to find the minimum amplitude as the Slice onset point. This affects the latency of the algorithm.
@ -71,7 +71,7 @@ ARGUMENT:: lookAhead
The length of the buffer kept after an offset to allow the algorithm, once the Slice is considered finished, to wait further in time (up to that many samples) to find a minimum amplitude as the Slice offset point. This affects the latency of the algorithm.
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.
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. A frequency of 0 bypasses the filter.
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.

@ -65,7 +65,7 @@ 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 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.
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. A frequency of 0 bypasses the filter.
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.
@ -86,7 +86,7 @@ c = Buffer.new(s);
b.play
b.plot
//
//process with symmetrical thresholds
FluidBufAmpSlice.process(s, b,indices: c,fastRampUp: 5,fastRampDown: 50,slowRampUp: 220,slowRampDown: 220, onThreshold: 10, offThreshold: 10,floor: -60);
c.query
c.getn(0,c.numFrames,{|item|item.postln;})

@ -81,7 +81,7 @@ code::
//Make 2 sources to be interpolated
(
b = Buffer.loadCollection(s, FloatArray.fill(44100, {|a|(a / pi).sin * 0.1}));
c = Buffer.loadCollection(s, FloatArray.fill(44100, {|a|(a / pi / 2).sin * 0.1}));
c = Buffer.loadCollection(s, FloatArray.fill(44100, {|a|(a / pi / 2).sin * 0.02}));
d = Buffer.new
)

@ -156,7 +156,7 @@ d.postln
e = Array.new;
d.do({
arg val, i;
if ((val[0] > 500) && (val[1] > 0.666)) {e = e.add(i)}; // if pitch is greater than 500Hz and confidence higher than 0.666, keep the index
if ((val[0] > 500) && (val[1] > 0.98)) {e = e.add(i)}; // if pitch is greater than 500Hz and confidence higher than 0.98, keep the index
});
)
e.postln;

@ -175,5 +175,5 @@ FluidBufStats.process(s, b, stats:c, numDerivs:1, action:{c.getn(0,c.numFrames *
//looking at the result is not easy to grasp, since it is interleaved: first number is mean of L, second is mean of R, third is stddev of L, fourth is stddev or R
//this will make it tidier - the first value of each line is Left, the second is Right
d.reshape(14,2).do({|x,i|["mean\t\t","stddev\t\t","skew\t\t\t", "kurtosis\t", "min\t\t\t", "median\t\t", "max\t\t\t","d-mean\t","d-stddev\t","d-skew\t\t", "d-kurtosis", "d-min\t\t", "d-median\t", "d-max\t\t"].at(i).post;x.round(0.01).postln})
d.reshape(14,2).do({|x,i|["mean\t\t","stddev\t\t","skew\t\t\t", "kurtosis\t", "min\t\t\t", "median\t\t", "max\t\t\t","d-mean\t","d-stddev\t","d-skew\t\t", "d-kurtosis", "d-min\t\t", "d-median\t", "d-max\t\t"].at(i).post;x.round(0.01).postln});"".postln;
::

@ -60,8 +60,8 @@ FluidBufThreadDemo.process(s, b, 1000, {|x|x.get(0,{|y|y.postln});});
// as the 'process' returns its parent UGen, we can cancel the process easily
c = FluidBufThreadDemo.process(s, b, 100000, {|x|x.get(0,{|y|y.postln});});
c.cancel
c.cancel //it stops silently for now but check the synth count going down by 1.
// if a simple call to the UGen is used, the progress can be monitored
// if a simple call to the UGen is used, the progress can be monitored. The usual cmd. will cancel the job by freeing the synth.
{c = FluidBufThreadDemo.kr(b,10000, Done.freeSelf); Poll.kr(Impulse.kr(2),c);}.scope;
::

@ -4,7 +4,17 @@ categories:: FluidManipulation
related:: Classes/FLuidDataSet
DESCRIPTION::
A UGen that writes to a link::Classes/FluidDataSet::
A UGen that adds labelled points to a link::Classes/FluidDataSet::
By default the object generates a numerical index that gets used for the point labels. This index starts counting from link::#offset#labelOffset:: and increments each time the Ugen is retriggered with a zero to non-zero transition. The label is then concatenated with the code::labelPrefix:: symbol, which is fixed at instantiation. In this way, one can make custom, incrementing labels, e.g.
code::
FluidDataSetWr.kr(~somedataset,"my_data",0,~somebuffer,trig)
::
would add points like code::my_data0, mydata1, mydata2...:: if successively retriggered.
Alternatively, for one shot use you may not want a numerical suffix at all. Setting code::indexLabel:: < 0 will bypass this and use only the labelPrefix. As such, any retriggering will result in a complaint from the link::Classes/FluidDataSet:: that the requested label is already present.
CLASSMETHODS::
@ -20,12 +30,14 @@ ARGUMENT:: labelPrefix
A string or symbol with a prefix for generated labels
ARGUMENT:: labelOffset
An integer with the offset to start labeling from. If the UGen is run in a server-side loop (i.e. repeatedly retriggered), the generated labels will count upwards from this offset.
ANCHOR::offset::
An integer with the offset to start labeling from. If the UGen is run in a server-side loop (i.e. repeatedly retriggered), the generated labels will count upwards from this offset. If < 0, then no numerical index will be applied to the generated label (i.e. only the labelPrefix is used).
ARGUMENT:: buf
The link::Classes/Buffer:: containing the data point.
ARGUMENT:: trig
A kr trigger signal
EXAMPLES::

@ -32,7 +32,7 @@ ARGUMENT:: maxwindowSize
How large can the windowSize be, by allocating memory at instantiation time. This cannot be modulated.
RETURNS::
A 2-channel KR signal with the [pitch, confidence] descriptors. The latency is windowSize.
A 2-channel KR signal with the [loudness, peak] descriptors. The latency is windowSize.
EXAMPLES::

@ -61,7 +61,7 @@ a.reference_(Array.fill(13,{0.5})); //make a center line to show 0
//run the window updating routine.
(
~winRange = 500;
~winRange = 200;
r = Routine {
{
@ -89,7 +89,7 @@ x = {arg type = 0;
// change the wave types, observe the amplitude invariance of the descriptors, apart from the leftmost coefficient
x.set(\type, 1)
~winRange = 100; //adjust the range above and below 0 to zoom in or out on the MFCC
~winRange = 50; //adjust the range above and below 0 to zoom in or out on the MFCC
x.set(\type, 2)
x.set(\type, 0)
// free this source
@ -106,6 +106,7 @@ x = {arg bands = 40, low = 20, high = 20000;
source.dup;
}.play;
)
~winRange = 10; //adjust the range above and below 0 to zoom in or out on the MFCC
// observe the number of bands. The unused ones at the top are not updated
x.set(\bands,20)

@ -89,11 +89,11 @@ Routine {
e.plot
//listen how the filter isolates each component and places them in each channel separately.
{FluidNMFFilter.ar(SinOsc.ar(500),e,2)}.play
{FluidNMFFilter.ar(SinOsc.ar(500, mul: 0.1),e,2)}.play
{FluidNMFFilter.ar(SinOsc.ar(5000),e,2)}.play
{FluidNMFFilter.ar(SinOsc.ar(5000, mul: 0.1),e,2)}.play
{FluidNMFFilter.ar(SinOsc.ar([500,5000]).sum,e,2)}.play
{FluidNMFFilter.ar(SinOsc.ar([500,5000], mul: 0.1).sum,e,2)}.play
::
STRONG::A guitar processor::

@ -216,7 +216,7 @@ FluidBufSpectralShape.process(s, c, features: ~spectralshapes, action:{
});
)
//7 shapes (track) x 8 components (tracks) x 7 stats(frames)
//the interleave format is 7 stats(frames) x 8 components in the source as tracks x 7 shapes (tracks)
~stats.query
~centroids.size()
@ -230,8 +230,8 @@ x = {
var sound = PlayBuf.ar(1,b,loop:1);
var harm, perc;
# harm, perc = FluidHPSS.ar(sound, maskingMode:1, harmThreshFreq1: 0.005869, harmThreshAmp1: -9.6875, harmThreshFreq2: 0.006609, harmThreshAmp2: -4.375, hopSize:256);
Out.ar(~splitaudio, harm);
Out.kr(~nmfenvs, FluidNMFMatch.kr(sound, ~bases, maxComponents:8, hopSize:256, fftSize:2048));
Out.ar(~splitaudio, (harm / 4) + perc);
Out.kr(~nmfenvs, FluidNMFMatch.kr(DelayN.ar(sound,delaytime: ((17-1)*256)/44100), ~bases, maxComponents:8, hopSize:256, fftSize:2048));
Out.ar(0,perc.dup)
}.play;
)
@ -241,7 +241,7 @@ x = {
8.do({
arg i;
{
var audio = BPF.ar(In.ar(~splitaudio,1), ~centroids[i],0.01,LagUD.kr(In.kr(~nmfenvs,8)[i],0.001,0.01,0.1));
var audio = BPF.ar(In.ar(~splitaudio,1), ~centroids[i],0.0015,Lag.kr(In.kr(~nmfenvs,8)[i] * 2,0.022));
Out.ar(0,Pan2.ar(audio, (i / 14) - 0.25));
}.play(x,addAction: \addAfter);
});

@ -107,13 +107,12 @@ s.reboot;
//write pitch statistics into a dataset
(
~extractor = FluidProcessSlices({|src,start,num,data|
var pitch, stats, labelPrefix, labelIndex, i;
var pitch, stats, label,i;
i = data.value[\voice];
labelPrefix = data.value[\prefix];
labelIndex = data.value[\index];
label = data.key;
pitch = FluidBufPitch.kr(src,start,num,features:~pitchbufs[i]);
stats = FluidBufStats.kr(~pitchbufs[i],stats:~statsbufs[i],trig:Done.kr(pitch));
FluidDataSetWr.kr(~pitchdata,labelPrefix,labelIndex,buf:~statsbufs[i],trig:Done.kr(stats))
FluidDataSetWr.kr(~pitchdata,label,-1,buf:~statsbufs[i],trig:Done.kr(stats))
});
)

@ -82,6 +82,12 @@ b = Buffer.read(s,File.realpath(FluidSines.class.filenameSymbol).dirname.withTra
// as the algorithm resynthesize the sinusoidal peaks, we would expect to get it to work almost perfectly on a sine wave, with these settings that tell the process to tolerate everything as a sinusoid, even short and quiet peaks
{FluidSines.ar(SinOsc.ar(mul: 0.1),detectionThreshold: -144,birthLowThreshold: -144,birthHighThreshold: -144,minTrackLen: 1,trackMagRange: 200,trackFreqRange: 1000,trackProb: 0)}.play;
// we can listen to the artefact in solo, amplifying it by 30dB, to hear the 'lobes' - not bad at all!
{FluidSines.ar(SinOsc.ar(mul: 0.1),detectionThreshold: -144,birthLowThreshold: -144,birthHighThreshold: -144,minTrackLen: 1,trackMagRange: 200,trackFreqRange: 1000,trackProb: 0)[1].dup * Line.ar(0,30,1).dbamp}.play;
// as this is a windowed process, the frequency of the peak is good for that full window, and therefore interesting artefacts appear when the pitch is changing.
{FluidSines.ar(SinOsc.ar(LFTri.kr(0.1).exprange(220,880),mul: 0.1),detectionThreshold: -144,birthLowThreshold: -144,birthHighThreshold: -144,minTrackLen: 1,trackMagRange: 300,trackFreqRange: 1000,trackProb: 0)}.play;
// if we solo and amplify the artefacts, they are much more apparent (and interesting)
{FluidSines.ar(SinOsc.ar(LFTri.kr(0.1).exprange(220,880),mul: 0.1),detectionThreshold: -144,birthLowThreshold: -144,birthHighThreshold: -144,minTrackLen: 1,trackMagRange: 300,trackFreqRange: 1000,trackProb: 0)[1].dup * Line.ar(0,30,1).dbamp}.play;
::

Loading…
Cancel
Save