DX suite pseudo ugens for crossfaded mixing and fanning according to demand-rate control  


Part of: miSCellaneous


See also: DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFan, DXFanOut, Buffer Granulation, Live Granulation, PbindFx, kitchen studies


DX (Demand XFade) ugens are built upon DemandEnvGen and PanAz and can hence use their dynamic control options. Their user interface and underlying ugen structure is almost identical, due to multichannel expansion they are capable of triggering complex signal flows. As demand rate sequencing can be performed fast, DX ugens can, beneath their functionality as signal distribution controllers in the medium or large time-scale, be used as genuin synthesis tools in the area of microsound, e.g. for fast switching between sources as well as different processings of them. DXEnvFan and DXEnvFanOut give specific options as they can be used as multichannel envelopes and triggers at the same time. This e.g. enables server-side granulation techniques for arbitrary sound sources that are difficult to handle with granulation ugens alone, such es effect sequencing per grain and others. A related application, not necessarily in a granular time-scale, is crossfaded playback from different buffer positions. Finally DX fanning ugens allow server-side definition of spatial movements by crossfading between non-adjacent channels respectively buses.


NOTE: As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the DX suite overview and go through the help file examples in this order: DXMix - DXMixIn - DXEnvFan - DXEnvFanOut - DXFan - DXFanOut. Some general conventions are treated in detail in the following examples: fades and steps in DXMix help, Ex.2 – width and offset arguments in DXMix help, Ex.3 – multichannel expansion in DXMix help, Ex.6 – crossfade types in DXEnvFan help, Ex.1.


NOTE: PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice.


NOTE: Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See Ex.8 from DXMix help and Ex.2, Ex.4 from DXEnvFan help for aspects of CPU demand.


NOTE: In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See DXFan help Ex.4 for aspects of granulation with high trigger rates / short grain durations.


NOTE: The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours.


CREDITS: Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz.



Ex.1) DXMix, crossfade sequencing


// Crossfaded switching between sources, there exists a number of options, 

// e.g. for fade mode (inclusion of steps = plateau phases), curve type and width.

// The syntax of passing the sources within a Ref object is necessary

// to distinguish from multichannel expansion.



(

{

DXMix.ar(

Dseq([1, 0, 1, 2], inf),

`([SinOsc.ar(100), WhiteNoise.ar(), LFTri.ar(100)]),

stepTime: 0.015,

fadeTime: 0.015,

fadeMode: 1, // alternate steps and fades

sine: 0, // sine type or not

equalPower: 0 // square-rooted (equal power) or not

)

}.plot(0.12)

)




Ex.2) Comparison of fanning DX ugens

// Crossfading source signals with DXFan,

// result is a multichannel signal of size that has to be passed


(

{

DXFan.ar(

Dseq([3,2,1,4,5,6,7,0], inf),

SinOsc.ar(500),

size: 8,

fadeTime: 0.01

)

}.plot(0.1)

)


(

{

DXFan.ar(

Dseq([2, 0, 4, 6], inf),

`(SinOsc.ar([300, 700])),

size: 8,

fadeTime: 0.01

)

}.plot(0.1)

)



// DXEnvFan returns a multichannel envelope,

// the size has to be passed.

// Without any options it defaults to the square-rooted (equal power) sine type.


(

{

DXEnvFan.ar(

Dseq([3,2,1,4,5,6,7,0], inf),

size: 8,

fadeTime: 0.01,

)

}.plot(0.1)

)


// proof of concept with other fanning DX ugens:


// for getting the same result with DXFan pass a DC as source

(

{

DXFan.ar(

Dseq([3,2,1,4,5,6,7,0], inf),

DC.ar(1),

size: 8,

fadeTime: 0.01

)

}.plot(0.1)

)


// envelopes can also be sent to buses, for plotting we can get them back with In,

// here the size is considered via the bus.


(

a = Bus.audio(s, 8);

{

DXEnvFanOut.ar(

Dseq([3,2,1,4,5,6,7,0], inf) + a.index,

fadeTime: 0.01

);

In.ar(a, 8)

}.plot(0.1)

)


// analogously with DXFanOut and DC input


(

b = Bus.audio(s, 8);

{

DXFanOut.ar(

Dseq([3,2,1,4,5,6,7,0], inf) + b.index,

DC.ar(1),

fadeTime: 0.01

);

In.ar(b, 8)

}.plot(0.1)

)


(

a.free;

b.free;

)