The server application uses synth definitions as templates for creating Synth nodes. (Methods such as Function: -play, etc. are simply conveniences which automatically create such a def.) The SynthDef class encapsulates the client-side representation of a given def, and provides methods for creating new defs, writing them to disk, and streaming them to a server.
SynthDef is one of the more complicated classes in SC and an exhaustive explanation of it is beyond the scope of this document. As such, the examples at the bottom of this document and those found in the various tutorials accessible from Help may be necessary to make some aspects of its use clear.
Some insights about common SynthDef issues can be found on the FAQ SynthDef Issues
The core of a def is its unit generator graph function. This is an instance of Function which details how the def's unit generators are interconnected, its inputs and outputs, and what parameters are available for external control. In a synth based on the def, arguments to the function will become instances of Control. These can have default values, or can be set at the time the synth is created. After creation they will be controllable through Node's set
and setn
methods, or the n_set and n_setn OSC messages.
There are four special types of arguments, which are treated differently:
a_input
), or that are specified as \ar
in the def's rates argument (see below), will be able to read an audio rate bus when mapped to it with /n_mapa
.i_freq
), or that are specified as \ir
in the def's rates argument (see below), will be static and non-modulatable. They will not respond to /n_set
or /n_map
. This is slightly more efficient in terms of CPU than a regular arg.t_trig
), or that are specified as \tr
in the def's rates argument (see below), will be made as a TrigControl. Setting the argument will create a control-rate impulse at the set value. This is useful for triggers./n_setn
.See the examples below for more detail on how this works.
Certain argument names (such as 'out' to specify an out bus) are in such common use that adopting them might be said to constitute 'good style'. One of these, 'gate' when used to control the gate input of an EnvGen, deserves special mention, as it allows one to use Node's release method. See Node for an example and more detail.
In some cases, it is useful to send a group of values to a single control name, for instance, aSynth.set(\freqs, [300, 400, 500])
, or for passing envelopes at Synth instantiation. This requires an arrayed control to be defined in the SynthDef.
There are two ways to define arrayed controls:
NamedControl can accept default values determined in code. For example, passing an envelope requires four values per breakpoint. It is easy to create a template for the arrayed control by writing NamedControl.kr(\env, Env.newClear(numSegments: 8).asArray)
.
Literal arrays may be more convenient for very small arrays where all of the default values are known in advance.
In general, it is likely to be simpler in most cases to use NamedControl for arrayed controls.
See the example under Array Arguments.
It is important to understand that although a single def can provide a great deal of flexibility through its arguments, etc., it is nevertheless a static entity. A def's UGen graph function (and the SC code within it) is evaluated only when the def is created. Thus statements like while, do, collect etc. will have no further effect at the time the def is used to create a Synth, and it is important to understand that a UGen graph function should not be designed in the same way as functions in the language, where multiple evaluations can yield different results. It will be evaluated once and only once.
if
is implemented as a linear signal crossfade when the receiver is an UGenThere are other ways of achieving similar results, however, often using UGens such as Rand. For example, the following def will have a single randomly generated frequency, which will be the same for every Synth based on it:
This one on the other hand will have a different random freq for each Synth created:
Create a SynthDef instance, evaluate the ugenGraphFunc and build the ugenGraph.
name |
A String or Symbol (i.e. "name" or \name). This name will be used to refer to the SynthDef when creating a Synth based upon it, and should be unique. |
ugenGraphFunc |
An instance of Function specifying how the def's UGens are interconnected. See the discussion above for information on how the Function's arguments are specified. |
rates |
An optional Array of specifications for the ugenGraphFunc's arguments. The order corresponds to the order of arguments. See the examples below to see how these are used. A specification can be:
|
prependArgs |
An optional Array of objects which will be passed as the first arguments to the ugenGraphFunc when it is evaluated. Arguments which receive values in this way will not be converted to instances of Control. See the |
variants |
An optional Event containing default argument settings. These can override the defaults specified in the ugenGraphFunc. When creating a Synth a variant can be requested by appending the defName argument in the form 'name.variant' or "name.variant". See example below. |
metadata |
An optional Event containing additional, user-defined information that is relevant to the use of the SynthDef in the client. The SynthDef itself is sent to the server for audio rendering; metadata are strictly client-side descriptive information. Currently the 'specs' key in the event is reserved for ControlSpecs to be associated with SynthDef arguments (this is useful for automatic GUI construction). Metadata can be persisted to disk and loaded automatically as part of a SynthDesc. See the SynthDesc help file for more details. |
Wraps a function within an enclosing synthdef.
Arguments to the wrapped function are automatically promoted to be SynthDef controls, using the same rules applied to arguments of the main UGen function. For a very simple example:
Prints: [ ControlName P 0 out control 0, ControlName P 1 freq control 0 ]
.
The outer function declares the argument 'out', and the wrapped function has 'freq' as its argument. The resulting SynthDef has both arguments as controls, exactly as if the outer function included both as arguments.
The rates array behaves as described earlier. PrependArgs
allows values or unit generators to be passed into the inner function from the enclosing SynthDef context. Any inner function argument that receives a prependArg value (including nil) will use that value, suppressing creation of a control for that argument. The longer example below demonstrates this technique.
This is very useful for mass-producing SynthDefs that have a common "shell" defining features such as enveloping or triggering mechanisms that apply to different subgraphs of unit generators. The common features need be written only once; the UGens that differ between the SynthDefs are plugged into the supporting architecture.
Get or set the default directory to which defs are written.
Remove the synthdef name
from the SynthDescLib named libname
and from its servers.
Create a new SynthDef. It is written to disk only if a def file with this name does not already exist. Note that this will not check for differences, so you will need to delete the defFile to get it to rebuild. Default for dir is to use the path specified by SynthDef.synthDefDir
.
SynthDef.writeOnce
is a legacy method. Its main use was to improve the efficiency of SynthDefs in quarks, but this is superseded by SynthDescLib. Being completely impervious to changes, it can cause difficult-to-diagnose bugs (such as having version 1.1 of a quark but with a SynthDef stuck in version 1.0). Quark developers should now use -add instead.
The exception is very large SynthDefs, where you have a choice between -writeDefFile and this method. Even then, the efficiency savings of writeOnce
are only in disk I/O -- both methods build the SynthDef every time they run.
When a SynthDef is too large to be sent to a local server in a standard OSC message, it is written to disk and the server loads it from there instead. If warnAboutLargeSynthDefs
is set to true, it will warn that this is happening. There will always be a warning for remote servers.
Adds the synthdef to the SynthDescLib specified by libname, and sends it to the library's servers. No defFile is written; all operations take place in memory.
After using this method, the synthdef can be used with event streams as in store()
, but without the permanent artifact of a file on disk. Calling this method triggers an update message with the key \synthDescAdded
for any dependants the library may have. This can be used to trigger additional behaviour every time a def/desc is added. See Object: Dependancy.
A server can be added by SynthDescLib.global.addServer(server)
.
Note that the "dir" and "mdPlugin" arguments do not exist for this method. Because no file is written, there is no need to specify a directory or write a metadata file.
Return this def's name.
Return this def's ugenGraphFunc.
Return an Event containing this def's variants.
An array of ControlName's for the controls.
A Dictionary of ControlSpecs for a SynthDef. Equivalent to: d.metadata[\specs]
(for most purposes, the method add is recommended)
Writes the def as a file called name.scsyndef in a form readable by a server. Default for dir is synthdefs/. Defs stored in the default directory will be automatically loaded by the local and internal Servers when they are booted.
Write the defFile and send a message to server to load this file. When this asynchronous command is completed, the completionMessage (a valid OSC message) is immediately executed by the server. Default for dir is synthdefs/.
Compile the def and send it to server without writing to disk (thus avoiding that annoying SynthDef buildup). When this asynchronous command is completed, the completionMessage (a valid OSC message) is immediately executed by the server.
Write the defFile and store it in the SynthDescLib specified by libname, and send a message to the library's server to load this file. When this asynchronous command is completed, the completionMessage (a valid OSC message) is immediately executed by the server. Default for libname is \global, for dir is synthdefs/. This is needed to use defs with the event stream system. See Streams and Pattern.
libname |
name of the SynthDescLib |
dir | |
completionMsg | |
mdPlugin |
(optional) The metadata plug-in class that will be used to persist metadata. If not supplied, the default plug-in is used. See the SynthDesc help file for details. |
A convenience method which compiles the def and sends it to target's server. When this asynchronous command is completed, it creates one synth from this definition, using the argument values specified in the Array args. For a list of valid addActions see Synth. The default is \addToHead
.
a corresponding Synth object.
Sometimes, it can be clearer to specify a ControlSpec for a parameter at the point of its usage in a SynthDef, rather than elsewhere. Specs can be set either when contructing a NamedControl or as a property of a SynthDef argument.