Question about using Mix.fill with a Pdef

(Apologies for the newbie question)

I am trying to figure out how to turn this bit of code :

(
{
var harmonics = 12, fund = 50;
	Mix.fill(harmonics,
		{ arg count;
			Pan2.ar(
				FSinOsc.ar(fund * (count + 1), 
					mul: FSinOsc.kr(rrand(1/3, 1/6), mul: 0.5, add: 0.5 )),
				1.0.rand2)
		}
	) / (2*harmonics)
}.play;
)

into a SynthDef that i can later play through a Pdef.
I’m wondering how I would go about writting the Mix.fill (syntax?) in a SynthDef, as well as what kind of envelope I would need to use in order to get the same sound when playing a Pdef.

It is pretty straight forward. I added some arguments and an envelope. I also renamed fund to freq which is convenient when using the pattern library. Note that harmonics cannot be an arg, it has to be defined at synthdef creation time.

(
SynthDef(\test, {
	arg freq = 50, atk = 0.1, rel = 1,gate = 1, amp = 1, out = 0;
	var harmonics = 12;
	var env = EnvGen.kr(Env.asr(atk, 1, rel), gate, doneAction: 2);
	var sig = Mix.fill(harmonics,
		{ arg count;
			Pan2.ar(
				FSinOsc.ar(freq * (count + 1), 
					mul: FSinOsc.kr(rrand(1/3, 1/6), mul: 0.5, add: 0.5 )),
				1.0.rand2, amp)
		}
	) / (2*harmonics);
	Out.ar(out, sig * env)
}).add;
)

x = Synth(\test)
x.set(\gate, 0)
1 Like

Thank you for your reply.
what would need to be adjusted in order to use it with a Pdef?
It seems the default duration as well as the amplitude needs something.

(
Pdef(\ptest,
	Pbind(
		\instrument, \test,
		\freq, 50,
		\atk, 0.1,
		\rel, 1,
)).play;
)

Duration is \dur.

Amplitude is \amp.

Just noticed that the Getting Started chapter on pattern sequencing doesn’t quite explain common event parameter names – I can do something about that later. In the meantime, the Practical Guide to patterns helpfile series has more information.

hjh

1 Like

Hey, thanks for the reply.
I am aware about \dur and \amp.
What I meant is that, when adjusting the initial block of code (meaning the {}.play;) into a Pdef, the resulting sound behavior is different, and my suspicion is that the default \dur of that Pdef is probably the reason.
In other words, in Thor_Madsen’s block of code (adding a SynthDef and then just playing it), the audio result is the same.
But when playing that SynthDef through a Pdef, it differs.
As for the amp, it’s also significantly lower in the Pdef scenario.

Add \amp, 1 to the Pdef to get the same amplitude as your original code. This synth is a slowly evolving sound and if you just want it to be shimmering like your original code, maybe Pdef or the pattern library in general is not what you want. Patterns are great for things you want to change at certain predetermined time intervals but not for something like ‘let this sound play until I decide to stop it’. What are you wanting to achieve by playing the sound with a pattern?

1 Like

Well, part of it is that I’ve been trying out some things with Patterns, so it’s a tiny bit clearer for me when it comes to the syntax and possibilities - some things I know how to do with patterns and not with other tools. For instance, I know I can use randomness (eg Pwhite) and let sounds play while having ever changing random values, while I’m not sure how to achieve that outside of patterns. For example - if I’m not mistaken - using something like “rrand” when calling a synth without the use of a Pbind will give me one random value and stick with it, unless I manually change it.
It’s these kind of little things that make me turn to patterns because they are a little less foggy to me.
For this particular example, I didn’t have something specific in mind I wanted to achieve sound wise, I’m just in the process of learning while adding more tools to my basic Pdef workflow.

For “changing values over time” (or any type of behavior that needs to be spread out in time), the alternative to patterns is a Routine (or its wrappers, Task [which largely substitutes directly for a Routine] or Tdef, which is a named reference to a Task, like Pdef is a named reference to a pattern).

The Getting Started tutorial series does cover routines.

I’m with you on patterns – I like them!

Pbind plays a new note for each event. The time between notes is \dur; the length that each note plays is (by default) expressed in \legato as a proportion of \dur, and the default \legato is 0.8. So your Pbind is playing one synth for 0.8 beat, then stopping that note, and after a 0.2 beat pause, starting an all new synth.

If you want one continuous synth, perhaps try Pmono. (This is mentioned in the Practical Guide to Patterns chapter on Pbind.) Pmono directly expresses the idea of one long note whose parameters are being changed in the middle, without stopping and restarting.

hjh

1 Like

Thank you for the feedback!

For instance, I know I can use randomness (eg Pwhite) and let sounds play while having ever changing random values, while I’m not sure how to achieve that outside of patterns. For example - if I’m not mistaken - using something like “rrand” when calling a synth without the use of a Pbind will give me one random value and stick with it, unless I manually change it.

Just some additional thoughts on this type of randomness. You can think of randomness in three different levels or degrees:

‘Once-and-for-all’. This is the type you have now. Random values are calculated once when you create the synthdef (this is the same for { }.play, which under the hood creates a synthdef for you). If you want new random values you need to recreate/reevaluate the synthdef.

‘Once-per-note (or node)’. New random values are created for each instance of the synth. This can be done server side using eg. the Rand ugen or language side and passed to the synth

‘Moving randomness’. This is best done on the server using ugens to move the panning around during the lifetime of the note.

(
// you need to create a synth input (arg) to be able to pass new values. 
// Note that pan position is a value in the range -1, 1, where -1 is all the way left, 0 is center, and 1 is all the way right.
// Note also that I am using a shortcut for NamedControl for the array of pan values and that
// the array is filled with random values, like in the orignal code. The difference that now you can pass new values to the Synth.
// search the helpfiles for 'NamedControl' to learn more
SynthDef(\test, {
	arg freq = 50, atk = 0.1, rel = 1,gate = 1, amp = 1, out = 0;
	var harmonics = 12;
	var env = EnvGen.kr(Env.asr(atk, 1, rel), gate, doneAction: 2);
	var pan = \pan.kr({rrand(-1.0, 1.0)}!harmonics);
	var sig = Mix.fill(harmonics,
		{ arg count;
			Pan2.ar(
				FSinOsc.ar(freq * (count + 1), 
					mul: FSinOsc.kr(rrand(1/3, 1/6), mul: 0.5, add: 0.5 )),
				pan[count], amp)
		}
	) / (2*harmonics);
	Out.ar(out, sig * env)
}).add;
)

x = Synth(\test, [\pan, {rrand(-1.0, 1,0)}!12])
(
// everytime to you run this, you will get new random values for panning
x.set(\gate, 0);
x = Synth(\test, [\atk, 2, \rel, 2, \pan, {rrand(-1,0, 1.0)}!12])
)
x.set(\gate, 0)

(
// With a pattern. You get a new random note with new random pannning every 5 seconds
Pdef(\test, 
	Pbind(
		\instrument, \test, 
		\freq, Prand([28, 30, 32, 33, 35].midicps, inf),
		// the \freq value can also be expressed directly as a midinote number - for this to work,
		// the synth input has to be named 'freq', so that is one of the reasons I changed it from 'fund' to 'freq'
		// comment out the \freq and uncomment below
		// \midinote,  Prand([28, 30, 32, 33, 35], inf),
		\legato, 1,
		\atk, 2,
		\rel, 2,
		\pan, Ptuple({Pwhite(-1.0, 1.0)}!12, inf), 
		\dur, 5
)).play
)

Pdef(\test).stop

(
// using the Rand ugen to the same effect - each new instance of the synth generates new random values
SynthDef(\test, {
	arg freq = 50, atk = 0.1, rel = 1,gate = 1, amp = 1, out = 0;
	var harmonics = 12;
	var env = EnvGen.kr(Env.asr(atk, 1, rel), gate, doneAction: 2);
	var pan = \pan.kr({rrand(-1, 1)}!harmonics);
	var sig = Mix.fill(harmonics,
		{ arg count;
			Pan2.ar(
				FSinOsc.ar(freq * (count + 1), 
					mul: FSinOsc.kr(rrand(1/3, 1/6), mul: 0.5, add: 0.5 )),
				Rand(-1, 1), amp)
		}
	) / (2*harmonics);
	Out.ar(out, sig * env)
}).add;
)

x = Synth(\test)
(
// everytime to you run this, you will get new random values for panning
x.set(\gate, 0);
x = Synth(\test, [\atk, 2, \rel, 2])
)

x.set(\gate, 0);

(
// using ugens to move the panning, here LFNoise1 but there are many other ways to create 'dynamic randoness' on the server.
SynthDef(\test, {
	arg freq = 50, atk = 0.1, rel = 1,gate = 1, amp = 1, out = 0;
	var harmonics = 12;
	var env = EnvGen.kr(Env.asr(atk, 1, rel), gate, doneAction: 2);
	var sig = Mix.fill(harmonics,
		{ arg count;
			Pan2.ar(
				FSinOsc.ar(freq * (count + 1), 
					mul: FSinOsc.kr(rrand(1/3, 1/6), mul: 0.5, add: 0.5 )),
				LFNoise1.kr(1).range(-1, 1), amp)
		}
	) / (2*harmonics);
	Out.ar(out, sig * env)
}).add;
)

x = Synth(\test, [\pan, {rrand(-1, 1)}!12]);

// you will hear panning changing over time.

x.set(\gate, 0);
1 Like

great stuff, thank you for this.

I’ll just add a little something I came across regarding Pdef duration (in case another inexperienced member is navigating a similar Pdef workflow):
there is the Pkey object, which could potentially help out when it comes to \dur and “clashes” with the synth envelope.
Pkey gives backwards access to values, so in this case I combined it with a fine-tuning of \legato and it smoothed out the output.
(taken from your second example)

(
// With a pattern. You get a new random note with new random pannning every 5 seconds
Pdef(\test, 
	Pbind(
		\instrument, \test, 
		\freq, 50,
		\legato, 2,
		\atk, 2,
		\rel, 2,
		\pan, Ptuple({Pwhite(-1.0, 1.0)}!12, inf), 
		//\dur, 5
		\dur, Pkey(\atk) + Pkey(\rel),
)).play
)