A better way make Pbind transitions when Live Coding

This is not an inspired piece of code… I wanted to see about making transitions while live coding to multiple Pbinds at the same time… this worked but it’s far from ideal. Seems like it could be done a lot smarter, please educate me. essentially I am just duping a clump and then swapping out the \instrument and \dur like so…


Ndef(\a1_pat).clock_(t).quant_(4).fadeTime_(2).play;
Ndef(\a2_pat).clock_(t).quant_(4).fadeTime_(2).play


(
Ndef(\a1_pat,Pbind(
	\instrument, \kick,
	\dur, 1
));
Ndef(\a2_pat, Pbind(
	\instrument, \hH,
	\dur, 0.25,
))
)

/////////////// inst + dur swap 
(
Ndef(\a1_pat,Pbind(
	\instrument, \cB,
	\dur, 2
));

Ndef(\a2_pat, Pbind(
	\instrument, \hC,
	\dur, 0.5,
))
)

Perhaps you need to look at Pbindef?

https://docs.supercollider.online/Classes/Pbindef.html

2 Likes

If your intention is to really just crossfade the sounds, then either using Ndef or Pdef fadeTime’s is almost for sure the right approach. The comparable fadeTime functionality on Pdef changes the \amp parameter of each event rather than a smooth crossfade, which I imagine is more musically natural, but it really depends on your intention.

If you want a more musically sophisticated crossfade than just fading, you’re in slightly uncharted territory, but if you want to build something a bit custom, it could be the basis for a very cool livecoding setup…

Take a look at how EventPatternProxy (the basis for Pdef) does it’s transitions:

			// Pdef.sc:528
			if(fadeTime.isNil) {
				// ...
			}{
				fadeOutCleanup = cleanup.copy;
				cleanup.clear; // change need be seen by caller function, i.e. embedInStream
				Ppar([
					EmbedOnce(
						PfadeOut(stream, fadeTime, delta, tolerance),
						fadeOutCleanup
					),
					PfadeIn(newStream, fadeTime, delta, tolerance)
				]).asStream
			}

If you ignore the cleanup stuff, it’s basically playing the last fadeTime beats of the outgoing pattern wrapped in a PfadeOut (which slowly turns down the \amp control), and at the same time plays a PfadeIn wrapping the new event stream (turning \amp up). Now, imagine a modified version of this code:

			if(fadeTime.isNil) {
				// ...
			}{
				fadeOutCleanup = cleanup.copy;
				cleanup.clear; // change need be seen by caller function, i.e. embedInStream
				this.makeTransition(stream, newStream, fadeTime, delta, tolerance, fadeOutCleanup).asStream;
			}

// ...

makeTransition {
	|stream, newStream, fadeTime, delta, tolerance, fadeOutCleanup|
	^envir.use {
		if (~transition.isNil) {
			Ppar([
				EmbedOnce(
					PfadeOut(stream, fadeTime, delta, tolerance),
					fadeOutCleanup
				),
				PfadeIn(newStream, fadeTime, delta, tolerance)
			]).asStream
		} { ~transition.value(stream, newStream, fadeTime, delta, tolerance, fadeOutCleanup) }
             }
        }
}

It’s the same thing except it will use a custom function at envir[\transition] to generate the transition when you change a Pdef - so this could be e.g. a Rest-based fade out, randomly muting more and more events from one stream, while playing more and more from the other. Or, increasing a \wet control and decreasing a \dry control to make the outgoing sound become more reverberant and fade away. Or, any number of other musically cool transitions. You set your transition function like:

Pdef(\pattern1).put(\transition, { 
    |stream, newStream, fadeTime, delta, tolerance, fadeOutCleanup| 
    Ppar([
        EmbedOnce(
              Pbind(
                \amp, Pkey(\amp) * Pseg([1, 0], [fadeTime), // fade amplitude out
                \dur, Pkey(\dur) * Pseg([1, 2.5], [fadeTime]) // make the durations of the outgoing pattern get progressively slower
              ) <> stream,
              fadeOutCleanup
        ),
        Pbind(
             \muteProbability, Pseg([1.0, 0.0, 0.0], [fadeTime, inf]),  unmute based on probability to fade in
             \dur, Pfunc({ |e| e[\dur] * e[\muteProbability].coin(Rest(1), 1) })    
        )  <> newStream
    ])
});

You would need to override the EventPatternProxy:constrainStream method and add the new makeTransition method, which is very minor surgery but the potential here is really cool.

I haven’t tested any of this :slight_smile: - so getting this to properly work is a bit of an exercise for anyone interested - but I think musically this could be really compelling and powerful

2 Likes

wow these are some really exciting ideas… still getting my head fully around it and controlling selected mutes feels def something worth exploring