scel: install files to site-lisp/SuperCollider
[supercollider.git] / HelpSource / Tutorials / JITLib / jitlib_efficiency.schelp
blob828197165f935a316f135b39d210c7f9031bf82a
1 title:: jitlib_efficiency
2 summary:: Efficient coding with NodeProxy
3 categories:: Libraries>JITLib>Tutorials
4 related:: Overviews/JITLib
6 link::Classes/NodeProxy:: (and, in disguise link::Classes/ProxySpace::) represent "pronouns", placeholders for all kinds of sound producing objects that are able to write to a specific bus on the server.
8 To prepare such an object for playing, different objects require different things, some very little, some more. As working with the placeolders does not show directly which actions are very efficient and whic ones are not, it is shown here more in detail.
10 This is also important if you want to automate certain processes (e.g. for control by an external interface or a task) - some things (a) are not meant to be used in certain ways and better solutions should be used instead then, others are much more efficient (b, c).
12 code::
13 a = NodeProxy.audio;
14 ProxySpace.push;
16 a.source = ... is equivalent to ~a = ...
17 a.add(...) a.put(0,...) a[0] = ... ~a[0] = ... are equivalent in cpu load.
20 section::a) rebuild and send: manual rate
22 the following code requires a rebuild and send of a link::Classes/SynthDef:: and is thus most cpu-expensive. though fine for slower use (esp.hand-use) for automatisation it is better to build a synthdef and assign it.
24 code::
25 ~a = { someUGenFunction };
26 ~a = Patch(instrname, args);
27 ~a = SynthDef(\name, { someUGenFunction });
30 // the same applies to rebuilding the graphs:
31 ~a.rebuild
33 // this rebuild is also used when setting one of the following properties:
34 server, bus, setRates
37 section::b) starting synths and tasks
39 the following code sends commands to the server to start synths, which is load mainly on the server and depends on the characteristics of the synthdef:
41 code::
42 ~a = \synthDefName; // the synthdef is already on the server
43 ~a = Pbind(\instrument, name, \freq, ...);
44 ~a = Routine({ loop({ s.sendMsg("/s_new", name, ...)}) });
46 ~a.refresh; ~a.wakeUp; // waking up a stopped proxy does not require a resend
49 these resend the synth with new properies
51 code::
52 ~a.send(...)    // directly sends a message. the mapping bundle of the proxy is cached
53 ~a.sendAll(...)
55                 // for the following the bundle is recalculated if a new key is assigned.
56                 // if you use the same key with a different value, the bundle is modified
58 ~a.xset(...) ~a.xmap(...)
59 ~a.nodeMap_(a map)
60 ~a.fadeToMap(a map)
62 // synthdefs for these things are on the server already.
64 ~a.gate, ~a.env, ~a.line, ~a.xline
66 // some more calculations have to be made on client side, so if automated, it is better to use
67 // the above or a lag in the synth.
69 ~a.lineAt(key), ~a.xlineAt(key)
72 section::c) sending messages to running synths
74 for these the least calculation has to be done
76 code::
77 ~a.set(\freq, 400, \dt, 0.2); ~a.unset(\freq); // if running the bundle will be recalculated
78 ~a.map(\freq, ~lfo); ~a.unmap(\freq);
79 ~a.fadeTime = 2;
80 ~a.gateAt(key)
82 // for avoiding bundle recalculation you can directly talk to the group.
83 // this setting will not be kept when you exchange the synth
84 ~a.group.set(\freq, 500);
87 section::switching audio
89 (this can now be done with map!)
91 todo: rewrite this part.
93 control rate sources can be easily and efficiently switched using strong::map:: or strong::xmap::. here is an example of how already running audio rate inputs can be switched. it is about as efficient as (b) - first example (setting a defname). it works only for 1 or 2 channels right now.
95 code::
97 s.boot;
98 p = ProxySpace.push(s);
103 ~out.play;
105 ~s1 = { Blip.ar(Rand(32,15), 100, 0.5) };
106 ~s2 = { SinOsc.ar(740, 0, 0.1) };
107 ~s3 = { Pulse.ar(140, 0.2, 0.1) };
110 ~out = { Pan2.ar(~mix.ar(1), MouseX.kr(-1,1)) };
112 ~mix.read(~s1);
113 ~mix.read(~s2);
114 ~mix.read(~s3);
116 //resetting the source stops reading
117 ~mix = \default;
119 //now you can also crossfade audio efficiently:
120 ~mix.fadeTime = 1.5;
122 ~mix.read(~s1);
123 ~mix.read(~s2);
124 ~mix.read(~s3);
126 // automation:
128 t = Task({
129         var dt;
130         loop({
131                 dt = rrand(0.01, 0.3);
132                 ~mix.fadeTime = dt;
133                 ~mix.read([~s1, ~s2, ~s3].choose);
134                 dt.wait;
135         });
139 t.play(SystemClock);
142 // change the sources meanwhile:
143 ~s1 = { Blip.ar(105, 100, 0.2) };
144 ~s2 = { SinOsc.ar(350, 0, 0.1) };
145 ~s3 = { Pulse.ar(60, 0.2, 0.1) };
147 ~freq = { MouseX.kr(200, 600, 2) };
149 ~s1 = { Blip.ar(~freq.kr * 0.3, 10, 0.2) };
150 ~s2 = { SinOsc.ar(~freq.kr, 0, 0.1) };
151 ~s3 = { Pulse.ar(~freq.kr * 0.2, 0.2, 0.1) };
154 t.stop;
156 // note that when restarting ~out, the inputs have to be woken up.
157 // to avoid this, you can add the inputs to the mix nodeMap parents:
159 ~mix.nodeMap.parents.putAll( (s1: ~s1, s2: ~s2, s3: ~s3) );
161 // also the task can be added to the proxy:
163 ~mix.task = Routine({
164         loop({
165                 ~mix.fadeTime = rrand(0.01, 0.1);
166                 ~mix.read([~s1, ~s2, ~s3].choose);
167                 [0.2, 0.4].choose.wait;
168         });