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
- 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