Actual polyphony inside a SynthDef?

Hi!

I apologize in advance if the question turns out to be silly, I’m quite new to SC and there’s a lot of things I still don’t understand properly…
Anyway, that’s my problem.

Let’s say I have a SynthDef named “hello”, generating a simple sine with random freq and random pan with a fixed envelope of 1 second and a doneAction: 2.
So, every time I recall “hello” with .play method I hear a random freq sine, randomly panned.
Perfect.

Now, what I need to do is to take “hello” and somehow put it in another SynthDef, named, for instance, “control_hello”.
I want “control_hello” to take two arguments: env_time and density.
In this way, every time I recall “control_hello” I can pass an env_time for all the “hello” instances generated, and (most important) specify how many "hello"s I need in terms of density over time.
The final line of code should be something like:

Synth.new(\control_hello, [\env_time, 3, \density, 100]);

In other words, I need a SynthDef to trigger another SynthDef (even better if I can fit all inside a single SynthDef, but not strictly necessary).

I have already tried the Mix.fill method, but that seems to need a fixed number of channels already declared (not a variable).

Any idea or examples to hack?
I hope I was clear, and sorry if there’s no code to start with, everything is still in my head since I don’t know how to formalize it.

Thank you so much!
Best,
Ardan.

Hi Ardan,

I think of the server as a brute, that does what it’s told. Your hello control thing sound to me like something the client should be doing.

For instance, you could define a function that executes all the logic and creates the hello synths, and/or knows about the synths already created and sends them updated parameters (you were a bit vague about this, or possibly i didn’t read closely enough)

Of course, just my opinion! There are people who like to do more in the server … i find it much more natural to do control stuff in sclang.

Cheers,
eddi

I agree – based on @ortensie’s description, this kind of polyphonic note-playing most likely belongs outside of a SynthDef. A SynthDef is just a recipe to make a sound. Then you play individual notes (“notes” here in an expanded sense) by calling Synth.new. There are different ways to do this. You could for example use a construct such as 100.do({ Synth.new(\hello, [ \env_time, 3 ]) }), which would create one hundred synth nodes from the same \hello recipe. If you want to be able to stop some of the synth nodes individually (rather than Ctrl + period to kill all at once), you may want to use .collect instead of .do and save the resulting Array into a variable, like

x = 100.collect({ Synth.new(\hello, [ \env_time, 3 ]) });
// then you can access individual notes like this:
x[0].free;
x[34].set(\amp, 0.4); // assuming your SynthDef has an amp argument, etc.

An even more readable way to get the same Array of synth nodes is to do Array.fill(100, { Synth.new(\hello, [ \env_time, 3 ]) }); which gives you the same result as .collect.

An entirely different approach would be to use Patterns to play your SynthDef, but based on the information you provided it I think the examples above are more straightforward.

Note: the actual sound to be made by a SynthDef recipe, of course, can be made up of anything from a single sine to any complex spectrum or combination of sounds. You could build a single SynthDef that does additive synthesis and accepts your density argument to specify how many layers of, say, a sine wave should be mixed together. But then you run into the problem you identified, which is a SynthDef cannot its fixed number of channels after being created. There are ways to work around this fixed nature of a SynthDef to get the desired behavior, but the approach outside of the SynthDef is a cleaner choice here.

Bruno