In general, the changes in this version try to to strengthen the ideal of proxies being true placeholders that behave in many ways like their source objects:
- Pattern proxies now should behave more like their source pattern
- Node proxies can adjust their number of channels to the size of the source ugen function if you let them
This added a little complexity, but for various reasons, other aspects could be simplified, so that there are fewer classes and a bit more readable code. The system is easier to recover from failure. Some lesser known (or unknown) bugs are fixed, too.
As many parts of the code have been touched, it is possible that there are still bugs in it. Below, you find a long series of (manual) tests that should also reveal a little bit about what you should be able to expect from the system.
Classes that have changed:
NOTE: examples are given with Ndef, but apply to ProxySpace and NodeProxy:
Ndef(\x, 5); is the same as
~x = 5; in ProxySpace.
Perhaps one of the greatest chages in terms of behavior is the elastic reshaping of node proxies (See: NodeProxy elastic behavior setting). By default it is off. If you want to test it as a default, you can add this to your startup file:
- When a none-stream/non-pattern object is the source of the proxy, return the object only once per stream (do not loop by default)
- In the pattern system, the role of a non-pattern object is ambiguous: in some cases, when used as an input of a pattern, it will return itself endlessly (e.g. in a Pbind value). In other cases (e.g. as an element of a Pseq list), they are used only once and give way to the next element. Pattern proxies should actually behave the same dependent on their input. This means that asStream and embedInStream have to be implemented slightly differently: all pattern proxies now behave to asStream and embedInStream like their respective source objects. E.g.
Pdefn(\x, 800); Pbindef(\freq, Pdefn(\x)) will loop 800, while
Pseq([Pdefn(\x), 900]) will return first 800, then 900.
- controls are now set at synth creation time, not in an extra set message. This means that i-rate controls can be set in the nodemap.
- send and spawn extraArgs now override any existing nodeMap settings for each synth
- when setting the source of a node proxy to a number or an array of numbers, the bus is set by a precompiled synth def, which is much more efficient and consistent than building one. This means the source can be now set to a number/array liberally at higher rates (e.g. Ndef(\x, [100, 200])).
- For implementation reasons, it is now not possible anymore to add up numbers in a single node proxy. One slot will overwrite the next. E.g.
Ndef(\x) = 100; Ndef(\x) = 200; the output will be 200 and not (as ist used to be) 300.
- play (Monitor) can now map from any number of channels to any number of channels
- play and playN (Monitor) previously passed arguments are kept and can be partially overridden by new ones (the message clear removes them).
- nodeProxy.value(n) (e.g.
SinOsc.ar(Ndef(\x)) will keep the rate the proxy already has).
x.kr(n) will automatically expand when
n is nil. It remains fixed if n is given.
nodeProxy.kr(n) if no
n is given, they will now always return an array,
nodeProxy.value(x) returns an array, if no input is given. This is for general consistency: a few ugens expect an array as an input, and as the numChannels of a proxy can change now, this has to be specified. In order to have a UGen and not an array, use
- unlike it was before,
x.ar(n, offset) will now wrap around the available proxy bus channels. There is a third argument (wrap), when set to false, it will clip instead
- a third argument, clip, was added to ar/kr:
x.ar(n, offset, clip). When set to \wrap it will extend the output size of the existing channels by wrapping (the default is \wrap). Set it to \clip if you want to keep it in range by repeating the last value.
- InBus is more flexible and logical in terms of multichannel expansion now and has a helpfile
- the message NodeProxy: -mold allows you to change the number of channels and rate of the proxy at runtime. The proxy's children are automatically remapped, both source and monitor will crossfade between the respective states.
- Note that when rebuilding children, the timing (clock, quant and fadeTime) of the parent is used for all others. If you need different time bases of related proxies, mold dosn't keep their timing. Set the molded proxy's quant to a smallest common multiple of the two quants in this case.
- You can now use NodeMap directly as arguments in Synth objects.
- NodeProxy can be used as argument in a Synth directly, it will either return its bus index or by asMap its bus mapping argument. Note that when reshaping is allowed, the synth won't update automatically. You can register a dependency on \bus.
- node proxies and pattern proxies can be copied now: this will copy the hidden internal state to make the copy independent, but will keep the reference to the source object. In NodeProxy, the rendered SynthDef is cached, which makes the copy efficient. A ProxySpace or LazyEnvir can be copied and then modified independently.
- NodeProxy is now able to reshape according to its source. When doing so, it recursively updates all other node proxies that depend on it. Both source and monitor will crossfade between the respective states.
- reshaping can be set on three levels:
- as a global default, e.g.:
BusPlug.defaultReshaping = \elastic.
- for a ProxySpace, e.g.:
p = ProxySpace.push; p.reshaping = \elastic.
- for an individual NodeProxy/BusPlug e.g.:
Ndef(\x).reshaping = \elastic.
- by default, reshaping is
nil (no automatic reshaping). Apart from this, currently, there is
\elastic: both shrink and grow and change rate, and
\expanding: only grow, but also adjust rate.
- An empty function / or a function returning nil to a node proxy will not fail, but simply play a synth without output
- when trying to play control rate proxy, just warn and don't throw an error
- the source of a proxy is built when it is inserted, not only when the server is running. This allows to know its number of channels independently of the server running.
- bus is freed after fadeTime as to avoid a too early reuse.
- proxy is passed into events produced by event streams (
- NodeProxy and BusPlug code has been refactored to make it easier to read and more consistent in behavior (see below).
- NodeMap is now simply a Dictionary (NodeMapSetting classes have been removed). You can use NodeMap for many purposes.
- A node proxy keeps track of any other node proxies that use its output so that it can rebuild them if the bus changes ("children").
- Some methods, like setSourceLikeInPbind and prFadeTime were not necessary anymore.
- Pattern Proxies sometimes didn't embed correctly when quant was not nil (fixed)
- The node order of node proxies relative to each other was wrong when starting them from each other (fixed)
- setting the source of a NodeProxy many times at once failed to release the respective synths (fixed)
- using group-dependent event patterns (like Pfxb) in NodeProxy assigned them the wrong group (fixed)
- Cleanup sometimes didn't work in Pdef. Fixes issue #107.