Creating multiple instances of a Synth using Dictionaries?

Hey all,

I am trying to create multiple instances of a SynthDef at once. To do this, I am using Dictionaries.

This is my SynthDef below. I am using it to access a Buffer that I have saved locally.

SynthDef(\mainbuf, {
	arg atk = 0.01, rel = 0.01, sust = 1, rate = 1, patch = 22, amp = 1;
	var sig, buffer;
	buffer = \buffer.kr(0);
	sig = PlayBuf.ar(1, buffer, BufRateScale.kr(buffer) * rate, * BufFrames.ir(buffer));
	// Added Impulse here to make sure the gate trigger is closed first, then opens to prevent zombie synths from spawning
	sig = sig * Env.asr(atk, sust, rel).ar(Done.freeSelf, \gate.kr(1) + Impulse.kr(0));
	sig = Out.ar(patch, sig * amp);
}).add;

This is a Tdef I am using with Dictionaries below. The problem I am running into is that the keys in the dictionary have to be unique, so I can’t reference the same SynthDef multiple times. Ideally, I am trying to get these two arrays to play in sync, each being it’s own Synth instance. Additionally, I would like to add Dictionaries to also control parameters for atk, rel, rate, bank:

(
Tdef(\test,
	Routine {
		var bpm, beat, tatum;
		var bufAmp;
		
		bpm = 170;
		beat = 60 / bpm;
		tatum = beat / 4;
		
		bufAmp = Dictionary [
			\mainbuf -> [1, 1, 1, 0],
			\mainbuf -> [0, 0, 0, 1],
		];
		loop {
			16.do { |i|
				bufAmp.keysValueDo { |synthDef, ampValues|
					s.makeBundle(s.latency, {
						synth = Synth(synthDef, [
							patch: ~b1,
							amp: ampValues[i % ampValues.size],  // Apply amp value from dictionary based on current loop index
							//atk:
							//rel:
							//rate:
							//bank:
						], ~sources);
					});
					s.makeBundle(s.latency, {
						synth.set(\gate, 0);
					});
					tatum.wait;
				};
			};
		};
	};
).play(quant: 4);
)

When I was testing this earlier, I was able to get this to work if I used multiple SynthDefs (i.e mainbuf1, mainbuf2. This made it so the keys are unique and I was able to trigger both, but I am trying to keep the code clean and just use the one SynthDef that I am needing.

Thank you

You’ve got some of your structures mixed up. Since all the keys in bufAmp are the same, this is an array. Accessing the synths through some key-value structure is a good idea, but since there names don’t mean anything, you might as well use an array for everything.

(some bits missing for brevity).

var buf_amp_list = [
	[1, 1, 1, 0],
	[0, 0, 0, 1]
];

var synth_array = buf_amp_list.collect({
	|amps, index|
	Synth(\def_name, [amp: amps.wrapAt(loop_index)])
})

Now the synths are accessed: synth_array[0],
Also, note .wrapAt

Now if you wanted to add more arguments specified as array things get a little more complex, personally, I’d consider this instead:

~synth_arg_funcs = {|i| [
	[patch: 0, amp: [1,1,1,0].wrapAt(i), atk: 3.0.rand],
	[patch: 0, amp: [0,0,1,0].wrapAt(i), atk: 1.0.rand]
] };

~synth_arg_funcs.(loop_index).collect({|args|
	Synth(\def_name, args: args.asKeyValuePairs );
});

That is a function that returns an array of arguments for each index.

Although very quickly it becomes easier to use patterns, which is what you should probably use for this.

1 Like

Thank you! This works perfectly. Also thank you for the recommended approach for more complex arguments. This is great

edit:

Does this look set up correctly for the second approach?

(
Tdef(\test24,
	Routine {
		var bpm, beat, tatum;
		var bufAmp, bufBank, bufRate, bufRel, bufAtk;
		var loop_index = 0;  // Initialize the loop index variable

		bpm = 170;
		beat = 60 / bpm;
		tatum = beat / 4;

		~synth_arg_funcs = {|i| [
			[patch: 0, amp: [1,1,1,0].wrapAt(i), atk: 3.0.rand],
			[patch: 0, amp: [0,0,1,0].wrapAt(i), atk: 1.0.rand]
		] };

		loop {
			16.do { |i|
				~synth_arg_funcs.(i).collect({|args|
					Synth(\mainbuf, args: args.asKeyValuePairs);
				});
				tatum.wait;
			};
		};
	};
).play(quant: 4);
)

I am getting the following error when I try to run:

^^ ERROR: Message 'asKeyValuePairs' not understood.
RECEIVER: [ patch, 0, amp, 1, atk, 0.12473559379578 ]

I changed asKeyValuePairs to asPairs and it is running. Should this be the same?

Oops, my mistake. If you just delete the asKeyValuePairs it should work

1 Like

Got it! Thank you again.

Also you might want to assign the results of the …

~synth_arg_funcs.(i).collect({|args|

…to a variable, or you won’t be able to free them later. If you don’t need to free them, then use .do.