SuperCollider CLASSES

# Server

Object representing an sc-server application
Source: /Applications/SuperCollider/SuperCollider.app/Contents/Resources/SCClassLibrary/Common/Control/Server.sc
Inherits from: Object
Subclasses: ScoreStreamPlayer

## Description

A Server object is the client-side representation of a server app and is used to control the app from the SuperCollider language application. (See Client vs Server for more details on the distinction.) It forwards osc-messages and has a number of allocators that keep track of IDs for nodes, buses and buffers.

The server application is a commandline program, so all commands apart from osc-messages are unix commands.

The server application represented by a Server object might be running on the same machine as the client (in the same address space as the language application or separately; see below), or it may be running on a remote machine.

Most of a Server's options are contolled through its instance of ServerOptions. See the ServerOptions helpfile for more detail.

### Paths

Server apps running on the local machine have two unix environment variables: SC_SYNTHDEF_PATH and SC_PLUGIN_PATH. These indicate directories of synthdefs and ugen plugins that will be loaded at startup. These are in addition to the default synthdef/ and plugin/ directories which are hard-coded.

These can be set within SC using the getenv and setenv methods of class String.

// all defs in this directory will be loaded when a local server boots
"SC_SYNTHDEF_PATH".setenv("~/scwork/".standardizePath);
"echo \$SC_SYNTHDEF_PATH".unixCmd;


### The default group

When a Server is booted there is a top level group with an ID of 0 that defines the root of the node tree. (This is represented by a subclass of Group : RootNode.) If the server app was booted from within SCLang (as opposed to from the command line) the method initTree will be called automatically after booting. This will also create a default_group with an ID of 1, which is the default group for all Nodes when using object style. This provides a predictable basic node tree so that methods such as Server-scope, Server-record, etc. can function without running into order of execution problems.

The default group is persistent, i.e. it is recreated after a reboot, pressing cmd-., etc. See RootNode and default_group for more information.

NOTE: If a Server has been booted from the command line you must call initTree manually in order to initialize the default group, if you want it. See initTree below.

### Local vs. Internal

In general, when working with a single machine one will probably be using one of two Server objects which are created at startup and stored in the class variables *local and *internal. In SuperCollider.app (OSX), two GUI windows are created to control these. Use -makeGui to create a GUI window manually.

The difference between the two is that the local server runs as a separate application with its own address space, and the internal server runs within the same space as the language/client app.

Both local and internal server supports scoping and synchronous bus access.

The local server, and any other server apps running on your local machine, have the advantage that if the language app crashes, it (and thus possibly your piece) will continue to run. It is thus an inherently more robust arrangement. But note that even if the synths on the server continue to run, any language-side sequencing and control will terminate if the language app crashes.

There is generally no benefit in using the internal server.

### The default Server

There is always a default Server, which is stored in the class variable default. Any Synths or Groups created without a target will be created on the default server. At startup this is set to be the local server (see above), but can be set to be any Server.

## Class Methods

### *new (name, addr, options, clientID = 0)

#### Arguments:

 name a symbol; each Server object is stored in one global classvariable under its name. addr an optional instance of NetAddr, providing host and port. The default is the localhost address using port 57110; the same as the local server. options an optional instance of ServerOptions. If nil, an instance of ServerOptions will be created, using the default values. clientID an integer. In multi client situations, every client can be given a separate nodeID range. The default is 0.

### *local [= value]

get/set the local server, stored in classvar local (created already on initClass)

### *internal [= value]

get/set the internal server, stored in classvar internal (created already on initClass)

### *default [= server]

Get or set the default server. By default this is the local server (see above).

#### Discussion:

Setting this will also assign it to the Interpreter variable 's'.

Server.default = Server.internal; // set the internal Server to be the default Server
s.postln; // internal


### *all [= dict]

get/set the set of all servers.

### *allRunningServers

#### Returns:

the set of all running servers.

### *quitAll

quit all registered servers

### *killAll

query the system for any sc-server apps and hard quit them

### *freeAll (evenRemote = false)

free all nodes in all registered servers

## Instance Methods

### -sendMsg ( ... msg)

send an osc message to the server.

#### Discussion:

s.sendMsg("/s_new", "default", s.nextNodeID, 0, 1);


### -sendBundle (time... msgs)

send an osc bundle to the server.

#### Discussion:

Since the network may have irregular performance, time allows for the bundle to be evaluated at a specified point in the future. Thus all messages are synchronous relative to each other, but delayed by a constant offset. If such a bundle arrives late, the server replies with a late message but still evaluates it.

s.sendBundle(0.2, ["/s_new", "default", x = s.nextNodeID, 0, 1], ["/n_set", x, "freq", 500]);


### -listSendMsg (msg)

as sendMsg, but takes an array as argument.

### -listSendBundle (time, msgs)

as sendBundle, but takes an array as argument.

#### Discussion:

This allows you to collect messages in an array and then send them.

s.listSendBundle(0.2, [["/s_new", "default", x = s.nextNodeID, 0, 1],
["/n_set", x, "freq", 600]]);


### -sendSynthDef (name, dir)

send a synthDef to the server that was written in a local directory

load a synthDef that resides in the remote directory

load all the SynthDefs in the directory dir.

#### Arguments:

 dir a String which is a valid path.

### -nextNodeID

get a unique nodeID.

### -nextPermNodeID

get a permanent node ID. This node ID is in a reserved range and will be held until you explicitly free it.

### -freePermNodeID (id)

free a permanent node ID for later reuse.

### -wait (responseName)

this can be used within a Routine to wait for a server reply

### -waitForBoot (onComplete, limit = 100, onFailure)

Evaluate "onComplete" as soon as the server has booted. This method will boot the server for you if it is not already running or booting. If the server is already running, "onComplete" is executed immediately.

#### Arguments:

 onComplete A function to evaluate after the server has booted successfully. limit The number of times to check for a successful boot. (5 times/sec) onFailure A function to evaluate after the server fails to boot. If onFailure is not given, an error message is posted. Providing a function suppresses the error message. If you want to supply a function and print the normal error message, make sure that your function returns "false," e.g. s.waitForBoot(onFailure: { ... custom action...; false }).

### -doWhenBooted (onComplete, limit = 100, onFailure)

Evaluate "onComplete" as soon as the server has booted. This method assumes the server is being booted explicitly through a separate boot call. If the server is already running, "onComplete" is executed immediately.

#### Arguments:

 onComplete A function to evaluate after the server has booted successfully. limit The number of times to check for a successful boot. onFailure A function to evaluate after the server fails to boot. If onFailure is not given, an error message is posted. Providing a function suppresses the error message. If you want to supply a function and print the normal error message, make sure that your function returns "false," e.g. s.waitForBoot(onFailure: { ... custom action...; false }).

### -boot (startAliveThread = true, recover = false, onFailure)

boot the remote server, create new allocators.

#### Arguments:

 startAliveThread If true, start a Routine to send a /status message to the server every so often. The interval between the messages is set by theServer.aliveThreadPeriod = (seconds). The default period is 0.7. If false, /status will not be sent and the server's window will not update. recover If true, create a new node ID allocator for the server, but use the old buffer and bus allocators. This is useful if the server process did not actually stop. In normal use, the default value "false" should be used. onFailure In this method, the onFailure argument is for internal use only. If you wish to take specific actions when the server boots or fails to boot, it is recommended to use -waitForBoot or -doWhenBooted.

#### Discussion:

N.B. You cannot boot a server app on a remote machine.

### -quit

quit the server application

### -reboot (func)

quit and restart the server application

### -freeAll

free all nodes in this server

### -status

query the server status

### -notify [= flag]

server sends notifications, for example if a node was created, a 'tr' message from a SendTrig, or a /done action. if flag is set to false, these messages are not sent. The default is true.

### -ping (n = 1, wait = 0.1, func)

measure the time between server and client, which may vary. the func is evaluated after n number of times and is passed the resulting maximum.

### -options [= value]

Get or set this Server's ServerOptions object. Changes take effect when the server is rebooted.

### -defaultGroup

#### Returns:

this Server's default group.

### -volume [= newVolume]

Get an instance of Volume that runs after the defualt group, or sets the Volume of the Server's output to level. Level is in db.

### -mute

mute the server's output. This can also be toggled from the Server window with the 'm' key.

### -unmute

unmute the server. This can also be toggled from the Server window with the 'm' key.

Move the nodes in nodeList to the location specified by target and addAction, placing them there in the order indicated by nodeList.

#### Discussion:

Any nodes which have already been freed will be skipped. Passing nil for target and addAction will result in the location being the head of the default group.

g = Group.new;
x = Array.fill(5, {Synth(\default)});
s.queryAllNodes;
s.queryAllNodes;


### -inputBus

Return a Bus object that represents the input audio bus.

### -outputBus

Return a Bus object that represents the output audio bus.

### -dumpOSC (code = 1)

#### Arguments:

code
 0 turn dumping OFF. 1 print the parsed contents of the message. 2 print the contents in hexadecimal. 3 print both the parsed and hexadecimal representations of the contents.

### -queryAllNodes (queryControls = false)

Post a representation of this Server's current node tree to the post window. See -plotTree for a graphical variant.

#### Discussion:

Very helpful for debugging. For local servers this uses g_dumpTree and for remote g_queryTree. See Group and Server Command Reference for more info.

s.boot;
s.queryAllNodes; // note the root node (ID 0) and the default group (ID 1)
s.quit;


### -avgCPU

Get peak and average CPU usage.

### -numSynths

Get number of running Synths.

### -numGroups

Get number of Groups.

### -numUGens

Get number of running UGens.

### -pid

Get process ID of running server (if not internal).

### -hasShmInterface

Returns true if a ServerShmInterface is available. See also Synchronous Control Bus Methods.

#### Discussion:

The shared memory interface is initialized after first server boot.

### Automatic Message Bundling

Server provides support for automatically bundling messages. This is quite convenient in object style, and ensures synchronous execution. See also Bundled Server Messages

### -makeBundle (time, func, bundle)

The Function func is evaluated, and all OSC messages generated by it are deferred and added to a bundle.

#### Arguments:

 time If set to nil or a number the bundle will be automatically sent and executed after the corresponding delay in seconds. If time is set to false the bundle will not be sent. func The function to evaluate. bundle allows you to pass in a preexisting bundle and continue adding to it.

#### Returns:

The bundle so that it can be further used if needed.

#### Discussion:

Calling sync inside func will split the bundle and wait for asynchronous actions to complete before continuing.

If an error is encountered while evaluating func this method will throw an Error and stop message deferral.

s.boot;
(
// send a synth def to server
SynthDef("tpulse", { arg out=0,freq=700,sawFreq=440.0;
Out.ar(out, SyncSaw.ar(freq,  sawFreq,0.1) )
)

// all OSC commands generated in the function contained below will be added to a bundle
// and executed simultaneously after 2 seconds.
(
s.makeBundle(2.0, {
x = Synth.new("tpulse");
a = Bus.control.set(440);
x.map(\freq, a);
});
)
x.free;

// don't send
(
b = s.makeBundle(false, {
x = { PinkNoise.ar(0.1) * In.kr(0, 1); }.play;
});
)
// now pass b as a pre-existing bundle, and start both synths synchronously
(
s.makeBundle(nil, { // nil executes ASAP
y = { SinOsc.kr(0.2).abs }.play(x, 0, 0, \addBefore); // sine envelope
}, b);
)
x.free; y.free;

// Throw an Error
(
try {
s.makeBundle(nil, {
s.farkermartin;
});
} { |error|
("Look Ma, normal operations resume even though:\n" + error.errorString).postln;
x = { FSinOsc.ar(440, 0, 0.2) }.play; // This works fine
}
)
x.free;

// use sync
(
s.makeBundle(nil, {
b = Buffer.read(s, Help.dir +/+ "sounds/a11wlk01.wav");
s.sync; // wait until load is done and then send the rest of the bundle
x = { PlayBuf.ar(1, b) * 0.5 }.play;
});
)
x.free; b.free;


### -bind (func)

Just as in makeBundle, the Function func is evaluated, and all OSC messages generated by it are deferred and added to a bundle, which is sent to the server, using the server default latency.

#### Discussion:

(
s.bind {
a = { |freq=100| SinOsc.ar(freq, LFTri.ar(freq)) * 0.2 }.play;
a.set(\freq, 400);
}
)


### Shared Controls

The internal server has a number of shared control buses. Their values can be set or polled using the methods below.

### -getSharedControl (num)

get the current value of a shared control bus. num is the index of the bus to poll. This command is synchronous and only works with the internal server.

### -setSharedControl (num, value)

set the current value of a shared control bus to value. num is the index of the bus to set. This command is synchronous and only works with the internal server.

### -allocSharedControls (numControls = 1024)

set the number of shared control buses. Must be done before the internal server is booted. The default is 1024.

### Persistent Node Trees

The class ServerTree can be used to store functions which will be evaluated after the server is booted, after all nodes are freed, and after cmd-. is pressed. This allows, for example, for one to create a persistent basic node structure. ServerTree is evaluated in the method initTree after the default group is created, so its existence can be relied upon.

### -initTree

This method initializes the default_group and runs ServerTree.

#### Discussion:

This method is called automatically when you boot a Server from the language. N.B. If you started a server app from the command line you will have to call initTree manually if you need this functionality.

s.quit;
f = {Group.new(s.defaultGroup); "Other code can be evaluated too".postln;};
s.boot;
s.queryAllNodes; // note the group within the default group
ServerTree.remove(f);


ServerBoot and ServerQuit provide similar functionality at boot and quit times.

### -makeGui (w)

Create and show the server window. The window responds to a number of keyboard shortcuts:
 key action n Post a representation of this Server's current node tree to the post window. (See -queryAllNodes) N As 'n' above but include controls. l Show input/output level meters. (See -meter) p Show graphical view of the node tree. (See -plotTree) (space) Boot server if not already booted. (See -boot) s Show scope window. (See -scope) f Show frequency analyzer window. (See -freqscope) d Toggle dumping of OSC messages. m Toggle mute. 0 Reset volume to 0 db.

### -scope (numChannels, index = 0, bufsize = 4096, zoom = 1, rate = 'audio')

Open a scope window showing the output of the Server. see Stethoscope for further details.

#### Arguments:

 numChannels the number of channels to be scoped out. The default is this server's options' numOutputBusChannels. index the first channel to be output. The default is 0. bufsize the size of the buffer for the ScopeView. The default is 4096. zoom a zoom value for the scope's X axis. Larger values show more. The default is 1. rate whether to display audio or control rate buses (either \audio or \control)

### -freqscope

Show frequency analyzer window.

### -meter

Show input/output level meters.

### -plotTree (interval = 0.5)

Plot the node/group tree. As -queryAllNodes but graphical.

### Recording Support

The following methods are for convenience use. For recording with sample accurate start and stop times you should make your own nodes. See the DiskOut helpfile for more info. For non-realtime recording, see the Non-Realtime Synthesis helpfile.

This functionality is also available through the recording button on the server windows. Pressing it once calls record, and pressing it again calls stopRecording (see below). When doing so the file created will be in your recordings folder and be named for the current date and time. The default location of the recordings folder varies from platform to platform but is always stored in thisProcess.platform.recordingsDir. Setting this variable allows you to change the default.

NOTE: record creates the recording synth after the Server's default group and uses In.ar. Thus if you add nodes after the recording synth their output will not be captured. To avoid this, either use Node objects (which use the default node as their target) or (when using messaging style) use a target nodeID of 1.
s.sendMsg("/s_new", "default", s.nextNodeID, 1,1);


For more detail on this subject see Order of execution, default_group, and Node Messaging.

See SoundFile for information on the various sample and header formats. Not all sample and header formats are compatible. Note that the sampling rate of the output file will be the same as that of the server app. This can be set using the Server's ServerOptions.

Example:

s.boot; // start the server

// something to record
(
SynthDef("bubbles", {
var f, zout;
f = LFSaw.kr(0.4, 0, 24, LFSaw.kr([8,7.23], 0, 3, 80)).midicps; // glissando function
zout = CombN.ar(SinOsc.ar(f, 0, 0.04), 0.2, 0.2, 4); // echoing sine wave
Out.ar(0, zout);
SynthDef("tpulse", { arg out=0,freq=700,sawFreq=440.0;
Out.ar(out, SyncSaw.ar(freq,  sawFreq,0.1) )

)

x = Synth.new("bubbles");

s.prepareForRecord; // you have to call this first

s.record;

s.pauseRecording; // pausable

s.record // start again

s.stopRecording; // this closes the file and deallocates the buffer recording node, etc.

x.free; // stop the synths

// look in your recordings folder and you'll find a file named for this date and time


### -prepareForRecord (path)

Allocates the necessary buffer, etc. for recording the server's output. (See record below.)

#### Arguments:

 path a String representing the path and name of the output file.

#### Discussion:

If you do not specify a path than a file will be created in your recordings folder (see the note above on this) called SC_thisDateAndTime. Changes to the header or sample format, or to the number of channels must be made before calling this.

### -record (path)

Starts or resumes recording the output.

#### Arguments:

 path this is optional, and is passed to prepareForRecord (above).

#### Discussion:

If you have not called prepareForRecord first (see above) then it will be invoked for you (but that adds a slight delay before recording starts for real).

### -pauseRecording

Pauses recording. Can be resumed by executing record again.

### -stopRecording

Stops recording, closes the file, and frees the associated resources.

#### Discussion:

You must call this when finished recording or the output file will be unusable. Cmd-. while recording has the same effect.

### -recordNode

#### Returns:

the current recording synth so that it can be used as a target. This should only be necessary for nodes which are not created in the default group.

### -recChannels [= value]

Get/set the number of channels (int) to record. The default is two. Must be called before prepareForRecord.

Get/set the header format (string) of the output file. The default is "aiff". Must be called before prepareForRecord.

### -recSampleFormat [= value]

Get/set the sample format (string) of the output file. The default is "float". Must be called before prepareForRecord.

### Asynchronous Commands

Server provides support for waiting on the completion of asynchronous OSC commands such as reading or writing soundfiles. N.B. The following methods must be called from within a running Routine. Explicitly passing in a Condition allows multiple elements to depend on different conditions. The examples below should make clear how all this works.

### -bootSync (condition)

Boot the Server and wait until it has completed before resuming the thread.

#### Arguments:

 condition an optional instance of Condition used for evaluating this.

### -sendMsgSync (condition... args)

Send the following message to the wait until it has completed before resuming the thread.

#### Arguments:

 condition an optional instance of Condition used for evaluating this. args one or more valid OSC messages.

### -sync (condition, bundles, latency)

Send a /sync message to the server, which will replie with the message /synced when all pending asynchronous commands have been completed.

#### Arguments:

 condition an optional instance of Condition used for evaluating this. bundles one or more OSC messages which will be bundled before the sync message (thus ensuring that they will arrive before the /sync message). latency allows for the message to be evaluated at a specific point in the future.

#### Discussion:

This may be slightly less safe then sendMsgSync under UDP on a wide area network, as packets may arrive out of order, but on a local network should be okay. Under TCP this should always be safe.

(
Routine.run {
var c;

// create a condition variable to control execution of the Routine
c = Condition.new;

s.bootSync(c);
\BOOTED.postln;

s.sendMsgSync(c, "/b_alloc", 0, 44100, 2);
s.sendMsgSync(c, "/b_alloc", 1, 44100, 2);
s.sendMsgSync(c, "/b_alloc", 2, 44100, 2);
\b_alloc_DONE.postln;
};
)

(
Routine.run {
var c;

// create a condition variable to control execution of the Routine
c = Condition.new;

s.bootSync(c);
\BOOTED.postln;

s.sendMsg("/b_alloc", 0, 44100, 2);
s.sendMsg("/b_alloc", 1, 44100, 2);
s.sendMsg("/b_alloc", 2, 44100, 2);
s.sync(c);
\b_alloc_DONE.postln;
};
)


## Keyboard Shortcuts

when a server window is in focus, these shortcuts can be used:
 space start the server d toggle dumpOSC n post a representation of the node tree N post a representation of the node tree and the current control values of any synths s scope (internal server only)