Delayed MIDI clusters

Hi there,

I need to send the same but delayed notes sequence (with Pseq) to an external MIDI synth. The idea is to change the transposition for each delayed voice to have a kind of a clustered seq. So far it works but using a really inconvenient way: I am using a Pbind for each delayed seq, changing the transposition inside each Pbind itself, and finally use Ptpar to play them delayed. But as I just need one notes seq and one midi channel, it’s a pity to have that amount of Pbinds. I would love to have a flexible method that would allow me syntax like this

// This note sequence
Pseq([.....], inf)

// Played in this way
[-24, -12, 0, 12, 24]
[0.1, 0.12, 0.25, 0.3, 0.4]

// where -24 is the midi transposition value and 0.1 the delay time

Is there a way to do that using only one Pbind and produce the transposed delayed voices of the same sequence inside ?
Or do you think about a totally different method ?
I am looking for the most minimal syntax.

Thanks a lot.

You can make transposed versions of a pbind by wrapping the pbind in a pbindf and adding a transposition key.

You could then define a function that combines everything together, e.g. (here using default synth but it’s basically the same with external midi). You still create a lot of patterns but you don’t need to type or copy/paste everything a gazillion times. e.g:

(
s.waitForBoot {

	var myseq = [0,3,1,4];
	
	var basepattern = Pbind(
		\instrument, \default, // for simplicity
		\degree, Pseq(myseq, 1),
		\amp, 0.1);
	
	var combine_pat = {
		| sequence, transpositions, delays |
		var patterns = [];
		transpositions.do {
			| t, idx |
			patterns = patterns ++ delays[idx] ++ Pbindf(basepattern, \gtranspose, t);
		};
		patterns;
	};
	
	Ptpar(combine_pat.(myseq, [-24, -12, 0, 12, 24], [0.1, 0.12, 0.25, 0.3, 0.4])).play;
})

One thing to consider is that if you do a lot of calculations to set up your patterns you will want to insert a delay before starting to play to avoid missing the deadlines of the first events because time already starts running during the calculations, e.g.

(
s.waitForBoot {

	var myseq = [0,3,1,4];
	
	var basepattern = Pbind(
		\instrument, \default, // for simplicity
		\degree, Pseq(myseq, 1),
		\amp, 0.1);
	
	var combine_pat = {
		| sequence, transpositions, delays |
		var patterns = [];
		transpositions.do {
			| t, idx |
			patterns = patterns ++ delays[idx] ++ Pbindf(basepattern, \gtranspose, t);
		};
		patterns;
	};
	
	fork {
		wait(thisThread.clock.elapsedBeats - thisThread.clock.beats);
		Ptpar(combine_pat.(myseq, [-24, -12, 0, 12, 24], [0.1, 0.12, 0.25, 0.3, 0.4])).play;
	};
})
1 Like

It’s exactly that thanks a lot.
I would like to ad the amp arg for each duplicated voice like for example [0.2, 0.5, 1, 1, 0] but I don’t get how without creating 5 new Pbinds. Could you put me on track ? Thanks

Check the Pbindf help file –

Pbindf.new(pattern … pairs)

Pairs is plural hence you are not limited to only one additional key/value pair – you can add as many new ones as you need.

hjh

Thanks and sorry to be that newb but regarding the shiins code if I declare an new amp arg

patterns = patterns ++ delays[idx] ++ Pbindf(basepattern, \gtranspose, t, \amp, q);

I donn’t know then where to put the amp array [1, 0.5, 1, 0.25, 1] to send thoses values to the transpositions function

Since the index is already in the loop, I’d do it like this:

	var combine_pat = {
		| sequence, transpositions, delays, amps([0.1]) |  // provide a default for amps
		var patterns = [];
		transpositions.do {
			| t, idx |
			patterns = patterns ++ delays[idx] ++ Pbindf(basepattern, \gtranspose, t, \amp, amps.wrapAt(idx));
		};
		patterns;
	};

Also I wouldn’t worry about wait(thisThread.clock.elapsedBeats - thisThread.clock.beats); – adding 5 patterns this way should take a fraction of a millisecond, far less than server messaging latency.

hjh