Dictionary keys as SynthDef arguments?

Hi everyone!

I have a pretty noob issue that I can’t solve.

I need to access a dictionary value inside a SynthDef by passing a key as an argument.
Here is a dummy example:

(SynthDef.new("ex", { |vow = 0|
	
	var dict, vowel, freq;

	dict = Dictionary[0 -> \a, 
	               1 -> \e,
	               2 -> \i, 
	               3 -> \o, 
	               4 -> \u];
	
	vowel = Vowel(dict.at(vow), \bass);

	freq = vowel.freqs;
	freq.postln;
}).add)

Reading around a bit, it seems the problem is related to arguments being converted to .kr values. Besides the fact that I don’t know how to convert them to usable values for this specific task, it is obviously not clear to me how the input arguments work. I was wondering if anyone could briefly explain to me where and why I’m wrong in this example…
Thanks a lot!

SynthDef inputs may only be floats. There’s no exception to this rule.

Dictionary-at is a language-side operation, so the server can’t perform it.

So on both counts, it has to be done a different way.

One way is to flatten the data into an array and access the data by index. If it’s a small array, you could hard code the array into the SynthDef; otherwise load it into a Buffer.

hjh

Hi @jamshark70! Thanks for your reply.

I’ve followed your suggestion of hard-coding the array into the SynthDef, but I got the same problem. It works when I access the index directly, as in:

array = Array.newFrom(Set[\a, \e, \i, \o, \u]);

vowel = Vowel(array[0], \alto);
freq = vowel.freqs;

…but not when I try to pass as it a SynthDef argument (vow, in this example):

array = Array.newFrom(Set[\a, \e, \i, \o, \u]);

vowel = Vowel(array[vow], \alto);
freq = vowel.freqs;

…which is actually what I need to do.
I suppose I’m missing something silly but I didn’t find any resource that could help me in solving this…

Not quite. I had suggested to get the data into an array, but your code snippet gets the keys into an array.

Again – the server does not know what to do with symbols. So an array of symbols is useless in the server.

at (= array[something]) is a language-side operation. This means that it needs to know, right now, exactly which index to look up.

A SynthDef argument is not a specific value. It’s an object that represents a place where a future value will be filled in.

So SynthDef arguments will always be incompatible with array[something].

In the server, if you want to index based on a synth argument, you can use Select.kr with a flat array of numbers (only numbers) that’s embedded into the SynthDef, or you can use Index.kr with a buffer. Other approaches are not going to work.

This means you have to manipulate the data into a format that can be embedded into a SynthDef, or loaded into a buffer. Fortunately, that’s the same format: a flat array (no sub-arrays).

Vowel(\a) gives you an object with properties freqs, widths and dBs. This is not an array, but you can make one:

(
f = { |vowel = \a, register = \alto|
	var v = Vowel(vowel, register);
	[v.freqs, v.widths, v.dBs]
};
)

f.(\a);
-> [ [ 800, 1150, 2800, 3500, 4950 ], [ 80, 90, 120, 130, 140 ], [ 0, -4, -20, -36, -60 ] ]

Note that there are 15 numbers for one vowel. That’s important later.

This is not a flat array – it has sub-arrays – but .flat helps with that.

Again, you can’t use Vowel directly in a SynthDef with changeable indexing. The help file examples work because the key is hardcoded (never changes). But you can collect all the vowels you need in advance, and pack them into one array.

(
f = { |vowel = \a, register = \alto|
	var v = Vowel(vowel, register);
	[v.freqs, v.widths, v.dBs]
};
)

a = [\a, \e, \i, \o, \u].collect { |vowel|
	f.value(vowel)
};

a = a.flat;
-> [ 800, 1150, 2800, 3500, 4950, 80, 90, 120, 130, 140, 0, -4, -20, -36, -60, 400, 1600, 2700, 3300, 4950, 60, 80, 120, 150, 200, 0, -24, -30, -35, -60, 350, 1700, 2700, 3700, 4950, 50, 100, 120, 150, 200, 0, -20, -30, -36, -60, 450, 800, 2830, 3500, 4950, 70, 80, 100, 130, 135, 0, -9, -16, -28, -55, 325, 700, 2530, 3500, 4950, 50, 60, 170, 180, 200, 0, -12, -30, -40, -64 ]

This is a flat array: first 15 numbers (index 0-14) are for \a, next 15 (index 15-29) for \e, etc.

If vow is your index number (0, 1, 2, 3 or 4), then you can get:

// assuming `vowelArray` is the array shown above
var baseIndex = vow * 15;
var freqs = Select.kr(baseIndex + (0..4), vowelArray);
var widths = Select.kr(baseIndex + (5..9), vowelArray);
var dBs = Select.kr(baseIndex + (10..14), vowelArray);

hjh

1 Like