Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / HelpSource / Guides / Order-of-execution.schelp
blob3885e51554ce3022b8fc745731b19373e5802461
1 title:: Order of execution
2 summary:: Understanding order of execution of synths on the server
3 categories:: Server>Nodes
4 related:: Classes/Server, Classes/Node, Classes/Group, Classes/ParGroup, Reference/default_group, Classes/Bus, Classes/Out, Classes/ReplaceOut, Classes/XOut, Classes/OffsetOut, Classes/In, Classes/InFeedback, Classes/LocalIn, Classes/LocalOut, Classes/SharedIn, Classes/SharedOut
6 Order of execution is one of the most critical and seemingly difficult aspects of using SuperCollider, but in reality it only takes a little thought in the early planning stages to make it work for you.
8 section:: Introduction
10 Order of execution in this context doesn't mean the order in which statements are executed in the language (the client). It refers to the ordering of synth nodes on the server, which corresponds to the order in which their output is calculated each control cycle (blockSize).
11 Whether or not you specify the order of execution, each synth and each group goes into a specific place in the chain of execution.
13 If you have on the server:
14 code::
15     synth 1 ---> synth 2
17 ... all the unit generators associated with synth 1 will execute before those in synth 2 during each control cycle.
19 If you don't have any synths that use In.ar, you don't have to worry about order of execution. It only matters when one synth is reading the output of another.
21 The rule is simple: if you have a synth on the server (i.e. an "effect") that depends on the output from another synth (the "source"), the effect must appear later in the chain of nodes on the server than the source.
22 code::
23     source ---> effect
25 If you have:
26 code::
27     effect ---> source
29 The effect synth will not hear the source synth, and you won't get the results you want.
31 image::server.png#A diagram of a typical server configuration::
33 On the server external signals can be received by synths from "public" input busses (one in the represented case), while the different synths must be connected to "public" out audio busses (two in the case) in order to output a signal externally to the soundcard (see Bus). Other busses (both control and audio) are internal.
34 In general, busses can be thought as roughly analogous to sends, busses, or submixes on an analog mixer, or as pipes allowing one to route "flowing" signals. If a synth is connected to a bus at a certain point (thus "flowing" into it)  a synth taking the signal from the same bus at a subsequent point will take as input the flowing signal (along with anything else previously output to the bus), just as would occur with a water pipe.
36 section:: Some Notes about Servers and Targets
38 There is always a default Server, which can be accessed or set through the class method Server.default. At startup this is set to be the local Server, and is also assigned to the interpreter variable s.
39 code::
40 // execute the following and watch the post window
41 s === Server.default;
42 s === Server.local;
43 Server.default = Server.internal; s === Server.default;
44 Server.default = Server.local; // return it to the local server
46 When a link::Classes/Server:: is booted there is a top level group with an ID of 0 that defines the root of the node tree. This is represented by a subclass of Group: link::Classes/RootNode::.
47 There is also a link::Reference/default_group:: with an ID of 1. This group is the default group for all Nodes. This is what you will get if you supply a Server as a target. If you don't specify a target or pass in nil, you will get the default group of the default Server.
49 The default group serves an important purpose: It provides a predictable basic Node tree so that methods such as Server:scope and Server:record can function without running into order of execution problems.
50 Thus in general one should create new Nodes within the default group rather than in the RootNode. See link::Reference/default_group:: and link::Classes/RootNode:: for more detail.
52 section:: Controlling order of execution
54 There are three ways to control the order of execution: using addAction in your synth creation messages, moving nodes, and placing your synths in groups. Using groups is optional, but they are the most effective in helping you organize the order of execution.
56 subsection:: Add actions
58 By specifying an addAction argument for code::Synth.new:: (or SynthDef.play, Function.play, etc.) one can specify the node's placement relative to a target. The target might be a group node, another synth node, or a server.
60 As noted above, the default target is the default_group (the group with nodeID 1) of the default Server.
62 The following Symbols are valid addActions for Synth.new: code::\addToHead, \addToTail, \addBefore, \addAfter, \addReplace::.
63 definitionlist::
64 ## code:: Synth.new(defName, args, target, addAction) :: || list::
65 ## if target is a Synth the  \addToHead, and \addToTail methods will apply to that Synths group
66 ## if target is a Server it will resolve to that Server's default group
67 ## if target is nil it will resolve to the default group of the default Server
71 For each addAction there is also a corresponding convenience method of class Synth:
73 definitionlist::
74 ## code:: Synth.head(aGroup, defName, args) :: || add the new synth to the the head of the group specified by aGroup
75 list::
76 ## if aGroup is a synth node, the new synth will be added to the head of that node's group
77 ## if target is a Server it will resolve to that Server's default group
78 ## if target is nil it will resolve to the default group of the default Server
81 ## code:: Synth.tail(aGroup, defName, args) :: || add the new synth to the the tail of the group specified by aGroup
82 list::
83 ## if aGroup is a synth node, the new synth will be added to the tail of that node's group
84 ## if target is a Server it will resolve to that Server's default group
85 ## if target is nil it will resolve to the default group of the default Server
88 ## code:: Synth.before(aNode, defName, args) :: || add the new node just before the node specified by aNode.
90 ## code:: Synth.after(aNode, defName, args) :: || add the new node just after the node specified by aNode.
91 ## code:: Synth.replace(synthToReplace, defName, args) :: || the new node replaces the node specified by synthToReplace. The target node is freed.
94 Using Synth.new without an addAction will result in the default addAction. (You can check the default values for the arguments of any method by looking at a class' source code. See Internal-Snooping for more details.)
95 Where order of execution matters, it is important that you specify an addAction, or use one of the convenience methods shown above.
98 subsection:: Moving nodes
99 code::
100     .moveBefore
101     .moveAfter
102     .moveToHead
103     .moveToTail
105 If you need to change the order of execution after synths and groups have been created, you can do this using move messages.
106 code::
107     ~fx = Synth.tail(s, "fx");
108     ~src = Synth.tail(s, "src");  // effect will not be heard b/c it's earlier
109     ~src.moveBefore(~fx);   // place the source before the effect
112 subsection:: Groups
114 Groups can be moved in the same way as synths. When you move a group, all the synths in that group move with it. This is why groups are such an important tool for managing order of execution. (See the Group helpfile for details on this and other convenient aspects of Groups.)
115 code::
116     Group 1 ---> Group 2
118 In the above configuration, all of the synths in group 1 will execute before all of the synths in group 2. This is an easy, easy way to make the order of execution happen the way you want it to.
120 Determine your architecture, then make groups to support the architecture.
123 subsection:: Parallel Groups
125 In some cases, server nodes do not depend on each other. On multiprocessor systems, these nodes could be evaluated on different CPUs.
126 This can be achieved by adding those nodes to a parallel group (see link::Classes/ParGroup::). Parallel Groups can be considered as
127 Groups, whose contained nodes are not guaranteed to have a specific order of execution.
129 note::
130 SuperCollider's default server strong::scsynth:: is not able to distribute the synths to different threads. However the alternative
131 server strong::supernova:: is able to distribute the contents of parallel groups to different CPUs.
135 subsection:: Using order of execution to your advantage
137 Before you start coding, plan out what you want and decide where the synths need to go.
139 A common configuration is to have a routine playing nodes, all of which need to be processed by a single effect. Plus, you want this effect to be separate from other things running at the same time.
140 To be sure, you should place the synth -> effect chain on a private audio bus, then transfer it to the main output.
141 code::
142         [Lots of synths] ----> effect ----> transfer
144 This is a perfect place to use a group:
145 code::
146         Group ( [lots of synths] ) ----> effect ----> transfer
148 To make the structure clearer in the code, one can also make a group for the effect (even if there's only one synth in it):
149 code::
150         Group ( [lots of synths] ) ----> Group ( [effect] ) ----> transfer
152 I'm going to throw a further wrench into the example by modulating a parameter (note length) using a control rate synth.
154 So, at the beginning of your program:
155 code::
156 s.boot;
159 l = Bus.control(s, 1);  // get a bus for the LFO--not relevant to order-of-exec
160 b = Bus.audio(s, 2);    // assuming stereo--this is to keep the src->fx chain separate from
161                                 // other similar chains
162 ~synthgroup = Group.tail(s);
163 ~fxgroup = Group.tail(s);
165 // now you have synthgroup --> fxgroup within the default group of s
167 // make some synthdefs to play with
168 SynthDef("order-of-ex-dist", { arg bus, preGain, postGain;
169         var sig;
170         sig = In.ar(bus, 2);
171         sig = (sig * preGain).distort;
172         ReplaceOut.ar(bus, sig * postGain);
173 }).add;
175 SynthDef("order-of-ex-pulse", { arg freq, bus, ffreq, pan, lfobus;
176         var sig, noteLen;
177         noteLen = In.kr(lfobus, 1);
178         sig = RLPF.ar(Pulse.ar(freq, 0.2, 0.5), ffreq, 0.3);
179         Out.ar(bus, Pan2.ar(sig, pan)
180                 * EnvGen.kr(Env.perc(0.1, 1), timeScale: noteLen, doneAction: 2));
181 }).add;
183 SynthDef("LFNoise1", { arg freq, mul, add, bus;
184         Out.kr(bus, LFNoise1.kr(freq, mul:mul, add:add));
185 }).add;
188 // Place LFO:
190 ~lfo = Synth.head(s, "LFNoise1", [\freq, 0.3, \mul, 0.68, \add, 0.7, \bus, l]);
192 // Then place your effect:
194 ~dist = Synth.tail(~fxgroup, "order-of-ex-dist", [\bus, b, \preGain, 8, \postGain, 0.6]);
196 // transfer the results to main out, with level scaling
197 // play at tail of s's default group (note that Function-play also takes addActions!
199 ~xfer = { Out.ar(0, 0.25 * In.ar(b, 2)) }.play(s, addAction: \addToTail);
201 // And start your routine:
204 r = Routine({
205         {
206                 Synth.tail(~synthgroup, "order-of-ex-pulse",
207                         [\freq, rrand(200, 800), \ffreq, rrand(1000, 15000), \pan, 1.0.rand2,
208                         \bus, b, \lfobus, l]);
209                 0.07.wait;
210         }.loop;
211 }).play(SystemClock);
214 ~dist.run(false);       // proves that the distortion effect is doing something
215 ~dist.run(true);
217 // to clean up:
219 r.stop;
220 [~synthgroup, ~fxgroup, b, l, ~lfo, ~xfer].do({ arg x; x.free });
221 currentEnvironment.clear; // clear all environment variables
224 Note that in the routine, using a Group for the source synths allows their order to easily be specified relative to each other (they are added with the .tail method), without worrying about their order relative to the effect synth.
226 Note that this arrangement prevents errors in order of execution, through the use of a small amount of organizational code. Although straightforward here, this arrangement could easily be scaled to a larger project.
229 subsection:: Messaging Style
231 The above examples are in 'object style'. Should you prefer to work in 'messaging style' there are corresponding messages to all of the methods shown above. See NodeMessaging, and Server-Command-Reference for more details.
234 section:: Feedback
236 When the various output ugens (Out, OffsetOut, XOut) write data to a bus, they mix it with any data from the current cycle, but overwrite any data from the previous cycle. (ReplaceOut overwrites all data regardless.)
237 Thus depending on node order, the data on a given bus may be from the current cycle or be one cycle old. In the case of input ugens (see In and InFeedback) In.ar checks the timestamp of any data it reads in and zeros any data from the previous cycle (for use within that synth; the data remains on the bus).
238 This is fine for audio data, as it avoids feedback, but for control data it is useful to be able to read data from any place in the node order. For this reason In.kr also reads data that is older than the current cycle.
240 In some cases we might also want to read audio from a node later in the current node order. This is the purpose of InFeedback. The delay introduced by this is at maximum one block size, which equals about 0.0014 sec at the default block size and sample rate.
242 The variably mixing and overwriting behaviour of the output ugens can make order of execution crucial when using In.kr or InFeedback.ar. (No pun intended.) For example with a node order like the following the InFeedback ugen in Synth 2 will only receive data from Synth 1 (-> = write out; <- = read in):
243 numberedlist::
244 ## Synth 1 -> busA (this synth overwrites the output of Synth3 before it reaches Synth 2)
245 ## Synth 2 (with InFeedback) <- busA
246 ## Synth 3 -> busA
248 If Synth 1 were moved after Synth 2 then Synth 2's InFeedback would receive a mix of the output from Synth 1 and Synth 3. This would also be true if Synth 2 came after Synth1 and Synth 3.
249 In both cases data from Synth 1 and Synth 3 would have the same time stamp (either current or from the previous cycle), so nothing would be overwritten.
251 (As well, if any In.ar wrote to busA earlier in the node order than Synth 2, it would zero the bus before Synth 3's data reached Synth 2. This is true even it there were no node before Synth 2 writing to busA.)
253 Because of this it is often useful to allocate a separate bus for feedback. With the following arrangement Synth 2 will receive data from Synth3 regardless of Synth 1's position in the node order.
254 numberedlist::
255 ## Synth 1 -> busA
256 ## Synth 2 (with InFeedback) <- busB
257 ## Synth 3 -> busB + busA
259 The following example demonstrates this issue with In.kr:
260 code::
262 SynthDef("help-Infreq", { arg bus;
263         Out.ar(0, FSinOsc.ar(In.kr(bus), 0, 0.5));
264 }).add;
266 SynthDef("help-Outfreq", { arg freq = 400, bus;
267         Out.kr(bus, SinOsc.kr(1, 0, freq/40, freq));
268 }).add;
270 b = Bus.control(s,1);
273 // add the first control Synth at the tail of the default server; no audio yet
274 x = Synth.tail(s, "help-Outfreq", [\bus, b]);
276 // add the sound producing Synth BEFORE it; It receives x's data from the previous cycle
277 y = Synth.before(x, "help-Infreq", [\bus, b]);
279 // add another control Synth before y, at the head of the server
280 // It now overwrites x's cycle old data before y receives it
281 z = Synth.head(s, "help-Outfreq", [\bus, b, \freq, 800]);
283 // get another bus
284 c = Bus.control(s, 1);
286 // now y receives x's data even though z is still there
287 y.set(\bus, c); x.set(\bus, c);
289 x.free; y.free; z.free;