One Pbind controlling multiple SynthDefs, Routines etc

Hi,

I want this Pbind to not only send pitch information to the SynthDef, but also to the function below. How is it possible to achieve this?

(SynthDef.new(\norg,{ arg gate = 1, freq = 100, release = 1;
	var snd, env;
	env = EnvGen.ar(Env.perc(0.01,release,1,-4.rand),gate,doneAction: 2);
	snd = SinOsc.ar([Array.geom(8,freq,1.5)],0,0.1);   
	Out.ar(0, snd*env);
}).add)
	
({
	var snd;
	snd = SinOsc.ar(freq,0,0.1);
}.play);

Pbind(\instrument,\norg,
	\scale, 	Scale.minor,
	\degree, 	Pseq((-2..-20),inf),
	\release, 	Pwhite(1.8, 2.3,inf),
	\dur,   	Pseq([1,Rest(1),1,Rest(1),1,1,Rest(1),1,Rest(1)],2),							
).play;

Any help would be appreciated.

Two things about the synth (and a few more about the pattern):

  1. In order to control something, you have to have access to the object. (If you have no access to the object, then you can’t send messages to it and there is no possibility of controlling it at all.) When you do { ... }.play, the result of this operation is not saved anywhere. So you have no access to the object, thus no way to control it. At minimum, assign it to a variable.

  2. freq is undefined, so you won’t be able to run that { }.play anyway. Yes, there is arg ... freq in the SynthDef. But args are local to the function in which they are defined. freq there exists only inside the SynthDef function.

    To control freq inside the function, you need to have a control input for this synth. Without a control input, there is no way for the language-side pattern to transmit new values into the synth. You did the control inputs in a valid way in \norg – use the same idea in the other block.

(
~sinosc = { arg freq = 100;
	var snd;
	snd = SinOsc.ar(freq, 0, 0.1);
}.play;
)

Then… transmitting from the pattern involves several details that are… not easy to figure out from the documentation.

The finish key is a way to insert extra logic into the process of playing an event: \finish, { ... your function...} in Pbind. (In this case, the order of processing doesn’t matter, but finish runs after Pbind has put all the values in and before the event’s main action.)

The function runs “inside” the Event, so, event values are accessible by ~environmentVar syntax. My suggestion above stores the Synth node in an environment variable living in the top environment, so it isn’t accessible directly within finish. But, you can stuff the node into the event too.

Then… timing. The \norg synths use a server’s latency value to ensure correct relative timing (see the Server Timing helpfile). If you just set the freq control, it will not use the latency value so the SinOsc frequency will change early. The solution is to wrap the set in a server bind call.

Last, you’ve got Rests… so you also need an if to skip the action for Rest events.

(
Pbind(
	\instrument, \norg,
	\scale, 	Scale.minor,
	\degree, 	Pseq((2..20),inf),
	\release, 	Pwhite(1.8, 2.3,inf),
	\dur,   	Pseq([1,Rest(1),1,Rest(1),1,1,Rest(1),1,Rest(1)],2),

	// here, make the ~sinosc synth node available inside each event
	\sinosc,    ~sinosc,

	// and then this function adds the synth-set logic
	\finish,    {
		if(currentEnvironment.isRest.not) {
			~sinosc.server.bind {
				~sinosc.set(\freq, ~freq.value);
			};
		};
	}
).play;
)

hjh
2 Likes

Alternatively, write the value to a bus, and have both synths read from the bus.

Wow, amazing, thank you so much for your explanation, this really helps beginners like me a lot. I will dive deeper into it and try the code when I get home from work.

Thank you Jordan! This seems to be the kind of solution I was looking for. Coming from a modular synth background I thought: shouldn’t there be a way to plug two cables into one output (Pbind), and link them to two different destinations? Now I need to figure out, how busses work exactly, that seems fun.

This might actually be a little complicated with regard to timing… @jamshark70 knows significantly more about patterns than I do, so they might be able to offer a solution using busses.

Instead, you can have the synth being created by the Pbind writie the freq value to a bus using ReplaceOut.kr(bus, freq_value), then the other permanent synth can just read from the bus. The issue here will be making sure the synths are in the correct order, as you only want the newest synths freq value to get through, meaning it needs to use \addToTail — so make sure you are familiar with node ordering and check s.plotTree, this should be reasonably familiar if you are comfortable thinking in a modular synth style.

1 Like

I don’t think it’s any different from my earlier example – just use a variable holding the bus instead (and including bus mapping strings in synth argument lists).

hjh