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.
In SC3 one can create Synths at any time simply by executing blocks of code.
Clocks, such as SystemClock, provide a way to schedule things at arbitrary points in the future. This is similar to
Synth.sched in SC2.
In SC3 time-based sequences of events can be implemented using Routines. A Routine which yields a number can be scheduled using a clock:
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.
Both SystemClock and 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 TempoClock.
A simple SC2 Spawn example is shown below, followed by its translation into SC3 style code.
Note that the above example uses a precompiled 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 Rand and TRand. See the section SuperCollider 3 versus SuperCollider 2: SynthDefsVsSynths for more detail.
Note the alternative syntax for playing a Routine.
aRoutine.play(aClock) are functionally equivalent. The two make different things more or less convenient, like sending messages to the Routine or Clock. (See the play helpfile for a more detailed discussion.) For instance:
For convenience pauseable scheduling can be implemented with a Task.
Task.new takes two arguments, a function and a clock, and creates it's own Routine. If you don't specify a clock, it will create a TempoClock for you. Since you don't have to explicitly create a Clock or Routine, use of Task can result in code that is a little more compact.