Creating and modifying masses of Synthdefs

Hello,

I have a project where I have a central clock with a variable time, which I want to control a ‘swarm’ of Synthdefs. I am slightly struggling with the architecture for this. First one has to mass produce the Synthdefs and then mass modify them. The former can be done with ‘do’ and can’t quite visualise how the latter would work.

Are there any working examples of how to do this?

Thanks,

Dom

If you store the synths in an array, you have a pointer to each of them and can modify them each individually:

a = 10.collect{|i| {|freq = 100| SinOsc.ar(freq*i, 0, 0.1)}.play}

a.do{|item| item.set(\freq, 1000.rand)};

Sam

1 Like

Synthdefs or synths? It’s unusual to be editing an existing synthdef …technically possible though…

1 Like

Hi Jordan,

Sorry, I was not clear, synths, not Synthdefs. And when I say modify them. I mean to be able to set specific parameters for specific instruments.

Sam, thanks for your reply. Let me take a proper look and have a think over lunch. It’s not how I envisioned doing things, but it’s very elegant and could possibly work.

Thank you both!

Another typical way to do it is the usage of Groups. Put all Synths into one Group and then set.

https://doc.sccode.org/Classes/Group.html#examples

2 Likes

Very helpful dkmayer, thank you. Between these replies I think I have a way forward!

One thing with groups though is that if you make a node after setting a value, the new node won’t lookup the set value.

g = Group();

v = 10.collect{ Synth.tail(g, \synth) };

g.set(\foo, 10); // all vs have \foo set to 10

Synth.tail(g, \synth);   // this synth won't have \foo set to 10.

I’ve found this to be annoying enough to avoid using Group-set.

1 Like

Hi Sam,

I’ve modified your code to this:

a = 10.collect{|i| {|freq = 100| Synth(\sine, [\freq, 200*i])}}

a.do{|item| item.set(\freq, 1000.rand)};

This post window shows me this…

[ a Function, a Function, a Function, a Function, a Function, a Function, a Function, a Function, a Function, a Function ]

If you or anyone else could englighten me to what I’m getting wrong I’d be grateful.

You don’t need the inner function, so do it like this:

a = 10.collect{|i| Synth(\sine, [\freq, 200 * (i + 1) ]) }

We don’t want to specify a freq of 0, so add 1 to ‘i’ to get the frequencies (200, 400…2000). Now you can iterate over ‘a’ to e.g. set gate to 0 (presuming the synthdef has an argument named ‘gate’ and an envelope which is triggered by ‘gate’):

a.do{|n| n.set(\gate, 0) }

Typically, if the synthdef is just a sine wave and you want to build a spectrally rich note by specifying the partials (like it seem is the intention here), you would also scale the amplitudes of each partial. A simple way of doing this is:

a = 10.collect{|i| Synth(\sine, [\freq, 200 * (i + 1), \amp, 1/(i + 1) ]) }

Again, I presume the sine synthdef has an ‘amp’ argument which controls the amplitude.

1 Like

Hi Thor,

Thanks so much for your thorough reply. Schoolboy error by me, so thanks for the clarification. Also yes to the gate and amp - they are important too.

Thanks for taking the time to help me out. The whole way of working is becoming much clearer.

Slight confusion here.

This works

a.do{|n| n.set(\gate, 0) }

This does not…

a.do{|n| n.set(\gate, 0, \freq, 220 * n) }

I get this error…

ERROR: binary operator ‘*’ failed.

It seems that logic does not work with do - or have I got that wrong?

If ‘a’ holds all the synths, then ‘n’ is the synth. Add a second arg to a.do to get the iteration count:

a.do{|n, i| n.set(\gate, 0, \freq, 220 * (i + 1)) };

Normally you would not set gate = 0 AND the freq arg at the same time, but only set the freq arg when gate = 1.

1 Like

Fantastic Thor, thank you.

Yes, it makes sense now. My confusion was due to this bit of code.

a.do

As this gives the size of the array I thought the same would apply inside the function. Thanks for clarifying!

a.do

As this gives the size of the array I thought the same would apply inside the function. Thanks for clarifying!

Just to clarify, a.do iterates over the array where the first arg is an element from the array, in this case a synth but could be anything almost, and the second arg is the iteration counter. If you want to know the size of the array you do a.size.

1 Like

That is a very useful clarification Thor, thank you. So it simply keeps iterating through the array until it is finished rather than calculating the size of the array and iterating that many times.

The do-method calls the .size method internally so it knows how many iterations to do. You can look up the implementation by hitting command + i (in OSX) and selecting ArrayedCollection.do from the list.

1 Like

Thanks for the additional clarification Thor!