Buses and patterns

Hello everyone,
i have a Pbind that plays a synth and on some steps i want to add more complex modulation to an argument of the synth. My idea is to map the arg to a bus and play another synth on that bus that outputs the modulation i want.
I came up with an idea, using a Prout, that creates the bus and plays the modulation-synth inside the Pbind but it feels a bit laborious and im not able to free the bus properly. Also it feels strange to play another synth inside a Pbind.

(SynthDef.new(
	\sin,
	{
		arg freq=4000, phase=0, amp=1, add=0, attack=0.02, release=0.5, curve=(-5), pan=(0), out=0;
		var env, sig;
		env = Env.perc(attack, release, amp, curve).ar(2);
		sig = Mix.ar(SinOsc.ar(freq, phase*2pi, env, add));
		sig = Pan2.ar(sig, pan);
		Out.ar(out, sig);
	}
).add)

(
Pbind(
	\instrument, \sin,
	\degree, Pseq([1,2,3,2,1,3,1,[1,3,5,7]],inf),
	\dur, Pseq([Pn(1/4,6), 3/8, 1/8],inf),
	\amp, 0.5,
	\phase, Prout({
		var bus; 
			bus=Bus.audio;
		loop{
			Synth(\sin,[
				\out, bus, \freq, 100, \amp, 1,
				\release, 2]);
			bus.asMap.yield;
			0.yield;
		}
	}),
).play)

I know that there is Pproto, which seems to be the right class for this task, but the documentation is missing examples for \audioBus, and i couldnt figure it out on my own.

Is there a better way of doing this?

1 Like

You’re definitely going in the right direction - if you want to continue down this route, you might consider using Pproto or Pbus, both of which handle clean-up of the bus and modulation synths a little better than doing it by hand.

You might also try my Pmod class, which does exactly what you’re trying to do here. It solves a bunch of tricky edge cases, group management, and such issues - things you will probably run into if you continue down this path of Pbind modulation. There are some examples attached to the gist as well. It’s still “alpha”, but I use it in more or less all of my patches, so it’s definitely working and relatively stable. Please feel to ask questions!

Here’s your example, written with Pmod:

(
SynthDef.new(
	\sin,
	{
		arg freq=4000, phase=0, amp=1, add=0, attack=0.02, release=0.5, curve=(-5), pan=(0), out=0;
		var env, sig;
		env = Env.perc(attack, release, amp, curve).ar(2);
		sig = Mix.ar(SinOsc.ar(freq, phase*2pi, env, add));
		sig = Pan2.ar(sig, pan);
		Out.ar(out, sig);
	}
).add;


Pbind(
	\instrument, \sin,
	\degree, Pseq([1,2,3,2,1,3,1,[1,3,5,7]],inf),
	\dur, Pseq([Pn(1/4,6), 3/8, 1/8],inf),
	\amp, 0.5,
	\phase, Pmod(
		\sin, // instrument by name - this can also be a function
		\resend, true, // resend every new event: else, this only resends when the synth changes
		\freq, 100,
		\amp, Pseg([0.1, 2, 0.1], [8, 8], \exponential, inf),
		\release, 2
	)
).play
)

Another variation, with a continuous modulator rather than discrete synths:

Pbind(
	\instrument, \sin,
	\tempo, 2.5,
	\release, 4,
	
	\dur, Pseq([1, 1, 1, 1, 2/3, 2/3], inf),

	\octave, Pseq([
		3,
		[3, 5]
	], inf).stutter(16),
	\degree, Pseq([
		0,
		[0, 5],
		[0, 3]
	], inf).stutter(Pseq([6, 3, 3], inf)),
	
	\amp, 0.5,
	\phase, Pmod(
		{ |amp, freq| amp * SinOsc.ar(freq) },
		\fadeTime, 5,
		\octave, 5,
		// \degree, 0,
		\paramLag, 0.4,
		\amp, 0.5 * Prand([0.1, 0.4, 0.7], inf).stutter(3),
	)
).play
3 Likes

Thank you for you answer!
Your Pmod class seems to be exactly what i’m looking for! Unfortunately i get an error, when i try the example. Also when i try the examples from your gist…

ERROR: Message 'asSynthDesc' not understood.
RECEIVER:
   Symbol 'sin'
ARGS:
CALL STACK:
	DoesNotUnderstandError:reportError
		arg this = <instance of DoesNotUnderstandError>
	Nil:handleError
		arg this = nil
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Routine>
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Routine>
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Routine>
		arg error = <instance of DoesNotUnderstandError>
	Object:throw
		arg this = <instance of DoesNotUnderstandError>
	Object:doesNotUnderstand
		arg this = 'sin'
		arg selector = 'asSynthDesc'
		arg args = [*0]
	< FunctionDef in Method Pmod:prepareSynth >  (no arguments or variables)
	Pmod:embedInStream
		arg this = <instance of Pmod>
		arg inEvent = <instance of Event>
		var server = <instance of Server>
		var synthStream = 'sin'
		var streamPairs = [*8]
		var endVal = 7
		var cleanup = <instance of EventStreamCleanup>
		var synthGroup = <instance of Group>
		var newSynthGroup = <instance of Group>
		var modGroup = <instance of Group>
		var newModGroup = <instance of Group>
		var buses = <instance of List>
		var currentArgs = nil
		var currentBuses = nil
		var currentSize = nil
		var currentEvent = nil
		var fadeTime = nil
		var nextEvent = <instance of Event>
		var nextSynth = 'sin'
		var streamAsValues = false
		var currentChannels = nil
		var currentRate = nil
	Routine:prStart
		arg this = <instance of Routine>
		arg inval = <instance of Event>
^^ The preceding error dump is for ERROR: Message 'asSynthDesc' not understood.
RECEIVER: sin


1 Like