A OFX_Chain is a wrapper around a nodeproxy which keeps an ordered collection of sound functions, which can be individually added to or removed from the proxy signal chain, by name.
The OFX_Chain class keeps a global dictionary of such sound functions, and a OFX_Chain can also have local sound functions.
Like Ndef, Pdef, Tdef, the OFX_Chain class keeps all named instances in a class variable OFX_Chain.all
where they can be accessed by name: OFX_Chain('chain1')
.
Basic code-only usage first:
// add a sound source
OFX_Chain.add(
\dust, \mix -> { |dens=20, dustdec=0.02, dustfreq= 600|
Ringz.ar(Dust.ar(dens).lag(0.0001), dustfreq, dustdec)
}
);
// add some effects, using NodeProxy roles:
// an association with \filter becomes a filter,
// and creates a wet/dry balance on the output.
// several funcs can be added as key1, func1, key2, type -> func2, etc.
OFX_Chain.add(
\dist, \filter -> { |in, drive=10, amp=0.2| (in * drive).tanh * amp },
\ringmod, \filter -> { |in, randrate=5|
// in a filter, 'in' is the signal on the bus
in.asArray[0] // force mono inputs
* SinOsc.ar(LFNoise0.kr([randrate, randrate]).exprange(300, 3000)).sum
},
\comb, \filterIn -> { |in, decay = 3| CombL.ar(in, 0.02, [0.03, 0.042], decay) },
\ampFin, \filter -> { |in, drive=1, ampLimit=1|
Limiter.ar(in * drive, ampLimit);
}
);
// the sound functions are here now:
OFX_Chain.allSources
// now make a OFX_Chain that uses them:
OFX_Chain(\test).clear;
OFX_Chain(\test, [\dust, \dist,\ringmod,\comb, \ampFin]);
// access by name
OFX_Chain(\test);
// warns that it cannot reset OFX_Chain from 'new' method
OFX_Chain(\test, [\dust, \dist,\ringmod, \ampFin]);
// tell the proxy to play
OFX_Chain(\test).play;
// kick in a source with a mix level
OFX_Chain(\test).add(\dust, 0.2)
// and an effect with a wet/dry level
OFX_Chain(\test).add(\ringmod, 0.7)
OFX_Chain(\test).add(\comb, 0.2)
// set effects parameters
OFX_Chain(\test).set(\decay, 10);
// set proxy fadetime
OFX_Chain(\test).proxy.fadeTime = 3;
// remove fx and source by fadeout
OFX_Chain(\test).remove(\ringmod)
OFX_Chain(\test).remove(\comb)
OFX_Chain(\test).remove(\dust)
// make a gui to see its state:
OFX_Chain(\test).gui;
Spec.add(\dens, [1, 100, \exp])
s), or by adding specs to the OFX_Chain's proxy. OFX_Chain also supports defining these specs when setting up the repertoire of functions.xxxxxxxxxx
( // add a sound source and its specs together:
OFX_Chain.add3(
\dust, \mix -> { |dens=20, dustdec=0.02, dustfreq= 600|
Ringz.ar(Dust.ar(dens).lag(0.0001), dustfreq, dustdec)
},
0.2, // default playing level,
// spec can be an array of key, value, key, value, or a dictionary
[
\dens, [1, 1000, \exp],
\dustdec, [0.00001, 0.1, \exp],
\dustfreq, [30, 15000, \exp]
]
);
OFX_Chain.add3(
\dist, \filter -> { |in, drive=10, amp=0.2| (in * drive).tanh * amp },
1.0,
( drive: [1, 10, \amp] )
);
OFX_Chain.add3(
\ringmod, \filter -> { |in, randrate=5|
// in a filter, 'in' is the signal on the bus
in.asArray[0] // force mono inputs
* SinOsc.ar(LFNoise0.kr([randrate, randrate]).exprange(300, 3000)).sum
},
0.5,
[randrate: [0.2, 200, \exp]]
);
OFX_Chain.add3(
\comb, \filterIn -> { |in, decay = 3| CombL.ar(in * 0.3, 0.02, [0.03, 0.042], decay) },
0.2,
(decay: [0.2, 200, \exp])
);
OFX_Chain.add3(
\ampFin, \filter -> { |in, drive=1, ampLimit=1|
Limiter.ar(in * drive, ampLimit);
},
1,
( drive: [1, 10, \amp], ampLimit: [0.5, 1] )
);
)
// ... and now the gui uses these specs:
OFX_Chain(\test, [\dust, \dist,\ringmod,\comb, \ampFin]);
g = OFX_Chain(\test).gui;
// slotNames can be changed while they are off, and the gui will show it
OFX_Chain(\test).slotNames = [\dust,\ringmod,\comb, \ampFin];
a dict of all available synth and filter functions
a dict of all OFX_Chain instances.
put synth functions into OFX_Chain.all
, by name, func, name, func ...
add a named synth func with level and specs
add a source func at srcName
add a default level for the func at srcName
add specs for the func at srcName
access the dict which contains all sourceDicts
get the srcDict at given srcName
check all sourceDicts for integrity
check the sourceDict at srcName
look up an existing OFX_Chain, or (if new and slotNames are given), make a new OFX_Chain with ordered names of synth functions in the slotNames.
xxxxxxxxxx
// the functions can be sources (func, \mix -> func)
// or filters (\filter -> func, \filterIn -> func)
(
c = OFX_Chain(\alpha, [\dust, \ringmod, \dist, \comb]);
c.play; // play the proxy
g = c.gui(12); // make a gui for it with 12 slots - see OFX_ChainGui
)
c.add(\dust);
key |
lookup name for the proxychain |
slotNames |
the names of the functions to have available. |
numChannels |
number of audio channels. default = 2. |
server |
server to use. default = s. |
like new, but using an existing NodeProxy or Ndef
xxxxxxxxxx
Ndef(\bla).ar(2);
OFX_Chain.from(Ndef(\bla), [\dust, \ringmod, \dist, \comb, \ampFin]);
OFX_Chain(\bla).play;
OFX_Chain(\bla).add(\dust);
OFX_Chain.all;
the key under which the proxyChain is stored in OFX_Chain.all
an optional dict of local source funcs - these will override source funcs with the same name in OFX_Chain.all
the proxy inside the chain
kick in a source by name, with a mix level
xxxxxxxxxx
c.add(\dust, 0.123);
c.add(\dust, 0.2);
c.add(\ringmod, 0.5);
c.add(\dist, 1);
key |
which function to kick in |
wet |
wet/dry mix ratio |
func |
an optional func that can locally replace the global func with that name. |
remove a currently playing source by name.
xxxxxxxxxx
c.remove(\dist);
c.remove(\ringmod);
c.remove(\riseComb5);
set (add or remove) multiple slots at once.
get slotNames, change to new slotNames.
the names of the currently playing slots.
get the currently active slot names
get the current settings (for the optional slotNames given)
get all keys at slotName
get all keys and values at slotName
make a OFX_ChainGui for the OFX_Chain - see examples.
xxxxxxxxxx
// by default, buttonList nil is replaced with control buttons for all slots.
c.gui(20);
// if specified, can be friendlier
(
g = c.gui(20,
[
[ \generators, \label ], // a label only
[ \dust, \slotCtl, 0.25 ], // a control for a slot, starting level
[ '1 > 1', \label ],
[ \ringmod, \slotCtl ], // 0 - dry by default
[ \dist, \slotCtl, 1 ], // 1 - all wet
[ '1 > 5', \label ],
[ \riseComb5, \slotCtl ],
// extras:
// e.g. an NdefGui with more space for param controls
[\phatEdit, \extra, { c.proxy.gui(40) } ],
// or maybe bigger buttons for play and end?
[\play, \extra, { c.playN.postln } ],
[\end, \extra, { c.end(2, true) } ],
]
)
)
Replacing a slot and reordering slots:
xxxxxxxxxx
// take proxychain from above:
OFX_Chain(\test);
// which has these slotnames
OFX_Chain(\test).slotNames
-> Order[ dust, dist, ringmod, comb, ampFin ]
// while no slots are active, switch to new slotNames:
OFX_Chain(\test).slotNames = [ \dust, \ringmod, \dist, \comb5, \ampFin ];
// make a gui for it - it has the new order
g = OFX_Chain(\test).gui;
(
// Add \comb5 now, after using its name in OFX_Chain
// -- this is a formlet-like reverb that fades in slowly
OFX_Chain.add3(
\comb5, \filterIn -> { arg in, delayScale = 1, decay = 5, dlDrift = 0.1;
var combs;
delayScale = delayScale.lag2(1);
dlDrift = dlDrift.lag2(1);
combs = [0.05, 0.08, 0.13, 0.21, 0.34].collect { |dt|
var drift = LFDNoise3.kr(0.3, dlDrift, 1);
CombL.ar(in, 0.7, dt * drift * delayScale, decay)
};
Splay.ar(combs)
},
0.2,
(
\delayScale: [0.1, 1, \exp],
\decay: [0.3, 300, \exp],
\dlDrift: [0, 0.8, \amp]
)
);
)
// now try kicking it in from the gui...