Pbindef control structure and spectral features

Hey guys.

I would like to ask for help, please.
Nice to meet you everyone.
I have a question about linking control structure with ‘Pbindef’ and spectral features.

I have a Pbindef and would like to play it when a condition is true (eg: if (spectralflatness < 0.5) {Pbindef.play} {Pbindef.stop}).

here the Pbindef function

~pS = Pbindef(
	\pSaw,
	\instrument, \bpfsaw,
	\freq, f,
	\freqLag, 0.5,
	\freqLagCrv, -7,
	\amp, Pwrand([0.03, 0.15, 0.3, 0.5, 0.75], [0.15,0.15,0.20,0.20,0.30], inf),
	\cfmin, f * Prand((1,2..5), inf),
	\cfmax, f * Pxrand((10,11..50),inf),
	\rqmin, Pexprand(0.003,0.03, inf),
	\rqmax, Pexprand(0.03,0.07, inf),
	\freqLF, Pexprand(0.3,0.7, inf),
	\detune, Pexprand(0.3,0.7, inf),
	\sus, Pexprand(0.3,9.0, inf),
	\pan, Pwhite(-1.0,1.0, inf),
	\out, 0,
	\rout, ~rbus,
	\rsend, -3,
);

the spectral flatness analysis from the help browser

(
///////////// Spectral Flatness
SynthDef.new(\features, {
    var in, chain, flat, flatdb, flatdbsquish;
    in = XFade2.ar(WhiteNoise.ar, SinOsc.ar, MouseX.kr(-1,1));
    chain = FFT(LocalBuf(2048), in);

    ~specFlatness = SpecFlatness.kr(chain);
    ~specFlatness.poll(1, "Flatness: ");
	}).add;
)
x = Synth.new(\features);

I tried this:

SendTrig.kr(~specFlatness < 0.5, ~pS.play, ~pS.stop);

and this:

(
s = Routine({
	var flatness = ~specFlatness;
	// Select.kr(flatness <= 0.5, [~pS.play, ~pS.stop]);
	if(flatness < 0.5) {~pS.play} {~pS.stop};
}).play;
)

I know that conditional/boolean is not executed on these structures with SynthDef (Pbindef).
I tried using Select.kr and even Trig.kr. But I was not successful.

Does anyone can please help me?
I also sent this message to Telegram group…
But I believe here is a good path to help me out

Thank you very much,

You’re on the right track with SendTrig but there’s still some confusion about the division of labor between language and server.

Playing and stopping the pattern happens on the language side.

SendTrig happens on the server side.

The server cannot directly do things in the language, ever. There’s no exception to this.

So there are a couple of things not quite right in that statement:

First – arguments are evaluated first and then passed to the method call. So what you’ve written is:

  1. Evaluate ~specFlatness < 0.5 right now, and use this result as the first argument. (That result will be a BinaryOpUGen.)
  2. Evaluate ~pS.play right now, and use this result as the first argument.
  3. Evaluate ~pS.stop right now, and use this result as the first argument.

Certainly you didn’t want to play, and immediately cancel play, at the time of building the SynthDef. You wanted to save those as instructions to be performed later, conditionally.

Any time you want to save instructions for later, they must be written into a function, e.g. { ~pS.play }.

That comes to the second problem: SendTrig’s inputs are trigger, id, value – but you have supplied a trigger, something you wanted to do when true, and something you wanted to do when false.

SendTrig is not going to understand what to do with those. SendTrig isn’t an if, and won’t change into one based on its inputs.

The right way to do it is to use SendTrig (or, better, SendReply) to send a message to the language, and use OSCFunc/OSCdef to receive the message in the language, and it’s this message-receiver that plays or stops the pattern.

(
///////////// Spectral Flatness
SynthDef.new(\features, {
	var in, chain, flat, flatdb, flatdbsquish;
	
	// note that ~specFlatness is not useful in the language
	// It will avoid confusion to keep all your UGens local to the SynthDef
	var specFlatness, flatnessBool;
	var trig;

	in = XFade2.ar(WhiteNoise.ar, SinOsc.ar, MouseX.kr(-1,1));
	chain = FFT(LocalBuf(2048), in);
	
	specFlatness = SpecFlatness.kr(chain);
	flatnessBool = specFlatness > 0.5;
	trig = Changed.kr(flatnessBool);
	
	// by using SendReply, you can control the OSC command path
	// this is more flexible. There's not much reason to use SendTrig anymore
	SendReply.kr(trig, '/flatnessSwitch', flatnessBool);
	
	specFlatness.poll(1, "Flatness: ");
}).add;
)

(
OSCdef(\flatness, { |msg|
	if(msg[3] > 0) {
		~pS.play;
	} {
		~pS.stop;
	}
}, '/flatnessSwitch', s.addr);
)

hjh

3 Likes

Thank you so much.
:grinning:
It works like a charm and more than that, I could learn a bit more about supercollider, its server and language.
You are right and I made a mistake between laguange and server;

Moreover, there are functions like Changed, SendReply and OSCdef that I got in touch in your reply.
I am studying your suggestion code and I am very delightful

Thank you so much.

Please, my apologies for reopening this post but I would like to understand an issue when trying to advance my studies on this topic.

I am trying to implement some operators along with the acoustic features
is this syntax correct for that case?

flatnessBool = ((specFlatness > 0.25) & (specFlatness < 0.5) & (rms > 0.5) & (rms < 0.75));

I am trying to map specific specFlatness and RMS values to trig different Pbindef’s
All these parentheses were necessary for the tests because I believe these are considered set values right?

Is there anything strange/any confusion about this line?

Thank you once again
please… :pray: @jamshark70

It’s pretty much fine.

& is bitwise “and” – it will work here because all the values are either 1 or 0. You’d have to be careful with e.g. 1 & 2 which will be 0, but that can’t happen in your expression.

hjh

1 Like

Wow! I see…
Thank you so much!