Syn:
Filter:
ddwPlug/Classes (extension) | Server > Nodes | Server > Abstractions

Syn
ExtensionExtension

Dynamically patchable Synth alternative

Description

Syn is like Synth in that it instantiates a SynthDef as a synth node in a server.

The argument list to a Synth may assign only numbers, or arrays of numbers, to a control name.

The argument list to a Syn may also include Plug objects, which patch signals from other SynthDefs to the synth input automatically.

Syn is designed for polyphony. When a Syn releases, all of its resources (auxiliary synth nodes for input signals, and control or audio buses) are freed up to be reused. Using the \syn event type (see Event types), an event pattern can play a sequence of Syn objects, where every network of synths is independent.

(JITLib also supports on-the-fly dynamic patching, but its support for polyphony appears to be limited. You can copy a NodeProxy, but AFAICS this does not copy its connections to other NodeProxies. JITLib's focus is on interaction; Syn's focus is replicable structure.)

Node structure

A Syn creates a flat list of nodes, arranged in order so that Plugs feeding into inputs come first.

Node 1000 is created first, using the given target and addAction. Subsequent nodes are added immediately after the previous one.

release-ing the Syn cascades through all the other objects, freeing them as well.

Buses are allocated and released automatically. In the above example, the Plug function returns one kr channel, and the single kr bus matches the single kr freq input defined by the default SynthDef.

If you need to use Syn with supernova, make sure to configure the following:

With this option enabled, each Syn will create its own Group (not ParGroup!) to maintain processing order. Syn Groups may be placed into a ParGroup for parallel processing.

Events

Syn defines the following event types:

syn
Analogous to \note, except that it creates a Syn object for each note (including multichannel expansion).
synOn
Analogous to \on.
synOff
Analogous to \off.
synSet
Analogous to \set. (Note that the arguments to set must be specified in an args array.)

Plugs may be generated dynamically by event keys ending in "Plug" -- see examples below.

NOTE: Pmono and PmonoArtic require a wrapper object, Pmsyn, to be able to use Plug inputs.

Limitations

Feedback between Plugs is not supported.

While it is supported to define Plugs based on a synthesis function, and Syn will attempt to maintain timing according to latency, a very complex Syn with a large number of function-based Plugs may take too long to prepare. For efficiency, it is recommended to use SynthDefs as much as possible in production settings.

However (new as of April 2025), Plugs based on functions will attempt to cache and reuse their temporary SynthDefs. This will improve efficiency of, for instance, patterns using function-based Plugs. See Plug: Plugs based on Functions.

Class Methods

.new

Create and perform a new Syn.

Arguments:

source

A SynthDef name (string or symbol), or a Function, specifying the main output signal.

args

A Synth-style argument list: [name, value, name, value...].

target

The node relative to which this Syn's nodes will be created.

addAction

One of \addToHead, \addToTail, \addBefore or \addAfter.

latency

Server messaging latency to specify when the sound should hit the speakers. nil means "as soon as possible."

Returns:

A playing Syn instance.

.newByArgPaths

Like *new, but accepts a list of argument paths and values applying to the entire Syn-Plug complex.

See Setting controls examples below.

Arguments:

source

A SynthDef name (string or symbol), or a Function, specifying the main output signal.

args

A Synth-style argument list, where names may be paths to Plug inputs in the tree: [name, value, name, value...].

target

The node relative to which this Syn's nodes will be created.

addAction

One of \addToHead, \addToTail, \addBefore or \addAfter.

latency

Server messaging latency to specify when the sound should hit the speakers. nil means "as soon as possible."

Returns:

A playing Syn instance.

.basicNew

Create a new Syn, but don't perform it.

Arguments:

source

A SynthDef name (string or symbol), or a Function, specifying the main output signal.

args

A Synth-style argument list: [name, value, name, value...].

target

The node relative to which this Syn's nodes will be created.

addAction

One of \addToHead, \addToTail, \addBefore or \addAfter.

Returns:

An idle Syn instance.

.basicNewByArgPaths

Create a new Syn with path-style arguments (see Syn: *newByArgPaths, but don't perform it.

Arguments:

source

A SynthDef name (string or symbol), or a Function, specifying the main output signal.

args

A Synth-style argument list, where names may be paths to Plug inputs in the tree: [name, value, name, value...].

target

The node relative to which this Syn's nodes will be created.

addAction

One of \addToHead, \addToTail, \addBefore or \addAfter.

Returns:

An idle Syn instance.

.useGroup

If true, each Syn will place its nodes into a dedicated group. If false, nodes go directly into the parent group. Default is false.

Instance Methods

Playing an idle instance

The following methods use OSCBundle because preparation messages may be needed.

.play

Generates and sends an OSC bundle for a Syn.basicNew.

Arguments:

latency

Server messaging latency defining the time when the sound should hit the speakers.

.prepareToBundle

Produce an OSCBundle object containing the messages required to perform the object.

Arguments:

bundle

Optional. An OSCBundle object.

Returns:

An OSCBundle.

.sendBundle

Given an OSCBundle, perform it at the time specified by latency.

Arguments:

bundle

An OSCBundle object created by prepareToBundle.

latency

Server messaging latency defining the time when the sound should hit the speakers.

Control

The following methods use a plain List for bundling.

.release

As in Synth: -release, send gate-set messages to cause sustaining envelopes to release. When the primary node(s) are removed, Syn will also release auxiliary resources.

Arguments:

latency

Server messaging latency defining the time to begin the release.

gate

The gate value to set. Numbers less than -1.0 will trigger a forced release (see EnvGen).

.releaseToBundle

Construct a bundle (List) of all the messages required to release this Syn.

Arguments:

bundle

A List or nil.

gate

The gate value to set. Numbers less than -1.0 will trigger a forced release (see EnvGen).

Returns:

The bundle, as a List.

.free

Send /n_free messages to hard-stop this Syn.

Arguments:

latency

Server messaging latency defining the time to free the nodes.

... why

Optional. An annotation. Mainly intended for debugging purposes.

.freeToBundle

Construct a bundle (List) of all the messages required to hard-stop this Syn.

Arguments:

bundle

A List or nil.

Returns:

The bundle, as a List.

.set

Set controls in the Syn.

A control input may receive a signal from another synth node. This synth node may itself have control inputs. These may be accessed using a path-style syntax: 'freq/rate' would set the rate parameter belonging to the Plug supplying the frequency to the main synth.

NOTE: If a control is assigned a Plug, then .set can replace the plug with a new Plug, but it cannot remove the Plug and replace it with a fixed number. See Setting controls and Three-point modulation below.

Arguments:

... args

Path-value pairs.

.setToBundle

Adds "set" messages into a bundle, for later sending.

Arguments:

bundle

Optional. A List of OSC messages. If not provided, one will be created for you.

... args

Name-value pairs.

Returns:

A List of OSC messages.

.setn

Set arrayed controls in the Syn.

Arguments:

... args

Name-value pairs.

.setnToBundle

Adds "setn" messages into a bundle, for later sending.

Arguments:

bundle

Optional. A List of OSC messages. If not provided, one will be created for you.

... args

Name-value pairs.

Returns:

A List of OSC messages.

.cleanup

Force the Syn's associated objects to clean themselves up, without actually sending a free message to the main Syn node. Normally, there is no need to call this method directly; however, cleanupToBundle is useful for non-real-time rendering.

.cleanupToBundle

Performs a cleanup operation, and captures all of the OSC messages into an OSCBundle. These messages may then be added into a NRT Score. See examples.

Arguments:

bundle

Optional. An OSCBundle. If omitted, an OSCBundle will be created for you, and returned.

Returns:

An OSCBundle containing cleanup messages.

Ordering

.moveToHead

Behaves like Node: -moveToHead.

Arguments:

group

.moveToTail

Behaves like Node: -moveToTail.

Arguments:

group

.moveBefore

Behaves like Node: -moveBefore.

Arguments:

aNode

.moveAfter

Behaves like Node: -moveAfter.

Arguments:

aNode

Parameter getters

.source

The Syn's source. Currently a string or symbol specifies an existing SynthDef, or a Function can create a SynthDef on-the-fly.

.args

The argument list.

.argAt

Access a given argument value only for the top-level Syn. This method does not look into child Plug arguments.

Arguments:

key

A Symbol identifying the argument to look up.

.argAtPath

Access a given argument value anywhere in the object tree.

Arguments:

path

A string or symbol locating a parameter, using the same syntax as in -set.

Returns:

An argument value, or Plug object.

.objectForPath

Finds the object to which a plug or other input belongs. Normally you should not need to call this directly. It is used when set() replaces a Plug: the old Plug's owner object is responsible for completing this operation.

Arguments:

path

A string or symbol locating a parameter, using the same syntax as in -set.

Returns:

The owner object of the given parameter.

.target

The existing node relative to which the Syn was created.

.addAction

One of \addToHead, \addToTail, \addBefore or \addAfter.

.server

The server on which the Syn is running. (Note that this is not specified directly, but derived from target.)

.rate

Calculation rate, either \control or \audio.

.bundleTarget

Mainly for private use. This method returns an array consisting of either [target, addAction] or (in "group" style) [group, \addToTail].

Structure

.node

The top-level synth node.

Returns:

A Synth node.

.group

If group-style node ordering has been chosen, this is the Syn's dedicated Group.

.antecedents

An IdentitySet of Plugs feeding into the main synth node. (These Plugs may themselves have antecedents -- that is, you can use the antecedents collections to iterate over the entire tree.)

.dest

The owner Syn -- i.e., this.

.allNodes

A LinkedList of all Synth nodes controlled by this Syn.

Examples

Shared Plugs

By default, a Plug copies itself before rendering. It's assumed that, wherever a Plug is used, its signal should be unique. Here, the three notes will be modulated by independent random curves.

Creating a Plug.shared will render one signal only for this object, which may be read in multiple places.

Setting controls

Synth: -set is simple because there is a one-to-one relationship between the Synth object and the synth node in the server.

A Syn can represent multiple nodes, so there needs to be a way to address set messages to specific nodes in the tree. Also, if a control is mapped onto a Plug, setting it will break the connection, and it can be difficult to recover.

Syn uses a path-style syntax to locate controls:

This Syn has three nodes, which are effectively nested:

To set the main synth's 'amp' parameter, use x.set(\amp, 0.1).

To set the frequency range of the Plug controlling 'freq': x.set("freq/low", 500, "freq/high", 1200). (Note that there is no leading slash.)

To set the innermost Plug, continue adding to the path: "freq/rate/rate", "freq/rate/low" etc.

Syn.newByArgPaths supports "set"-style path arguments at Syn creation time. For example, all of the following are equivalent to x above.

The redundancy in the multiple paths might be cumbersome to type manually, but in some cases may be more convenient to generate programmatically.

What if you try x.set(\freq, 300)? "freq" is mapped to a Plug. Setting it to a fixed value would break the modulation. Instead, Syn will try to push the freq set down to a lower level Plug, if possible. In this case, the Plug synth has no 'freq' input, so nothing will happen. If it did have a 'freq' input, then it would be set at the second level.

There is a reason for this:

Three-point modulation

In three-point modulation, there are three values to consider:

base
The parameter's value without modulation.
source
The modulator signal. Commonly an LFO or envelope.
depth
AKA width: how far to deviate from the base.

For Event use, however, it is inconvenient to set the base frequency as "freq/base". Events expect to address frequency as "freq". This is why .set will pass values down into the Plug tree. Plug's map parameter can change the control name to which passed-down values are sent.

Events and "xxxPlug" keys

In the previous example, you have direct control over the Syn's structure. An Event creates Syn objects for you. This poses a problem: How to specify a parameter's baseline value using normal pattern calculations, and apply Plug modulation to it?

The \syn and \synOn event types look for event values ending in Plug:

\degree will control the default SynthDef's freq input, to which a "freqPlug" may be applied. This is given as a function to be evaluated per event. The function argument comes from the event being processed (see Function: -valueEnvir). In this function, you can create a Plug with any structure you want. Here, the frequency is passed in an arg list, and modulated in the standard way.

NOTE: Pmono and PmonoArtic require a wrapper object, Pmsyn, to be able to use Plug inputs.

NRT (Non-Real-Time)

The NRT interface at this point is not especially convenient, but it is possible to use xxxToBundle methods to capture OSC messaging, and at the messages one by one into a Score.

NOTE: After releasing a Syn, always -cleanupToBundle and add the messages after the node's envelope release time. In real time use, this cleanup is performed automatically when the Syn node ends. In NRT, there is no existing node to track. It then becomes your responsibility to know how long your Syn will take to release, and do the cleanup yourself. (If this is not done, then OSCFunc and object dependencies will accumulate, eventually slowing down the sclang interpreter.)

Repatching

Plugs' sources can be changed on the fly, without disrupting the structure. To do this, access the Plug object using -argAtPath and call Plug: -source on it.

Alternately, new Plugs may be introduced at any time through the standard -set interface. If there was already a Plug in that location, the old Plug and all of its upstream Plugs will be removed.