class library: quit internal server on class library compilation
[supercollider.git] / HelpSource / Guides / Spawning.schelp
blob0e505efe41663db409c8fa42050cf5d03bcf9ee4
1 title:: "Spawning" and "TSpawning"
2 summary:: The lack of the Spawn and TSpawn UGens and their various convienence classes
3 categories:: SC3 vs SC2
5 In SC2, Spawn and TSpawn were two of the most powerful and commonly used UGens. In SC3 the idea of a top level Synth in which everything is spawned is no longer valid. Synthesis is always running (at least as long as a server is) and new Synths can be created on the fly. This arrangement results in even greater flexibility than in SC2, but requires a slightly different approach.
7 In SC3 one can create Synths at any time simply by executing blocks of code.
9 code::
10 // do this
12 x = SynthDef("Help-SynthDef", { arg out = 0;
13         Out.ar(out, PinkNoise.ar(0.1))
14 }).play; // SynthDef-play returns a Synth object.
17 // then do this
19 SynthDef("help-Rand", { arg out = 0;
20         Out.ar(
21                 out,
22                 FSinOsc.ar(
23                         Rand(200.0, 400.0), // frequency between 200 and 400 Hz
24                         0, Line.kr(0.2, 0, 1, doneAction:2) // frees itself
25                 )
26         )
27 }).play(s);
30 x.free;
33 Clocks, such as link::Classes/SystemClock::, provide a way to schedule things at arbitrary points in the future. This is similar to code::Synth.sched:: in SC2.
35 code::
37 SystemClock.sched(2.0, {
38         "2.0 seconds later".postln; // this could be any code, including Synth creation
39         nil // this means don't repeat
40 });
44 In SC3 time-based sequences of events can be implemented using Routines. A link::Classes/Routine:: which yields a number can be scheduled using a clock:
46 code::
48 var w, r;
50 w = Window.new("trem", Rect(512, 256, 360, 130));
51 w.front;
53 r = Routine({ arg time;
54         60.do({ arg i;
55                 0.05.yield; // wait for 0.05 seconds
56                 {
57                         w.bounds = w.bounds.moveBy(10.rand2, 10.rand2);
58                         w.alpha = cos(i*0.1pi)*0.5+0.5;
59                 }.defer;
60         });
61         1.yield; // wait for 1 second before closing w
62         w.close;
63 });
65 SystemClock.play(r);
69 Note that this implementation avoids one of the stranger aspects of the SC2 approach: The need to start a Synth to schedule time-based behavior, even if no audio is involved.
71 Both link::Classes/SystemClock:: and link::Classes/AppClock:: (a less accurate version which can call Cocoa primitives) have only class methods. Thus one does not create instances of them. If you need to have an individual clock to manipulate (for instance to manipulate the tempi of different sequences of events) you can use link::Classes/TempoClock::.
73 A simple SC2 Spawn example is shown below, followed by its translation into SC3 style code.
75 code::
76 // This will not execute in SC3
78 Synth.play({
79         Spawn.ar(
80                 { EnvGen.ar(Env.perc) * SinOsc.ar(440,0,0.1) },
81                 1, // one channels
82                 1 // new event every second
83         )
87 // The same example in SC3 (will execute)
89 s = Server.default;
90 s.boot;
94 SynthDef("help-EnvGen",{ arg out = 0;
95         Out.ar(
96                 out,
97                 EnvGen.kr(Env.perc,1.0,doneAction: 2) * SinOsc.ar(440,0,0.1)
98         )
99 }).send(s);
103 r = Routine.new({ { Synth.new("help-EnvGen"); 1.yield; }.loop }); // loop every one second
104 SystemClock.play(r);
108 Note that the above example uses a precompiled link::Classes/SynthDef::. This results in a lower CPU spike when Synths are created than SC2-style Spawning. It is possible to create SynthDefs on the fly, if this is necessary, but a great deal of variation can be achieved with arguments, or with UGens such as link::Classes/Rand:: and link::Classes/TRand::. See the section link::Overviews/SC3vsSC2#SynthDefsVsSynths:: for more detail.
110 code::
111 // SynthDefs on the fly
113 s = Server.default;
114 s.boot;
118 t = TempoClock.new;
119 r = Routine.new({
120         10.do({
121                 // could be done with an argument instead of a new def, but proves the point
122                 SynthDef("help-EnvGen" ++ i, { arg out = 0;
123                         Out.ar(
124                                 out,
125                                 EnvGen.kr(Env.perc, 1.0, doneAction: 2)
126                                 * SinOsc.ar(100 + (100 * t.elapsedBeats), 0, 0.1)
127                         )
128                 }).play(s);
129                 1.yield;
130         });
131 }).play(t); // Note the alternative syntax: Routine.play(aClock)
135 Note the alternative syntax for playing a Routine. code::aClock.play(aRoutine):: and code::aRoutine.play(aClock):: are functionally equivalent. The two make different things more or less convenient, like sending messages to the link::Classes/Routine:: or link::Classes/Clock::. (See the play helpfile for a more detailed discussion.) For instance:
137 code::
139 // this, that and the other
140 r = Routine.new({var i = 0; { ("this: " ++ i).postln; i = i + 1; 1.yield; }.loop });
141 q = Routine.new({var i = 0; { ("that: " ++ i).postln; i = i + 1; 1.yield; }.loop });
142 t = Routine.new({var i = 0; { ("the other: " ++ i).postln; i = i + 1; 1.yield; }.loop });
145 SystemClock.play(r);    // start this
146 SystemClock.play(q);    // start that
147 SystemClock.play(t);    // start the other
149 r.stop;                 // stop this but not that or the other
150 q.reset;                // reset that while playing
152 c = TempoClock.new;     // make a TempoClock
153 r.reset;                // have to reset this because it's stopped
154 c.play(r);              // play this in the new clock; starts from the beginning
155 c.tempo = 16;           // increase the tempo of this
157 SystemClock.clear;      // clear EVERYTHING scheduled in the SystemClock; so that and the other
158                         // but not this
160 c.clear;                // clear everything scheduled in c, i.e. this
161 c.play(r);              // since it wasn't stopped, we don't have to reset this
162                         // and it picks up where it left off
164 c.stop;                 // stop c, destroy its scheduler, and release its OS thread
167 For convenience pauseable scheduling can be implemented with a link::Classes/Task::. code::Task.new:: takes two arguments, a function and a clock, and creates it's own link::Classes/Routine::. If you don't specify a clock, it will create a link::Classes/TempoClock:: for you. Since you don't have to explicitly create a link::Classes/Clock:: or link::Classes/Routine::, use of link::Classes/Task:: can result in code that is a little more compact.
169 code::
171 t = Task.new({
172         inf.do({ arg i;
173                 i.postln;
174                 0.5.wait
175         });
179 t.start;                // Start it
180 t.stop;                 // Stop it
181 t.start;                // Start again from the beginning
182 t.reset;                // Reset on the fly
183 t.stop;                 // Stop again
184 t.resume;               // Restart from where you left off
185 t.clock.tempo = 0.25;   // Get the Task's clock and change the tempo. This works since the
186                         // default is a TempoClock.
187 t.pause;                // Same as t.stop
190 TSpawn's functionality can be replicated with link::Classes/SendTrig:: and link::Classes/OSCFunc::. See their individual helpfiles for details on their arguments and functionality.
192 code::
194 s = Server.default;
195 s.boot;
199 // this Synth will send a trigger to the client app
200 SynthDef("help-SendTrig", {
201         SendTrig.kr(
202                 Dust.kr(1.0), // trigger could be anything, e.g. Amplitude.kr(SoundIn.ar(0) > 0.5)
203                 0, 0.9
204         );
205 }).send(s);
209 // this receives the trigger on the client side and 'Spawns' a new Synth on the server
210 OSCFunc({
211         SynthDef("help-EnvGen", { arg out = 0;
212                 Out.ar(
213                         out,
214                         EnvGen.kr(Env.perc, 1.0, doneAction: 2)
215                         * SinOsc.ar(440, 0, 0.1)
216                 )
217         }).play(s);
218 }, '/tr', s.addr);
220 // Start 'spawning'
221 Synth("help-SendTrig");