Dictionary as SynthDef input arg?

Another silly question:

Is it possible to pass a dictionary (or array or list) into a SynthDef as an argument?

I’m thinking here of a dictionary of different parameters and their values, rather than an array of different values for the same parameter.

Like this you can pass a dictionary to a SynthDef, but the values will be spread over the different arguments. I don’t know if you can pass a dict as a single argument, and I wouldn’t know how to use it within a SynthDef… so maybe you can achieve what you want with something like the following?

(
SynthDef(\test){|freq,dur,amp,out|
   // ... bla bla bla ...
   // let's poll all arguments just to check if it works
   [freq,dur,amp,out].poll
}.add;
)
// define our parameter dict (technically an Event)
o = (freq: 440, dur: 1, amp: 0.1, out: 0);
// send the dict at synth creation time
x = Synth(\test, o.asPairs)

// or use it after creation with .set
o = (freq: 840, dur: 2, amp: 1, out: 3);
x.set(*o.asPairs)

asPairs transforms a dictionary into an array of key-value pairs: e.g. (a:1, b:2).asPairs results in [\a,1,\b,2]

the * operator I’m using in x.set is a syntax shortcut to pass separate arguments as an array: e.g. x.set(*[1,2,3,4]) is equivalent to x.set(1,2,3,4)

3 Likes

Thanks very much for the quick and detailed reply, @elgiano!

I will try that with my setup.

hello I have a kind of a similar question, but wanting to change on the fly a wave collected previously such as:

(
b= Buffer.allocConsecutive(10 ,s,2048,1,{
	|buf,idx|
	var i;
	i = idx;
	("wave folder "++ ~myPath.entries[idx].fileName).postln;
	buf.readMsg("wave folder" ++ ~myPath.entries[idx].fileName);
});
)

(
SynthDef(\test.....

sig = GrainBuf.ar(sndbuf:  b ...??? )
}).add;
)

x=Synth(\test);
x.set(\  //i want to call the wave number 5);

I tried with NamedControl without finding the appropriate syntax

Thanks!

You cant use a control as an index into an array (an argument to a SynthDef is always converted to a Control), but you can implement the same functionality using Select.

Try GrainBuf.ar( Select.kr(wavenum, b), ... )
And then you should be able to do
x.set(\wavenum,5)

I think it’s not actually necessary to hardcode the array into the SynthDef using Select.

Using allocConsecutive saves a lot of trouble because it guarantees that the buffer numbers are n, n+1, n+2 … n+(size-1). So you can do:

SynthDef(\test, { |firstbuf, bufindex|
   ...
   GrainBuf.ar(sndbuf: firstbuf + bufindex, ...)
}).add;

That works only if you used allocConsecutive.

The advantage of this way is that you can also use a server-side modulator on the buffer number, e.g., to choose a random buffer per grain:

SynthDef(\test, { |firstbuf, numbufs|
    var trig = Impulse.ar(...);  // or Dust, or other trigger source
    var bufindex = TRand.ar(0, numbufs - 0.9999);
   ...
   GrainBuf.ar(sndbuf: firstbuf + bufindex, ...)
}).add;

hjh

1 Like

Oh, and for a dictionary supplying argument values, if it’s an Event = (name: value, name: value) syntax, you can do:

myEvent.use {
    SynthDescLib.at(\test).msgFunc.valueEnvir
}

This is the way events do it when you play them. It will collect only the keys/values that exist as synth controls (and ignore the others).

hjh

2 Likes

Thanks, that’s clear.

I have also this problem: the wavefolder contains 400 wav files and each of this wave has 4096 sample frames of lenght. (and I need them x 2: one for the grainbuf, the other for the envbuf). My goal, like we saw it’s to be able to call any of thoses waves on the fly, using x.set.
The problem using the allocConsecutive technique is that I get - of course - the No block of 400 consecutive buffer numbers is available. What should I do?
Thanks

Check out ServerOptions.numBuffers for the maximum number of buffers you can allocate.
It is 1024 by default, but you can change it with s.options.numBuffers = 2048 (or any other number you want). You need to reboot the server for this to take effect.

It shouldn’t be needed though if you are allocating only 400 or 800 buffers. So maybe also check if you aren’t running the allocation multiple times by mistake :slight_smile:

I wanted to achieve the same but I also want to pass the buffer list as argument, which is loaded with a bunch of audio files.

a = ... // a list of buffers with audio files loaded into them
b = ... // another list of buffers with audio files in them

// a and b may be of different size

SynthDef(\test, {
	var buf = \buf.kr(0!32);
	var n = \n.kr(0);
	var sig = PlayBuf.ar(2, Select.kr(n, buf), doneAction:2);	
	Out.ar(0, sig)
}).add;

Pdef(\a, Pbind(\instrument, \test, \buf, a, \n, 0)).play
Pdef(\a, Pbind(\instrument, \test, \buf, b, \n, Pseq([0,2],inf)))

I’ve tried both the Select and allocConsecutive methods but neither works.
Any ideas on how to make this work?

Normal behavior of events WRT arrays is to “multi-synth expand” so that you get one separate synth for every array value.

But you want one synth receiving multiple array values.

The way to do that is to wrap the array in another array layer: \buf, [a]. Then the array processed by the event has only one element (an array), and the whole subarray gets passed to the synth.

hjh

Thanks! That should work.