Using lambda SynthDefs in patterns

I grabbed some code using the { UGen graph }.play syntax and a Routine to sequence it and started tinkering it. Since I love patterns, I tried to use pattern to sequence it but the SynthDef code is full of .rand and .choose and I don’t want to rewrite it. So I asked myself: why the two approach are so exclusive ?

But they are not, it is very easy to use a function as a SynthDef in a pattern thanks to .asSynthDef method:

(
Pdef(\demo, 
	Pbind(
		\instrument, Pfunc({
			{
				var rep = [4, 8, 16, 32];
				var n = rep.choose;
				var x = [

					54, 60, 66, 72, 81, 90, 96, 102,
					108, 128, 132, 144, 162, 180, 192, 204,
					216, 240, 264, 288, 324, 360, 384, 408,
					432, 480, 528, 576, 648, 720, 768, 816,
					864, 960, 1056, 1152, 1296, 1440, 1536, 1632,
					1728, 1920, 2112, 2304, 2592, 2880, 3072, 3264,
					3456, 3840, 4224, 4608, 5184, 5760, 6144, 6528,
					6912, 7680, 8448, 9216, 10368, 11520, 12288, 528

				];
				var fac1 = [1,10,100,1000].choose;
				var fac2 = [1,10,100,1000].choose;
				var fac3 = [1,10,100,1000].choose;
				Mix.fill(1,
					{
						var detune = 5.rand;
						var saw;
						var sin;
						var sig;
						detune = XLine.kr(0.1,1+250.0.rand ,2+9.0.rand) * 2.0.rand* [1,-1].choose;
						sin = SinOsc.ar(x.choose * ( 1 + ( SinOsc.ar(x.choose/fac1) * x.choose/fac2 )) + detune, 4.rand, 0.25);
						saw = RLPF.ar(Saw.ar(x.choose*0.01+detune, 0.75), x.choose, 2.rand);
						saw = [
							saw,
							saw.fold2( SinOsc.ar(x.choose/fac3).range(0.1,1) ),
							saw.wrap2( SinOsc.ar(x.choose/fac3).range(0.1,1) ),
							saw *  SinOsc.ar(x.choose/2),
							( saw *  SinOsc.ar(x.choose/fac3).range(1,20) ).tanh/2,
						].choose;
						sig = (sin+saw) * EnvGen.kr(Env.sine(rrand(4,20), 1/n), 1, doneAction:2);
						sig = Limiter.ar(sig);
						sig = Pan2.ar(sig, 1.rand2);
					}
				);
			}.asSynthDef.add;
		}),
		\dur, Pexprand(0.2,3,inf),
		\amp, 0.1,
	)
).play;
);
1 Like

It’s even possible to use Pbind keys to patternally generate the SynthDef

(
Pdef(\demo, 
	Pbind(
		\osc, Prand([
			{ arg freq; SinOsc.ar(freq) },
			{ arg freq; LFSaw.ar(freq) },
		],inf),
		\instrument, Pfunc({ arg ev;
			{ arg freq, amp, gate=1;
				var sig;
				sig = ev[\osc].(freq);
				sig = sig ! 2 * amp;
				sig = RLPF.ar(sig, \lpfr.kr(1.3) * freq, \rq.kr(0.5));
				sig * EnvGen.kr(\adsr.kr(Env.adsr(0.1,0.1,0.8,0.1)), gate, doneAction:2);
			}.asSynthDef.add
		}),
		\degree, Pseq([0,2,3],inf),
		\dur, 1,
		\amp, 0.1,
	)
).play;
);
2 Likes

This is a nice approach! Sequencing in SC2 used to build on the fly.
I’ve never thought about such building with patterns, but I did some live replacement with Functions returning oscillators.

https://www.listarc.bham.ac.uk/lists/sc-users-2012/msg22935.html

Similar can be done with Patterns as well, of course. A downside of building on the fly is the increased OSC traffic, problems could occur with large SynthDefs.
However the gained flexibilty is certainly an interesting resource if sequencing is not too fast (I think ‘OverlapTexture’ was the SC2 class for this type of sequencing).