Figuring out Arrays

~array1 = Array.fill(4, {Saw.ar(440, 0.2)});
~array1[0];
~array1[1];
~array1[2];
~array1[3];

{~array1[0]}.play;

{Saw.ar(440, 0.2)}.play;

How come I can’t hear the:

{~array1[0]}.play;

???

I see it on the server, but it’s complete silence

It’s not an array problem.

UGen objects must be created within the synthesis function. This is because their correct operation depends on the input and output connections to other units, and those are set when you create the object. They aren’t updated at any other time.

When you create the 4 Saw units outside of a synthesis function, you have the Saw units but no connections. So, no sound.

hjh

Ok, that makes sense. I find that when I write my code for an elaborate synth, the code itself is quite repetitive. I think to be a good programmer, you can do something elaborate with as minimal code as possible. I’m trying to figure out how to not be so repetitive when I write my code. For example, how could I create 4 oscillators with an array and be able to play them? Also, would it be possible to index those oscillators so I could have access and play each one individually?

They have to be in the synth, like this:

SynthDef(\demo, { |out, gate = 1, freq = 440, amp = 0.1, ffreq = 2000, rq = 1, detun = 1.008|
	var oscAndFilter = { |oscfreq, filtfreq, filtrq|
		RLPF.ar(Saw.ar(oscfreq), filtfreq, filtrq)
	};
	var pairs = Array.fill(4, { |i|
		oscAndFilter.value(freq * (detun ** Rand(-1.0, 1.0)), ffreq, rq)
	});
	... more stuff here...
	... pairs[0] is the first Saw -> RLPF, pairs[1] is the second etc. ...
	Out.ar(out, something);
}).add;

Or the constructor could be outside the synth, as a function:

~oscAndFilter = { |oscfreq, filtfreq, filtrq|
	RLPF.ar(Saw.ar(oscfreq), filtfreq, filtrq)
};

SynthDef(\demo, { |out, gate = 1, freq = 440, amp = 0.1, ffreq = 2000, rq = 1, detun = 1.008|
	var pairs = Array.fill(4, { |i|
		~oscAndFilter.value(freq * (detun ** Rand(-1.0, 1.0)), ffreq, rq)
	});
	... more stuff here...
	Out.ar(out, something);
}).add;

You can’t have the Saw units living outside the synth.

hjh

Thank you, this is helpful! I have a couple of questions though.

How does the ‘filtfreq’ and ‘filtrq’ work when you don’t plug in any values into it?

Is there a specific helpfile for how you used ‘.value’? i wouldn’t of thought to do that

What does ** mean?

Why is there an additional ‘ffreq’ and ‘rq’ argument? Didn’t you already make the ‘filtfreq’ and ‘filtrq’ argument?

Context is: You had asked how to reduce repetition in SynthDef code. There aren’t that many ways. One way is to make a library of functions that create UGen objects. You pass in all the parameters that the UGens need, and get a graph of units out.

It’s a function, not an array of units. So it can be defined anywhere. You call it in the context of SynthDef building, and any units created by the function are created in the right context, and it all works.

I didn’t put default values in the function’s argument list, but you could easily do that.

Function help. This is how you call a function in SC.

It’s exponentiation.

I went back and forth for years on the best way to do randomized detuning. Eventually I settled on this formula. The argument is the maximum detuning ratio. Raising this to the power of 1 gives you the maximum upward detuning – freq * detun. Raising it to the power of -1 gives you the inverse ratio, equivalent to freq / detun. Raising it to the power of a random number between -1 and 1 detunes by a random interval above or below the given frequency (at most the given detuning factor).

It was just an example where you might want parallel UGen chains.

There are arguments to the SynthDef, and arguments to the UGen-creator function. These aren’t the same. If I had named them the same, you might have imagined that they would magically share values – they don’t. (The second example is clearer about this than the first.)

hjh

Thank you, this is very helpful!