Client versus Server Architecture and Operations
The name "SuperCollider" is in fact used to indicate five different things (Figure 1):
1. an audio server
2. an audio programming language
3. an interpreter for the language, i.e. a program able to interpret it
4. the interpreter program as a client for the server
5. the application including the two programs and providing mentioned functionalities
Figure 1. Structure of the SuperCollider application
The SuperCollider application is thus made up of two distinct, autonomous, components, a server and a client. The first is named scsynth (SC-synthesizer), the second sclang (SC-language).
The SuperCollider application makes use of client/server architecture which separates two functions, respectively one providing and the other requesting services. The client and the server communicate through a network.
Figure 2. Client/Server architecture
In Figure 2 a generic network architecture is depicted: A number of clients communicating with a server by exchanging messages through a network. In SuperCollider the client and the server make use of a specific subset of CNMAT's Open Sound Control (OSC) protocol in order to communicate (over TCP or UDP). As a consequence, you will see many references to "OSC messages" in the help files.
To avoid any possible confusion: The network is defined at an abstract level. This means that the client(s) and the server(s) can be in execution on the same physical machine. This is what normally happens when you use the SuperCollider application: two programs will run on your machine, scsynth and sclang.
The server app, scsynth, is a lean and efficient command line program dedicated to audio synthesis and processing. It knows nothing about SC code, objects, Object Oriented Programming, or anything else to do with the SC language.
The client of this server is sclang. Sclang performs two distinct tasks:
1. it is the client for the server, i.e. it sends OSC messages to the server.
In order to write a letter to server, you need a paper sheet and a mailer: sclang is both.
2. it is the interpreter for the SuperCollider programming language, i.e. it allows to the user to write code in the aforementioned language and interactively execute the resulting commands, e.g. to control the audio server. In particular OSC messages can be cumbersome to write, as they share with the server its low-level perspective. The SuperCollider language is a high-level, fully featured object oriented language, allowing the user to gain a much more expressive power than OSC messages. Typically, the interpreter translates the code in SuperCollider language in OSC messages for the server. The user writes poetry (so to speak) in the SuperCollider language which is then paraphrased in OSC prose by the sclang interpreter, to be sent to the server.
From inside sclang, starting a server app can be accomplished by:
s = Server.default; // create a new Server object and assign it to variable s
s.boot; // boot the server app, i.e. tell the server to be ready to work
The sclang interpreter can send OSC messages to scsynth in two fashions:
- directly: in this case, sclang offers a thin syntax layer which allows one to deal with raw OSC messages. All the server's functionality is in this case available "by hand" using the .sendMsg method of Server, and other similar messages.
n = s.nextNodeID; // get an available nodeID from the server and assign it to n
s.sendMsg("/s_new", "default", n); // use the SynthDef "default" to create a synth with ID n
s.sendMsg("/n_free", n); // release the synth n
- indirectly: the language app provides you with convienent OOP functionality to keep track of and manipulate things on the server. The high-level syntax is translated into low-level OSC messages by sclang and sent to the server (language wrapping).
x = Synth("default"); // create a synth on the default server (s) and allocate an ID for it
x.free; // free the synth, its ID and resources
Working this way you have gained certain functionality. It provides a node ID for you automatically, it allows you to control the Synth in syntactically elegant and efficient ways (see the Synth and Node helpfiles), and to access all the advantages of object oriented programming while doing so. Encapsulating the complexities and bookeeping greatly reduces the chance of bugs in your own code.
Figure 3. Sclang as a high-level client.
Language wrapping allows the user to access complex behaviours from very little code. Figure 3 (ignore for the moment that sclang is represented as a client among other possible ones, see later) schematically represents what happens when you evaluate an audio function like this:
// assuming the server is already booted
In this case many server operations are hidden. To understand the passages inolved in the evalutation of this code see Functions and Other Functionality and SynthDefs and Synths (part of Scott Wilson's tutorial).
The OOP-style also has a small amount of overhead. It requires clientside CPU cycles and memory to create and manipulate an object. Normally this is not significant, but there may be times when you would prefer to use the less elegant, and less expensive first method, for instance when creating large numbers of grains which will simply play and then deallocate themselves.
Thus it is possible to create synth nodes on the server without actually creating Synth objects, providing you are willing to do the required housekeeping yourself. The same is true of group nodes, buffers, and buses. A more detailed discussion of these concepts can be found in the NodeMessaging helpfile.
In conclusion, the crucial thing to remember is the distinction between things like nodes, busses, buffers, and servers and the objects that represent them in the language app (i.e. instances of Node, Bus, Buffer, and Server; these are referred to as 'Server Abstraction Objects'). Keeping these conceptually distinct will help avoid much confusion.
The client/server architecture provides three main advantages:
stability: if the client crashes, the server keeps on working, i.e. the audio does not stop. This is intuitively relevant for a live situation. Vice versa, the server can crash letting you still manage the situation from the client.
modularity: synthesis is one thing, control another. Separating the two aspects allows one to (for example) control scsynth from applications besides sclang. The only important thing is that they are able to send the right OSC messages to the server.
remote control: the client/server network can be external to your computer, e.g. over the Internet. This allows one to control an audio server in Alaska from a client (sclang or other) in India, for example.
There are two notable drawbacks:
latency: The messaging process introduces a small amount of latency. This should not be confused with audio latency which can be quite low. It only means that there is a small, usually insignificant delay between the one side sending a message and the other receiving it and acting upon it. (This can be minimized by using the 'internal' server. See Server for more detail.)
asynchronous execution: In some cases the client might need to know that a task on the server (for instance processing a large sound file) has been completed before continuing with another task. Since some tasks take an arbitrary length of time to complete, a reply mechanism is necessary. This can add some complexity to your code, but is in principle not an issue. (See OSCresponder and OSCresponderNode.) Some server abstraction objects such as Buffer provide for this automatically through 'action' functions which wait for completion before executing.
A final remark for the advanced reader
Apart from sclang, it is possible to control scsynth from any other client which provides for OSC messaging (e.g. from Java, Python, Max/MSP, etc.). For networking, see Server-Architecture, NetAddr, OSCresponder, OSCresponderNode.
In general however, sclang is the preferable way to communicate with scsynth for three reasons:
- it gives you the expressive power of the SuperCollider language;
- the language is explicitly fitted to scsynth's needs (and, more importantly, to musician's ones)
- it allows one to create and load SynthDefs onto scsynth (see SynthDef), which is a not such an easy task to accomplished in another client app.