FluidBufToKr don't work with buffer.bufnum as argument

Hello to all,

I have a question maybe for @tedmoore or @tremblap ? but a solution from anybody is welcome too.
I 'd like to pass a buffer as argument to a SynthDef for feeding a FluidBufToKr UGen.
The documentation for the argument buffer of the FluidBufToKr stated:
" buffer Either a Buffer object or an index pointing to a buffer that this pseudo UGen will read out of…"
But I have an error message (entire message at the end of the post) when I try to pass a bufnum or even an instance of Buffer as an argument.

Here is a piece of code to illustrate the problem:

(
s.waitForBoot{ arg predicting = 0;
	var xydata = FluidDataSet(s);
	var paramsdata = FluidDataSet(s);
	var xybuf = Buffer.alloc(s, 2);
	var paramsbuf = Buffer.alloc(s, 10);
	
	var mlp = FluidMLPRegressor(s,
		[7],
		activation: FluidMLPRegressor.sigmoid,
		outputActivation: FluidMLPRegressor.sigmoid,
		maxIter: 1000,
		learnRate: 0.1,
		batchSize: 1,
		validation: 0
	);
	
	{
		var values, xy, trig;
		
		xy = FluidBufToKr.kr(xybuf);
		trig = Mix(Changed.kr(xy));
		mlp.kr(trig * predicting, xybuf, paramsbuf);
		values = FluidBufToKr.kr(paramsbuf);
		
		/*...*/
	}.play;
};
)

(
s.waitForBoot{
	var xydata = FluidDataSet(s);
	var paramsdata = FluidDataSet(s);
	var xybuf = Buffer.alloc(s, 2);
	var paramsbuf = Buffer.alloc(s, 10);
	
	var mlp = FluidMLPRegressor(s,
		[7],
		activation: FluidMLPRegressor.sigmoid,
		outputActivation: FluidMLPRegressor.sigmoid,
		maxIter: 1000,
		learnRate: 0.1,
		batchSize: 1,
		validation: 0
	);
	
	{
		SynthDef(\regressor, { arg xybuf, paramsbuf, predicting = 0;
			var values, xy, trig;
			
			xy = FluidBufToKr.kr(xybuf);
			trig = Mix(Changed.kr(xy)) * predicting;
			mlp.kr(trig, xybuf, paramsbuf);
			values = FluidBufToKr.kr(paramsbuf);
			
			/*...*/
		}).add;
		
		s.sync;
		
		Synth(\regressor, [\xybuf, xybuf.bufnum, \paramsbuf, paramsbuf.bufnum, \predicting, 0]);
	}.fork;
};
)

First block of code: No error message.
Second block of code: error:

ERROR: Meta_FluidBufToKr if no buffer is specified, numFrames must be a value >= 1.

PROTECTED CALL STACK:
	Meta_FluidBufToKr:kr	0x614de35ba500
		arg this = FluidBufToKr
		arg buffer = an OutputProxy
		arg startFrame = 0
		arg numFrames = -1
	a FunctionDef	0x614de5055098
		sourceCode = "<an open Function>"
		arg xybuf = an OutputProxy
		arg paramsbuf = an OutputProxy
		arg predicting = an OutputProxy
		var values = nil
		var xy = nil
		var trig = nil
	SynthDef:buildUgenGraph	0x614de40ac040
		arg this = SynthDef:regressor
		arg func = a Function
		arg rates = nil
		arg prependArgs = [  ]
		var result = nil
		var saveControlNames = nil
	a FunctionDef	0x614de40aa5c0
		sourceCode = "<an open Function>"
	Function:prTry	0x614de23dd000
		arg this = a Function
		var result = nil
		var thread = a Routine
		var next = nil
		var wasInProtectedFunc = false
	
CALL STACK:
	Exception:reportError
		arg this = <instance of Error>
	Nil:handleError
		arg this = nil
		arg error = <instance of Error>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of Error>
	Thread:handleError
		arg this = <instance of Routine>
		arg error = <instance of Error>
	Object:throw
		arg this = <instance of Error>
	Function:protect
		arg this = <instance of Function>
		arg handler = <instance of Function>
		var result = <instance of Error>
	SynthDef:build
		arg this = <instance of SynthDef>
		arg ugenGraphFunc = <instance of Function>
		arg rates = nil
		arg prependArgs = nil
	< FunctionDef in closed FunctionDef >  (no arguments or variables)
	Routine:prStart
		arg this = <instance of Routine>
		arg inval = 631.683702033
^^ The preceding error dump is for ERROR: Meta_FluidBufToKr if no buffer is specified, numFrames must be a value >= 1.

if you’re going to pass in the buffer later (as an argument to the synth) the buf to kr has no way of knowing how long of a kr stream it needs to output (which is needed to construct the synth’s graph), so you can tell it with the argument numFrames how many values it will output.

specify that argument and it should work.

2 Likes

Thank you very much for your answer and my apologies, I have to read the documentation and the error message more carefully.
I try to follow your advice but I get another error.
This is what I tried:

(
s.waitForBoot{
	var xydata = FluidDataSet(s);
	var paramsdata = FluidDataSet(s);
	var xybuf = Buffer.alloc(s, 2);
	var paramsbuf = Buffer.alloc(s, 10);
	
	var mlp = FluidMLPRegressor(s,
		[7],
		activation: FluidMLPRegressor.sigmoid,
		outputActivation: FluidMLPRegressor.sigmoid,
		maxIter: 1000,
		learnRate: 0.1,
		batchSize: 1,
		validation: 0
	);
	
	{
		SynthDef(\regressor, { arg xybuf, xybNumFrames, paramsbuf, paramsbNumFrames, predicting = 0;
			var values, xy, trig;
			
			xy = FluidBufToKr.kr(xybuf, numFrames: xybNumFrames);
			trig = Mix(Changed.kr(xy)) * predicting;
			mlp.kr(trig, xybuf, paramsbuf);
			values = FluidBufToKr.kr(paramsbuf, numFrames: paramsbNumFrames);
			
			/*...*/
		}).add;
		
		s.sync;
		
		Synth(\regressor, [\xybuf, xybuf.bufnum, \xybNumFrames, xybuf.numFrames, \paramsbuf, paramsbuf.bufnum, \paramsbNumFrames, paramsbuf.numFrames, \predicting, 0]);
	}.fork;
};
)

it give me this error:

-> localhost
ERROR: Operator '||' applied to a UGen is not supported in scsynth

PROTECTED CALL STACK:
	BasicOpUGen:operator_	0x614de28c0ac0
		arg this = a BinaryOpUGen
		arg op = ||
	BinaryOpUGen:init	0x614de28c5740
		arg this = a BinaryOpUGen
		arg theOperator = ||
		arg a = a BinaryOpUGen
		arg b = true
	Meta_FluidBufToKr:kr	0x614de35ba500
		arg this = FluidBufToKr
		arg buffer = an OutputProxy
		arg startFrame = 0
		arg numFrames = an OutputProxy
	a FunctionDef	0x614de54c3658
		sourceCode = "<an open Function>"
		arg xybuf = an OutputProxy
		arg xybNumFrames = an OutputProxy
		arg paramsbuf = an OutputProxy
		arg paramsbNumFrames = an OutputProxy
		arg predicting = an OutputProxy
		var values = nil
		var xy = nil
		var trig = nil
	SynthDef:buildUgenGraph	0x614de40ac040
		arg this = SynthDef:regressor
		arg func = a Function
		arg rates = nil
		arg prependArgs = [  ]
		var result = nil
		var saveControlNames = nil
	a FunctionDef	0x614de40aa5c0
		sourceCode = "<an open Function>"
	Function:prTry	0x614de23dd000
		arg this = a Function
		var result = nil
		var thread = a Routine
		var next = nil
		var wasInProtectedFunc = false
	
CALL STACK:
	Exception:reportError
		arg this = <instance of Error>
	Nil:handleError
		arg this = nil
		arg error = <instance of Error>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of Error>
	Thread:handleError
		arg this = <instance of Routine>
		arg error = <instance of Error>
	Object:throw
		arg this = <instance of Error>
	Function:protect
		arg this = <instance of Function>
		arg handler = <instance of Function>
		var result = <instance of Error>
	SynthDef:build
		arg this = <instance of SynthDef>
		arg ugenGraphFunc = <instance of Function>
		arg rates = nil
		arg prependArgs = nil
	< FunctionDef in closed FunctionDef >  (no arguments or variables)
	Routine:prStart
		arg this = <instance of Routine>
		arg inval = 15205.742349183
^^ The preceding error dump is for ERROR: Operator '||' applied to a UGen is not supported in scsynth

you can’t pass the numFrames in as an argument to the synthdef. the numFrames in this case needs to be known when the synthdef is compiled (when .add is called).

(
s.waitForBoot{
	var xydata = FluidDataSet(s);
	var paramsdata = FluidDataSet(s);
	var xybuf = Buffer.alloc(s, 2);
	var paramsbuf = Buffer.alloc(s, 10);
	
	var mlp = FluidMLPRegressor(s,
		[7],
		activation: FluidMLPRegressor.sigmoid,
		outputActivation: FluidMLPRegressor.sigmoid,
		maxIter: 1000,
		learnRate: 0.1,
		batchSize: 1,
		validation: 0
	);
	
	s.sync;
	
	SynthDef(\regressor, { arg predicting = 0;
		var values, xy, trig;
		
		xy = FluidBufToKr.kr(xybuf, numFrames: xybuf.numFrames);
		trig = Mix(Changed.kr(xy)) * predicting;
		mlp.kr(trig, xybuf, paramsbuf);
		values = FluidBufToKr.kr(paramsbuf, numFrames: paramsbuf.numFrames);
		
		/*...*/
	}).add;
	
	s.sync;
	
	Synth(\regressor, [\xybuf, xybuf.bufnum, \xybNumFrames, xybuf.numFrames, \paramsbuf, paramsbuf.bufnum, \paramsbNumFrames, paramsbuf.numFrames, \predicting, 0]);
};
)

Thank you for your answer.
If I understand what you said by “the numFrames in this case needs to be known when the synthdef is compiled”, I can’t pass a Buffer as argument to feed the FluidBufToKr UGen.

In your code example, the xybuf and paramsbuf present in the synth graph are referring to the variables declared at the begin of the routine not to the arguments of the graph.
Your example is equivalent to the first block of code (the one without error) in my first post.
In this case you pass an instance of Buffer not a bufnum and correct me if I’m wrong, you don’t need to specify the numFrames argument in this case.
So if I understand correctly, the answer to my question:
“I 'd like to pass a buffer as argument to a SynthDef for feeding a FluidBufToKr UGen” is no you can’t ?

What he said was that the number of output frames must be known at the time of compiling the SynthDef.

What you’re trying to do is, compile a SynthDef where the number of output frames is not known, and supply that number when running the synth.

So no, you cannot do it in the way that you want.

hjh

Thanks James, that is true.

This (^) is possible:

// fill a 1-channel buffer with 7 numbers
~buf1 = Buffer.loadCollection(s,{exprand(100,4000)} ! 7);

// in a synth, read those numbers out of the buffer and get them as a control stream
(
~synth = {
    arg buf;
    var freqs = FluidBufToKr.kr(buf,numFrames:7);
	freqs.poll;
	nil;
}.play(args:[\buf,~buf1]);
)

// then you can change what's in the buffer and it will get read out by the synth
~buf1.setn(0,{exprand(100,4000)} ! 7);

// make a new buffer and tell the synth to use that one

~buf2 = Buffer.loadCollection(s,{rrand(0.0,1.0)} ! 7);

~synth.set(\buf,~buf2);
1 Like

Ok it’s clearer for me now, thank you.

1 Like

Flucoma is amazing, thank you for that too

1 Like