Nested LocalOuts?

I’d like to create a function that has a scalable number of delay lines, depending on the number of input channels.

I came up with the following idea, but it doesn’t work. I’m wondering if this is a possible approach (using nested LocalIn/LocalOuts). Thank you in advance for any insight into this code.

	~delays = {{|sig|
				var time1, fb1,  m, chans=4;
				time1 = ~makeRangedControl.(\time1, 0.5, 0, 1.0);
				fb1 = ~makeRangedControl.(\fb1, 0.9, 0, 1.0);
				m = sig.collect{|x, index|
		        var local, a, b, c;
	            local = LocalIn.ar(1);
	           	a = DelayN.ar(x, 1, time1[index]);
		        local = (a*fb1[index]);
				LocalOut.ar(local);
		        x+local;
	            };
                m
			}};

Unfortunately, this won’t work. The LocalIn help file says: “There can only be one audio rate and one control rate LocalIn per SynthDef.”

1 Like

Oh - I must’ve forgotten that part. Do people normally do something like this with separate busses loaded on the Server?

The single LocalIn/Out pair can have multiple channels – and there’s no rule that you have to use all of the channels at once.

In this case, you’re pulling a LocalIn channel and pushing a LocalOut channel right away – there is never more than one pending LocalIn channel – so the logic can be as simple as “get one from the array, add one to the output array.”

SynthDef(\delays, { |out, gate = 1, etc|
	var localSize = 10;
	var localChannels = LocalIn.ar(localSize);
	var currLocalChan = 0;
	var localOut = nil;
	
	~delays = { |sig|
		var time1, fb1, m, chans = 4;
		time1 = ~makeRangedControl.(\time1, 0.5, 0, 1.0);
		fb1 = ~makeRangedControl.(\fb1, 0.9, 0, 1.0);
		m = sig.collect{ |x, index|
			var local, a, b, c;
			local = localChannels[currLocalChan];
			a = DelayN.ar(x, 1, time1[index]);
			local = (a*fb1[index]);
			currLocalChan = currLocalChan + 1;
			localOut = localOut.add(local);
			x+local;
		};
		LocalOut.ar(localOut.extend(localSize, DC.ar(0)));
		m
	}.value(signal);
	
	Out.ar(out, ...);
}).add;

Or, encapsulate the + 1 in a stream.

SynthDef(\delays, { |out, gate = 1, etc|
	var localSize = 10;
	var localChannels = LocalIn.ar(localSize);
	var localInStream = Pseq(localChannels.asArray, 1).asStream;
	var localOut = nil;
	
	~delays = { |sig|
		var time1, fb1, m, chans = 4;
		time1 = ~makeRangedControl.(\time1, 0.5, 0, 1.0);
		fb1 = ~makeRangedControl.(\fb1, 0.9, 0, 1.0);
		m = sig.collect{ |x, index|
			var local, a, b, c;
			local = localInStream.next;
			a = DelayN.ar(x, 1, time1[index]);
			local = (a*fb1[index]);
			localOut = localOut.add(local);
			x+local;
		};
		LocalOut.ar(localOut.extend(localSize, DC.ar(0)));
		m
	}.value(signal);
	
	Out.ar(out, ...);
}).add;

It looks like you want ~delays to be a reusable component. That wouldn’t work directly with the above approach, because it’s using local-declared variables belonging to the SynthDef function – although, you could pass them as arguments.

(
var delays = { |sig, localInStream, localOutList|
	var time1, fb1, m, chans = 4;
	time1 = ~makeRangedControl.(\time1, 0.5, 0, 1.0);
	fb1 = ~makeRangedControl.(\fb1, 0.9, 0, 1.0);
	m = sig.collect{ |x, index|
		var local, a, b, c;
		local = localInStream.next;
		a = DelayN.ar(x, 1, time1[index]);
		local = (a*fb1[index]);
		localOutList.add(local);
		x+local;
	};
	m
}.value(signal);

SynthDef(\delays, { |out, gate = 1, etc|
	var localSize = 10;
	var localChannels = LocalIn.ar(localSize);
	var localInStream = Pseq(localChannels.asArray, 1).asStream;
	var localOut = List.new;  // must be List! Not Array! See top of Array help about .add

	... sig...
	sig = delays.(sig, localInStream, localOut);
	
	LocalOut.ar(localOut.extend(localSize, DC.ar(0)));
	Out.ar(out, ...);
}).add;
)

Not tested but something like that should work.

hjh

3 Likes