How to scramble a channels array on the server?

Hey there,

I recently came across a similar problem (but I needed the scramble to be deterministic). Here’s what I came up with:

(
var permute = {|array, permutation=0|
	var size = array.size;
	var selectIndices, res;
	var func = {|coll, size|  (size+1).collect{|i| (coll ++ size).rotate(i)  } };
	var factorial = size.asFloat.factorial;
	var divs = (2..size-1).collect{|layer| (layer..size).product.div(layer) } ++ [ 1 ];
	var indexes2 = (2..size).collect{|layer,index| permutation.div(divs[index]).trunc.mod(layer)};
	selectIndices = [[0]];
	(size-1).do{|layer| selectIndices = Select.ar(indexes2[layer], K2A.ar( func.(selectIndices, layer+1))).flatten };
	Select.ar(selectIndices, array);
};

var scramble = {|array, in|
	permute.(array, Hasher.ar(in).range(0, array.size.factorial));
};

SynthDef(\permute, {
	var phasor = Phasor.ar(0, SampleDur.ir*0.5, 0, 1);
	var sequence = (0..7) * 150; 
	// permute array
	sequence = permute.(K2A.ar(sequence), \permute.ar(0));
	sequence = Select.ar(phasor.linlin(0,1, 0, sequence.size).trunc, K2A.ar(300 + sequence));
	Out.ar(0,0.2 * SinOsc.ar(sequence));
	// Changed.ar(phasor.trunc(1/5), 0)
}).add;

SynthDef(\scramble, {
	var phasor = Phasor.ar(0, SampleDur.ir*0.5, 0, 1);
	var sequence = (0..7) * 150; 
	// permute array
	sequence = scramble.(K2A.ar(sequence), \scramble.ar(0));
	sequence = Select.ar(phasor.linlin(0,1, 0, sequence.size).trunc, K2A.ar(300 + sequence));
	Out.ar(0,0.2 * SinOsc.ar(sequence));
	// Changed.ar(phasor.trunc(1/5), 0)
}).add;

SynthDef(\multichanscramble, { 
	var pitches = (1..8) * 100; 
	pitches = scramble.(K2A.ar(pitches), \scramble.ar);
	Out.ar(0, Splay.ar(SinOsc.ar(pitches, Array.series(8, 0.125, 0.125) )) * 0.2);
}).add;
)

// permutations: range is 0..array.size.factorial
x = Synth(\permute)
x.set(\permute, 0)
x.set(\permute, 12)
x.set(\permute, 14)
x.set(\permute, 23)
x.set(\permute, 4)
x.set(\permute, 7.factorial.rand)
x.free

x = Synth(\scramble)
x.set(\scramble, 0)
x.set(\scramble, 1)
x.set(\scramble, 2)
x.set(\scramble, 3)
x.set(\scramble, 4)
x.set(\scramble, 5)
x.set(\scramble, 7.factorial.rand.postln)

x = Synth(\multichanscramble)
x.set(\scramble, 0)
x.set(\scramble, 1)
x.set(\scramble, 2)
x.set(\scramble, 3)
x.set(\scramble, 4)
x.set(\scramble, 5)
x.set(\scramble, 8.factorial.rand.postln

I’m by no means experienced in this field, but it seems like this is a robust way to get all the permutations:

(
s.options.numWireBufs = 64 * 64;
s.options.sampleRate_(48000);
s.options.blockSize_(8);
s.reboot
)
(
var size = 5;
var synth = Synth.basicNew(\permute, s, s.nextNodeID).register;
SynthDef(\permute, {
	var arr = [[0]], res;
	var func = {|coll, size|  (size+1).collect{|i| (coll ++ size).rotate(i)  } };
	var factorial = size.asFloat.factorial;
	var perm = Phasor.ar(0, 1/BlockSize.ir, 0, factorial);
	var divs = (2..size-1).collect{|layer| (layer..size).product.div(layer) } ++ [ 1 ];
	var indexes = (2..size).collect{|layer,index| perm.div(divs[index]).trunc.mod(layer)};
	arr = [[0]];
	(size-1).do{|layer| arr = Select.ar(indexes[layer], K2A.ar( func.(arr, layer+1))).flatten };
	SendReply.ar(Changed.ar(perm.trunc) + Impulse.ar(0), "/proof", arr);
	FreeSelf.kr(DelayN.ar(Trig.kr( Slope.ar(perm).abs > 10000), 1, 1));
}).store(completionMsg: synth.newMsg );
p = Set();
synth.onFree({ "set size: %, factorial: %, test outut is %".format(p.size, size.asFloat.factorial, p.size == size.asFloat.factorial).postln});
OSCdef(\proof, {|msg| p.add(msg[3..].collect(_.asInteger))}, "/proof");
)

On my machine, I can run this with arrays up to a size of about 20 or so. It’s surprisingly easy on the CPU, but of course a bit intense memory-wise.

All best,
moritz