SCDoc: Use proper static string constants instead of comparing string literals.
[supercollider.git] / HelpSource / Tutorials / JITLib / jitlib_basic_concepts_03.schelp
blobb359d748c9bf941dcc1b80da9be03939f96194ed
1 title:: jitlib_basic_concepts_03
2 summary:: proxyspace - basic concepts
3 categories:: Libraries>JITLib>Tutorials
4 related:: Overviews/JITLib, Tutorials/JITLib/jitlib_basic_concepts_02, Tutorials/JITLib/jitlib_basic_concepts_04
6 internal structure of the node proxy, node order and the parameter context
8 list::
9 ## link::#a)_nodeproxy_slots#a) slots::
10 ## link::#b)_fade_time#b) fadeTime::
11 ## link::#c)_play/stop,_send/free,_pause/resume#c) play/stop, send/release, pause/resume, clear::
12 ## link::#d)_the_parameter_context#d) the parameter context::
15 A NodeProxy has two internal contexts in which the objects are inserted: The group, which is on the server, and the nodeMap, which is a client side parameter context. As the group can contain an order of synths, there is a client side representation, in which the source objects are stored (see link::Classes/Order::).
17 code::
18 // make new space
19 p = ProxySpace.push(s.boot);
20 ~z.play; ~y.ar; // explicitly initialize proxies
23 section::a) NodeProxy slots
25 One node proxy can hold several objects in an execution order. The index can be any positive integer.
27 code::
28 // the initial slot (0) is used when assigning directly.
29 // ~y is still unused, we will add it later.
31 ~z = (~y * pi).sin * 0.1 * { LFSaw.kr(LFNoise1.kr(0.1 ! 3).sum * -18).max(0.2) };
33 // other slot numbers are accessed by positive integers:
35 ~y[1] = { Saw.ar([400, 401.3], 0.4) };
36 ~y[0] = { Saw.ar([300, 301], 0.4) };
38 // to remove one of them, nil is used:
40 ~y[0] = nil;
42 // what is to be found at index 1?
43 ~y.objects[1] // a playing interface
44 ~y.objects[1].source.postcs // the function that was put in.
45 ~y.objects.postcs       // this returns objects in the slots.
46 ~y.source.postcs        // this returns the function in slot 0 only.
49 multiple assignment
51 code::
52 // the function is assigned to th slots from 1 to 4
53 ~z[1..4] = { SinOsc.ar(exprand(300, 600), 0, LFTri.kr({exprand(1, 3)} ! 3).sum.max(0)) * 0.1 };
56 // the function is assigned to the slots 1, 2 and 3 (subsequent)
57 ~z[1..] = [ {SinOsc.ar(440) * 0.1 }, { SinOsc.ar(870) * 0.08 }, { SinOsc.ar(770) * 0.04 }];
59 // if no slot is given, all other slots are emptied
60 ~z = { OnePole.ar(Saw.ar([400, 401.3], 0.3), 0.95) };
62 ~z.end;
63 ~y.end;
66 section::b) fade time
68 code::
69 // setting the fadeTime will allow cross fades.
70 // in case of an audio rate proxy the fade is pseudo-gaussian
71 // in case of a control rate proxy it is linear.
73 ~z.play;
75 ~z.fadeTime = 5.0; // 5 seconds
76 ~z = { max(SinOsc.ar([300, 301]), Saw.ar([304, 304.3])) * 0.1 };
77 ~z = { max(SinOsc.ar(ExpRand(300, 600)), Saw.ar([304, 304.3])) * 0.1 };
79 // the fadeTime can be set effectively at any time
80 ~z.fadeTime = 0.2;
81 ~z = { max(SinOsc.ar(ExpRand(3, 160)), Saw.ar([304, 304.3])) * 0.1 };
84 note::
85 the fadeTime is also used for the operations xset and xmap. (see below)
88 section::c) play/stop, send/free, pause/resume
90 there are a couple of messages a NodeProxy understands that are related to play, stop etc. Here is what they do.
92 subsection::play/stop
94 this pair of messages is related to the monitoring function of the proxy. play starts monitoring, stop ends the monitoring. emphasis::if the proxy group is playing:: (this can be tested with .isPlaying), play will not affect the proxie's internal behaviour in any way. Only if it is not playing (e.g because one has freed the group by cmd-period) it starts the synths/objects in the proxy. Stop never affects the internal state of the proxy.
96 code::
97 // first hit cmd-period.
98 ~z = { max(SinOsc.ar(ExpRand(3, 160)), Saw.ar([304, 304.3])) * 0.1 };
99 ~z.play;                // monitor the proxy
100 ~z.stop;                // note that now the proxy is still playing, but only in private
101 ~z.isPlaying;           // is the group playing? yes.
102 ~z.monitor.isPlaying;   // is the monitor playing? no.
105 You can pass a vol argument to play to adjust the monitor volume without affecting the proxy internal bus volume.
107 code::
108 ~z.play(vol:0.3);
109 // while playing you can set the volume also:
110 ~z.vol = 0.8;
113 subsection::send / release
115 this pair of messages controls the synths within the proxy. It does not affect the monitoring (see above). send starts a new synth, release releases the synth. strong::send:: by default releases the last synth. if the synth frees itself (doneAction 2) strong::spawn:: can be used.
117 code::
118 // first hit cmd-period.
119 ~z.play; // monitor. this starts also the synth, if the group wasn't playing.
121 ~z = { SinOsc.ar(ExpRand(20, 660) ! 2) * Saw.ar(ExpRand(200, 960) ! 2) * 0.1 };
123 ~z.release; // release the synth. the current fadeTime is used for fade out
125 ~z.send; // send a new synth. the current fadeTime is used for fade in
127 ~z.send; // send another synth, release the old
129 ~z.release;
131 ~z.stop;
133 ~z.play; // monitor. as the group was still playing, this does _not_ start the proxy.
136 in order to free the synths and the group together, strong::free:: is used:
138 code::
139 ~z.free; // this does also not affect the monitoring.
140 ~z.play; // monitor. as the group was not playing, this starts the proxy.
143 in order to free the synths and the group, stop playback, strong::end:: is used.
145 code::
146 ~z.end(3); // end in 3 sec
149 in order to rebuild the synthdef on the server, use strong::rebuild::. this is of course far less efficient than emphasis::send::, but it can make sense; e.g. the synthdef has random elements. UGens like Rand(300, 400) create new random values on every send, while client-side random functions like exprand(1, 1.3) only get built once; to force new decisions with these, one can use strong::rebuild::.
151 code::
153 ~z = {
154         Splay.ar(
155                 SinOsc.ar(Rand(300,400) + ({exprand(1, 1.3)} ! rrand(1, 9)))
156                 * LFCub.ar({exprand(30, 900)} ! rrand(1, 9))
157                 * LFSaw.kr({exprand(1.0, 8.0)} ! rrand(1, 9)).max(0)
158                 * 0.1
159         )
163 ~z.play;
164 ~z.rebuild;
165 ~z.send;        // send just creates a new synth - new freq, all else remains the same
166 ~z.rebuild;     // rebuild the synthdef, re-decide numbers of oscs
167 ~z.end;
170 subsection::pause / resume
172 when paused, a node proxy still stays active, but every synth that is started is paused until the proxy is resumed again.
174 code::
175 ~z.play;
177 ~z.pause; // pause the synth.
179 ~z = { SinOsc.ar({ExpRand(300, 660)} ! 2) * 0.1 };      // you can add a new function,
180                                                         // which is paused.
182 ~z.resume; // resume playing.
185 Note that pause/resume causes clicks with audio rate proxies, which do not happen when pauseing control rate proxies.
187 subsection::clear
189 clear removes all synths, the group, the monitor and releases the bus number.
191 code::
192 ~z.clear;
193 ~z.bus;         // no bus
194 ~z.isNeutral;   // not initialized.
197 note that when other processes use the nodeproxy these are not notified. So clearing has to be done with regard to this.
199 section::d) The parameter context
201 what happens to function arguments?
203 code::
204 ~y.play;
205 ~y = { arg freq=500; SinOsc.ar(freq * [1, 1.1]) * 0.1 };
208 now the argument 'freq' is a control in the synth (just like in SynthDef) which you can change by the strong::'set':: message.
210 code::
211 ~y.set(\freq, 440);
213 // unlike in synths, this context is kept and applied to every new synth:
215 ~y = { arg freq=500; Formant.ar(50, freq * [1, 1.1], 70) * 0.1 };
218 the message strong::xset:: is a variant of set, to crossfade the change using the current fadeTime:
220 code::
221 ~y.fadeTime = 3;
222 ~y.xset(\freq, 600);
224 // the same context is applied to all slots:
226 ~y[2] = { arg freq=500; SinOsc.ar(freq * [1, 1.1]) * LFPulse.kr(Rand(1, 3)) * 0.1 };
227 ~y.xset(\freq, 300);
230 the parameter context also can keep bus mappings. a control can be mapped to any emphasis::control proxy:: :
232 code::
233 ~c = { MouseX.kr(300, 800, 1) };
234 ~y.map(\freq, ~c);
236 // also here the context is kept:
238 ~y = { arg freq=500; Formant.ar(4, freq * [1, 1.1], 70) * 0.1 };
241 the message strong::xmap:: is a variant of map, to crossfade the change using the current fadeTime:
243 code::
244 ~y.set(\freq, 440);
245 ~y.xmap(\freq, ~c);
248 to remove a setting or a mapping, use unmap / unset.
250 code::
251 ~y.unmap;
254 also multichannel controls can be mapped to a multichannel proxy using strong::map:: :
256 code::
257 ~c2 = { [MouseX.kr(300, 800, 1), MouseY.kr(300, 800, 1)] };
258 ~y = { arg freq=#[440, 550]; SinOsc.ar(freq) * SinOsc.ar(freq + 3) * 0.05 };
259 ~y.map(\freq, ~c2);
262 the parameter context can be examined:
264 code::
265 ~y.nodeMap;
267 // apart from the parameters explicitly set,
268 // it contains the bus index and the fadeTime
270 // for more information, see NodeMap
273 p.clear(8); // clear the whole proxy space, in 8 secs.
276 previous: link::Tutorials/JITLib/jitlib_basic_concepts_02:: next: link::Tutorials/JITLib/jitlib_basic_concepts_04::