FluidDataSetWr Exclude Silences

Hi all,

I am using SuperCollider and FluCoMa to create a classifier (much like the tutorial already posted, but with a broader set of instruments). I was wondering whether FluidDataSetWr stops recording data into the FluidDataSet during silences in an audio buffer or if it’s possible to ensure this happens?

I have tried to write up a synth controller that auto detects amplitude and then sends a reply to the client to add points to the fluid data set when the amplitude is above a certain threshold, but for some reason, no points are being recorded. Maybe I have a silly mistake in my code as well…

~nmfccs = 13;
~mfccbuf = Buffer.alloc(s,13);
~timbredata = FluidDataSet(s);
~labels = [FluidLabelSet(s), FluidLabelSet(s), FluidLabelSet(s)];
~counter = 0;

// function to build an amplitude detecting SynthDef that sends its name and amplitude value as a reply out of the server from a factory made SynthDef.
~amp_reply_synth_def_constructor = {
	arg synthDefName;
	SynthDef.new(\++synthDefName, {
		arg bufnum=0, start=1;
		var playBuf, trig, amp, mfccs;
		playBuf = PlayBuf.ar(2, bufnum, BufRateScale.ir(bufnum), start, doneAction:2);
		trig = Impulse.ar(30);
		amp = Amplitude.kr(playBuf);
		mfccs = FluidMFCC.kr(playBuf, ~nmfccs, startCoeff:1, maxNumCoeffs: ~nmfccs);
		FluidKrToBuf.kr(mfccs, ~mfccbuf);
		SendReply.ar(trig, '/'++synthDefName.asString, amp);
		Out.ar(0, playBuf);
	}).add;
};

// Function to build a given Synth with an amplitude reply based on a synthDef name and a given buf num.
~amp_reply_synth_init = {
	arg synthDefName, buf;
	var synth, newSynthDef;
	newSynthDef = ~amp_reply_synth_def_constructor.value(synthDefName);
	synth = Synth(synthDefName, [\bufnum, buf]);
};

~osc_def_point_adder_builder = {
	arg oscPath;
	var smoothingArray, counter;
	smoothingArray = Array.fill(10, {arg i; 0});
	counter = 0;
	OSCdef(\analy, {|msg, time|
		var avg;
		// put 10 values into an array
		smoothingArray.put(counter % 10, msg[3]);
		// average values
		avg = smoothingArray.median;

		// increment counter
		counter = counter + 1;
		//Boolean test for whether rolling average amplitude is over desired level. Add point if true.
		if(avg > 0.0009, {	~add_point.value(oscPath); });

	}, oscPath);
};

// Function to add points to timbre data and labels
~add_point = {
	arg oscPath;
	var id, labels;
	id = "example-%".format(~counter);
	labels = oscPath.asString.split($-);
	~timbredata.addPoint(id,~mfccbuf);
	~labels.do({
		arg item, i;
		item.addLabel(id, labels[i]);
	});
	~counter = ~counter + 1;
};

// amp reply synth init test code - do one by one for now...
~singlePath = PathName.new("/path/to/train/aluminum-brush-fortissimo.wav");
b = Buffer.read(s, ~singlePath.fullPath, 0, -1);
~osc_def_point_adder_builder.value('aluminum-brush-fortissimo');
~amp_reply_synth_init.value('aluminum-brush-fortissimo', b);

For some reason pulling this process out of a SynthDef and just jumping straight to a synth like in the example classifier worked.

~amp_reply_synth_constructor = {
	arg synthDefName, bufnum, start;
	{
		var playBuf, trig, amp, mfccs;
		playBuf = PlayBuf.ar(1, bufnum, BufRateScale.ir(bufnum), start, doneAction:2);
		trig = Impulse.ar(30);
		mfccs = FluidMFCC.kr(playBuf, ~nmfccs, startCoeff:1, maxNumCoeffs: ~nmfccs);
		FluidKrToBuf.kr(mfccs,~mfccbuf);
		amp = Amplitude.kr(playBuf);
		SendReply.ar(trig, '/'++synthDefName.asString, amp);
		Out.ar(0, playBuf);
	}.play;
};

Hmm, not sure why that would be offhand. May @tedmoore can spot something.

Anyway, glad it seems to be working now!

FluidDataSetWr creates a new data point when triggered so you could have it only be triggered if the volume is above a certain threshold. I often do these kinds of things by multiplying an Impulse.kr by a boolean 1 or 0 if the volume is above the threshold or not (effectively “muting” Impulse’s triggers).

//==========================================================

	newSynthDef = ~amp_reply_synth_def_constructor.value(synthDefName);
	synth = Synth(synthDefName, [\bufnum, buf]);

the problem here is that the server isn’t done preparing the synthdef for use by the time you ask the server to create the new synth from the def. if you synced with the server after adding the synth def–before creating the synth you’d be ok. because your solution was to not use a synth def but just put it all in a function, there’s no need to wait for the server since calling .play on a function sends it to the server and creates the synth in one go.

let me know if that answers the question!

t

2 Likes