Product SiteDocumentation Site

11.3.12. Ordering and Other Synth Features

This section discusses the important topic of creating and enforcing an "order" on the server. Because this is done with Functions (or methods) from the Synth Class, other useful Functions from the Class are discussed here.

11.3.12.1. Ordering

Ordering is instructing the server to calculate in a particular order. The audio synthesized by the server takes the same form as any other digital audio: a series of samples are played at a particular speed (called sample rate), each with a set number of bits per sample (called sample format). For each sample, the server calculates the signal at that point in a pre-determined order. Each sample is calculated from scratch, so if a particular UGen depends on the output of another UGen, the other one had better be calculated first. For more information on samples, sample rate, and sample format, see Section 1.3, “Sample, Sample Rate, Sample Format, and Bit Rate”.
Consider the following example:
{ SinOsc.ar( freq:SinOsc.kr( freq:1, add:500, mul:10 ), mul:0.2 ); }.play;
What happens if the server calculates the audio-rate UGen first? It wouldn't have a frequency. This is another one of those things which the interpreter takes care of automatically when we run Function rather than create a Synth. Since it's often preferable to use a synth instead of a Function, we need some way to control the order of execution. The interpreter and the server are only so good at guessing what we need, after all.
There are two methods in the Synth Class that we can use to inform the server about our desired order of execution: "before" and "after". They represent a small extension to the "new" method, and they work like this:

Synth.before(variableHoldingSynth, nameOfSynthDef, ListOfArguments);

and

Synth.after(variableHoldingSynth, nameOfSynthDef, ListOfArguments);

And it works just as it looks, too: the server creates a new synth, adds it before or after the synth represented by "variableHoldingSynth" (depending on which Function you use), and uses "nameOfSynthDef" and "ListOfArguments" just as in the "add" method. This example, from Section 11.3.11.4, “Using Busses: Control-Rate Example”, uses the "after" Function to ensure that the control-rate synth is calculated before the audio-rate synths that depend on it.
( // execute first: prepare the server
   var busAudioSynth = 
   {
      arg bus, freqOffset = 0;
      
      Out.ar( 0, SinOsc.ar( freq:( In.kr(bus) + freqOffset ), mul:0.1 ) );
   };
   
   var busControlSynth =
   {
      arg bus, freq = 400;
      
      Out.kr( bus, SinOsc.kr( freq:1, mul:( freq/40 ), add:freq ) );
   };
   
   SynthDef( \tutorialAudioBus, busAudioSynth ).send( s );
   SynthDef( \tutorialControlBus, busControlSynth ).send( s );
   
   b = Bus.control( s );
)

( // execute second: create synths
   x = Synth.new( \tutorialControlBus, [\bus, b] ); // control synth
   y = Synth.after( x, \tutorialAudioBus, [\bus, b] ); // low audio synth
   z = Synth.after( x, \tutorialAudioBus, [\bus, b, \freqOffset, 200] ); // high audio synth
)

( // commands to free each Object
   x.free; x = nil; // control synth
   y.free; y = nil; // low audio synth
   z.free; z = nil; // high audio synth
   b.free; b = nil; // control bus
)
In this case, the control-rate synth is created before the audio-rate synths - probably the easier way to think about it. Even so, it's possible to add them in the opposite order with a little extra thought.
The other example from Section 11.3.11, “Busses” use the "before" Function to ensure that the "pink noise" and "sine wave" UGen's were calculated before the "reverberation" UGen. Especially since these are all audio-rate UGen's, the server would not reasonably know which to calculate first, so you need to let it know.