How to scramble a channels array on the server?

Hey everyone,
Inside a synth I’m generating a 16-channel array and playing it… i.e. something like this:

sig = Saw.ar((1..16) * 100);
Splay.ar(sig);

I would like to be able to use a trigger to scramble the channel order of sig before sending it to Splay, in the same way one can do this in the language using ArrayedCollection.scramble

Any clue how I might do this? I was looking at Demand rate UGens like Drand and Dshuf, but it looks like these will only give you one channel out of the array rather than scrambling the whole thing.

xxjc

The trick is to feed one Dshuf into multiple Demand units. This accesses all of the Dshuf values at once.

(
SynthDef(\rearrange, { |freq = 440, amp = 0.1, gate = 1, out = 0|
	var eg = EnvGen.kr(Env.adsr, gate, doneAction: 2);
	
	var n = 5;
	var initTrig = Impulse.kr(0);
	var randomizer = Dshuf((0 .. n-1), 1);
	var indices = Demand.kr(Array.fill(n, initTrig), 0, randomizer);
	
	var freqs = freq * (1..n);
	var oscs = SinOsc.ar(freqs);
	var channels = Select.ar(indices, oscs);
	
	Out.ar(out, Splay.ar(channels, level: amp) * eg)
}).add;
)

(instrument: \rearrange, sustain: 1.5).play;

hjh

1 Like

there is also TScramble:


(
SynthDef(\rearrange, { |freq = 440, amp = 0.1, gate = 1, out = 0|
	var eg = EnvGen.kr(Env.adsr, gate, doneAction: 2);
	
	var n = 5;
	var initTrig = Impulse.kr(0);
	
	var freqs = freq * (1..n);
	var oscs = SinOsc.ar(freqs);
	var channels = TScramble.ar(oscs, initTrig);
	
	Out.ar(out, Splay.ar(channels, level: amp) * eg)
}).add;
)
1 Like

Oh that’s cool… worth noting that this is in the wslib quark (not a core or sc3-plugins class).

hjh

1 Like

Hmm… I spoke too soon. The indices are only scrambled once (even with a non-0 frequency Impulse). Is it possible to scramble the indices again and again after the synth has been initialized?

Ndef(\monitorme, {
	var n = 5, amp = 0.1, freq=200, sig;
	var t_trigs = Impulse.kr(2).dup(n);
	var randomizer = Dshuf((0 .. n-1), inf);
	var indices = Demand.kr(t_trigs, 0, randomizer);
	var freqs = freq * (1..n);
	var oscs = SinOsc.ar(freqs);
	var channels = Select.ar(indices, oscs);
	sig = Splay.ar(channels, level: amp);
	indices.poll(1);
	sig;
}).play(outbus: 0);

Yes, that’s correct. Pshuf / Dshuf intentionally repeats the same ordering.

“Why? Wouldn’t you want a new ordering on each repeat?” – If it enforced a new ordering on every repeat, then it would be impossible to repeat the same ordering. So this design gives you a choice.

To get the new ordering, Pshuf / Dshuf should output one ordering only one time, and then repeat this externally. That is, there’s a difference between a Pshuf / Dshuf repeating infinitely, and infinitely repeating a one-shot Pshuf / Dshuf.

Pshuf([1, 2, 3], 3).asStream.all
-> [ 3, 2, 1, 3, 2, 1, 3, 2, 1 ]

Pn(Pshuf([1, 2, 3], 1), 3).asStream.all
-> [ 1, 3, 2, 2, 3, 1, 2, 1, 3 ]

s.boot;

(
a = {
	var trig = Impulse.kr(4);
	var source = Dshuf([1, 2, 3], 3);
	var demand = Demand.kr(trig, 0, source);
	demand.poll(trig);
	FreeSelfWhenDone.kr(demand);
	Silent.ar(1)
}.play;
)

UGen(OutputProxy): 3
UGen(OutputProxy): 2
UGen(OutputProxy): 1
UGen(OutputProxy): 3
UGen(OutputProxy): 2
UGen(OutputProxy): 1
UGen(OutputProxy): 3
UGen(OutputProxy): 2
UGen(OutputProxy): 1
UGen(OutputProxy): 1  // not sure why there's an extra

There’s no Dn() so we have to translate Pn(x, n) as Dseq([x], n).

(
a = {
	var trig = Impulse.kr(4);
	var source = Dseq([Dshuf([1, 2, 3], 1)], 3);
	var demand = Demand.kr(trig, 0, source);
	demand.poll(trig);
	FreeSelfWhenDone.kr(demand);
	Silent.ar(1)
}.play;
)

UGen(OutputProxy): 2  // 213
UGen(OutputProxy): 1
UGen(OutputProxy): 3
UGen(OutputProxy): 3  // 312 -- changed ordering
UGen(OutputProxy): 1
UGen(OutputProxy): 2
UGen(OutputProxy): 2  // 213 -- changed again
UGen(OutputProxy): 1
UGen(OutputProxy): 3
UGen(OutputProxy): 3

hjh

1 Like