ProxyChain  playing multiple synth and filter functions in one proxy




ProxyChain keeps a global repertoire of sound functions by name. 

A ProxyChain has an ordered collection of sound functions and uses a nodeproxy 

to add or remove the sound functions to/from the signal chain individually, by name.





*add(name, func, name, func, ... ) add functions to ProxyChain.allSources.


(

q = q ? ();


q.numChans = 5; 


ProxyChain.add(


// add a sound source

\dust, \mix -> { |dens=20, dustdec=0.02, dustfreq= 600| 

Ringz.ar(Dust.ar(dens).lag(0.0001), dustfreq, dustdec) 

},


// an association with \filter becomes a filter,

// and creates a wet/dry balance on the output.

\ringmod, \filter -> { |in, randrate=5| 

in.asArray[0] // force mono inputs

* SinOsc.ar(LFNoise0.kr([randrate, randrate]).exprange(300, 3000)).sum 

}, 


\dist, \filter -> { |in, drive=10, amp=0.2| (in.asArray[0] * drive).clip2(0.5) * amp },

// an association with \filterIn also becomes a filter,

// but creates the wet/dry balance control on the fx input.

\riseComb5, \filterIn -> { arg in, delay = 0.023, dlDrift = 0.02, spread=0.5, 

decayRise=0.5, decayFall=100;

var delayscales = 2 ** ((0 .. q.numChans - 1) * 2 / (q.numChans - 1) - 1 * spread); 

var dels = delayscales.scramble.collect { |dscale| 

var timedrift = LFDNoise3.kr(0.3, dlDrift, 1) * dscale;

var ampcomp = (20 * decayRise).dbamp * (decayFall ** -0.25);

var combs; 

in = in.asArray[0] * ampcomp.lag(0.2);

combs = (decayFall * [ 1, decayRise]).collect { |decay| 

CombL.ar(in, 1, delay * dscale, decay * delay) 

};

combs[0] - combs[1]; // combs come in slowly, like formlet. 

};

Splay.ar(dels)

}

);


// add specs for the controls used (for NodeProxyEditor).

Spec.add(\dens, [0.1, 1000, \exp]);

Spec.add(\dustamp, [0, 1, \amp]);

Spec.add(\dustdec, [0.0001, 0.1, \exp]); 

Spec.add(\dustfreq, \freq); 


Spec.add(\dt, [0.001, 0.2, \exp]); 

Spec.add(\dc, [0.01, 100, \exp]); 


Spec.add(\drive, [1, 100, \exp]); 


Spec.add(\spread, [0, 1, \amp]); 

Spec.add(\decayRise, [0, 0.9, \amp]); 

Spec.add(\decayFall, [1, 1000, \exp]); 

Spec.add(\dlDrift, [0, 0.1, \amp]); 


s.boot;

)

*new(numChannels, slotNames, server)

numChannels - of the proxy

srcFunc - a source to put in slot 0

slotNames - define which functions from ProxyChain.allSources will be available in what order.

// can be sources (func, \mix -> func) 

// or filters (\filter -> func, \filterIn -> func)

c = ProxyChain(q.numChans, [\dust, \ringmod, \dist, \riseComb5, \test]);

c.px.play; // play the proxy

c.gui(\chaintest, 12); // make a NodeProxyEditor for it




*from(proxy, slotNames)

make a proxychain for an existing proxy.

p = ProxySpace.push;

~pxchain.ar(2);

c = ProxyChain.from(~pxchain, [\dust, \ringmod, \dist, \riseComb5, \test]);

~pxchain.play;




add(key, wet) add a sound or filter function, wet is dry/wet balance


c.add(\dust, 0.123);

c.add(\dust, 0.2);


c.add(\ringmod, 0.5);

c.add(\dist, 1);


c.px.fadeTime = 2;

c.add(\riseComb5, 0.1); // \filterIn not show correctly in NodeProxyEditor yet.


// add a local version of a source:

(

c.add(\dust, nil, \mix -> { |dens=20, dustdec=0.02, dustfreq= 600| 

Ringz.ar(Dust.ar(dens).lag(0.0001), dustfreq * [0.62, 1, 1.62], dustdec).mean 

});

)

c.sources.postcs;

c.sources.put(\dust, nil);

c.add(\dust);

c.sources.postcs;




remove(key) remove a sound or filter function.

c.remove(\dist); // nodemap removes settings as well, so ...

c.remove(\ringmod);

c.remove(\riseComb5); // sometimes misses current value - why?


c.slotNames; // all slotnames that are available.

c.slotsInUse; // which ones are playing now?


c.remove(\dust);




butWin(name, buttonList, nSliders)

make a button window for simple control, and extra functions.

(

c.butWin(\PxChain, 

[ 

[ \generators, \label ],  

[ \dust, \switch ], 


[ '1 > 1', \label ],  

[ \ringmod, \switch ], 

[ \dist, \switch ], 


[ '1 > 5', \label ],  

[ \riseComb5, \switch ], 

[],

[\edit, \extra, { c.gui('Mestre', 16) }],

[\play, \extra, { c.px.playN }],

[\end, \extra, { c.px.end }],

], 

16

)

)



To do: 

insert new slotNames by name, or remove existing slotnames, keeping structure consistent; 

for reconfiguration of the list of proxychain slots that can be used. 



// maybe later like this. 

c = ProxyChain(q.numChans, [\gen, [\dust], '1>1', [\ringmod, \dist], '1>5', [\riseComb5]]);