Polyphonic controls, arrays and OSC

Hello everyone!
I’m a beginner SC user and I need your help on a specific task I can’t solve…
Basically, I have this simple SynthDef:

(
SynthDef.new(\test, {
	arg wfreq, wpan, wgate =0, outl = ~frontl, outr = ~frontr;
	var wsig, wenv;
	wenv = EnvGen.kr(Env.adsr(1, 0.6, 0.7, 3, curve: -2), wgate, doneAction: 2);
	wsig = SinOsc.ar(freq: wfreq, phase: 0, mul: 0.8);

	Out.ar(outl, wsig * wenv * (1-wpan).sqrt);
	Out.ar(outr, wsig * wenv * wpan.sqrt);
}).add
);

Then, I allocate 10 copies of this synth into an array:

~tests = Array.fill (10, {Synth.new(\test)});

Finally, I send a specific message from another software to a specific instance, via OSC:

(
OSCdef('w', {
	arg wmsg;
	var num = wmsg[1], freq = wmsg[2], pan = wmsg[3], gate = wmsg[4];
	[wmsg].postln;
	~tests[num].set(\wfreq, freq, \wpan, pan, \wgate, gate);
}, "/try" );
);

Until now, everything works fine. If I send, for example, a message “[ \try, 1, 400, 0.5, 1 ]”, the first instances plays correctly and I can change pan and frequency as long as I don’t send a gate 0 message.
BUT
What if I need to change one parameter (frequency, for expample) over time?
I need a way to retrigger a Line every new OSC message INSIDE a specific instance that is already playing. Or passing the message from outside, but I don’t know how…
So, to be clear, I’ll send OSC message formatted like this:
[\try, instance, initial freq, final freq, pan, gate]
For example:

  • [\try, 1, 200, 400, 0.5, 1] and the first instance start playing a glissato from 200 to 400 Hz in a fixed amount of time, AND KEEP THE LATEST VALUE until a new message is received
  • [\try, 1, 400, 500, 0.5, 1] and the same instance goes from 400 to 500 Hz…
    And so on until I send a \gate 0, freeing the instance.

    I hope I was clear… As I said before, I’m a beginner and I don’t even know if this should be the smartest way to accomplish this task…
    Thank you all for help!

Line doesn’t have a trigger argument, so it can’t restart – for that, you need EnvGen.

(
SynthDef.new(\test, {
	arg startfreq, endfreq, time = 1, t_trig = 1, wpan, wgate =0, outl = ~frontl, outr = ~frontr;
	var wsig, wenv, freq;
	wenv = EnvGen.kr(Env.adsr(1, 0.6, 0.7, 3, curve: -2), wgate, doneAction: 2);
	freq = EnvGen.kr(Env([startfreq, endfreq], [time]), t_trig);
	wsig = SinOsc.ar(freq: freq, phase: 0, mul: 0.8);

	Out.ar(outl, wsig * wenv * (1-wpan).sqrt);
	Out.ar(outr, wsig * wenv * wpan.sqrt);
}).add
);

This will not jump to startfreq on every segment (see EnvGen help for details).

Couple of other notes:

  • outl = ~frontl, outr = ~frontr in the arg list isn’t doing what you think. SynthDef arguments may have default values but they must be literal numbers or arrays, never expressions or variables (but you can use NamedControl for that if you really need it). The default values will be 0 for these, no matter the values of the environment variables at that time.

  • You don’t need to roll your own panning – see Pan2: Out.ar(out, Pan2.ar(wsig, wpan * 2 - 1, wenv)) and then you need only one Out (unless the buses are not consecutive, but I’ve never needed to do that in 18 years of SC-ing).

hjh