[Topic]
SuperCollider

Common Music supports the writing and rendering of non-realtime SuperCollider files. Support for running in real-time is currently in progress.

SuperCollider synths

SuperCollider synth objects are defined similarly to clm or csound instruments.

To begin, let's look at a fairly simple synthdef in SuperCollider.

	  (
	  SynthDef("simple", {arg dur=1.0,freq=440.0,amp=0.2,pan=0.0;
	    var osc;
	    osc = EnvGen.kr(Env.triangle(dur,amp), doneAction: 2) * SinOsc.ar(freq);
	    Out.ar(0,Pan2.ar(osc,pan));
	    }).writeDefFile.load(s);
	  )
	

Defining a CM scsynth object to generate data for this instrument is straightforward:

	  (defobject simple (scsynth)
	   ((freq :initform 440)
	     (dur :initform 1)
	     (amp :initform .2)
	     (pan :initform 0))
	   (:parameters freq dur amp pan))
	

The object is a subclass of the abstract class scsynth which contains additional slots that will be introduced below.

All arguments to the synthdef are used in the object definition of simple. The name of the slots are always treated as lowercase strings when written to an .osc file. This is important because if you have defined arguments to your synthdef which are mixed case or uppercase (e.g. "Dur" "DUR") things will not work properly.

In addition to user defined slots, all scsynth objects inherit the following slot initargs:

:node number
The node created on the sc server. This defaults to -1, which allows the server to generate its own id for the instrument. This does mean in most cases that you will not be able to send commands to this specific instance of the synth since you will not know what the node id is. In cases where this is needed this value should be set.
:add-action number
How to add the new node according to following from SuperCollider Server Command Reference (Default is 1):
  • 0 - add the new node to the the head of the group specified by the add target ID.
  • 1 - add the new node to the the tail of the group specified by the add target ID
  • 2 - add the new node just before the node specified by the add target ID.
  • 3 - add the new node just after the node specified by the add target ID.
  • 4 - the new node replaces the node specified by the add target ID.
:target number
The group or node referenced by the :add-action slot.
:time number
The time to begin the synth.

Envelopes in SuperCollider

To send an envelope to a scsynth, one must typically use node-setn. Instead it is also possible to use an sc-env when creating a new instance of s scsynth. Here is a simple example in SC:

	  (
	  SynthDef("simple-env", {arg dur=1.0,freq=440.0,amp=0.2,pan=0.0;
	    var osc,ampenv;
	    ampenv = Env.newClear(8);
	    ampf =  Control.names([\ampenv]).kr( ampenv.asArray );
	    osc = EnvGen.kr(ampf, levelScale: amp, doneAction: 2) * SinOsc.ar(freq);
	    Out.ar(0,Pan2.ar(osc,pan));
	  }).writeDefFile.load(s);
	  )
	  

This is the corresponding defobject in cm.

	  (defobject simple-env (scsynth)
	   ((freq :initform 440)
	    (dur :initform 1)
	    (amp :initform .2)
	    (ampenv :initform #f)
	    (pan :initform 0))
	   (:parameters freq dur amp ampenv pan))
	

Now a sc-env can be used in the creation of a new instance of simple-env.

	  (new simple-env :time (now) 
		          :freq (between 300 700) 
		          :dur (between 10 20)
		          :node (+ i 1000)
		          :amp .1
		          :ampenv (new sc-env :envelope '(0 0.0 10 1.0 80 .5 100 0.0) :duration 10)
		          :pan 1.0)
	
[Class]
sc-env
:envelope list
Envelope used. Required.
:duration number
Envelope duration. Required.
:curve {keyword | list | number}
Curve segments. Defaults to :linear
Valid curve descriptors are :linear :lin :exp :exponential :step :sine :welch.
Curve descriptors may also be numbers which indicate a curvature value.
:scale number
Scale values.
:offset number
Offset values.
:release-node number
Release segment of envelope.
:loop-node number
Loop segment of envelope.
(new sc-env :envelope'(0 0.0 10 1.0 80 .5 100 0.0) :duration 10)
(new sc-env :envelope'(0 0.0 10 1.0 80 .5 100 0.0):duration 10 :curve :exp)
(new sc-env :envelope'(0 0.0 10 1.0 80 .5 100 0.0):duration 10 :curve '(:exp -1.4 :welch))
	

Buffers in SuperCollider

[Class]
sc-buffer

Instead of using different commands for creating buffers, sc-buffer attempts to encapsulate some of the most commonly used buffer creation/filling methods into one cm event.

:bufnum number
Buffer number.
:with-file string
Path to a file to load into the buffer
:with-values {function | list | number}
Fills buffer with :with-values. If a number, fills buffer with that value. If a list, will set buffer to those values. If a function will call this function for as many frames as are in the buffer minus :starting-at.
:with-gen list
Uses a buffer-gen to fill the buffer.
:starting-at number
Offset into buffer. Defaults to 0
:frames number
Number of frames in buffer. If used with :with-file defaults to reading in the entire file
:channels number
Number of channels in buffer.
:time number
When to create buffer.
(new sc-buffer :with-gen'(:sine1 (1.0 .2 .1 .01)) :frames 512 :time  (now))
(new sc-buffer :with-file "/Applications/SuperCollider3/sounds/a11wlk01.wav":time (now))
(new sc-buffer :with-values .2 :time (now))
(new sc-buffer :with-values (lambda () (ran :from -1.0  :below 1.0)) :time (now))
	

SuperCollider Command Events

All SuperCollider command events contain the :time slot inherited from event.

For a description of the following commands, refer to Help/Server-Command-Reference.rtf in the SuperCollider distribution

Most of these events work with in both realtime and non-realtime mode unless otherwise noted.

[Class]
load-synthdef
:path string
Synthdef file to load.
	  (new load-synthdef :path "/path/to/synthdef.scsyndef" :time (now))
	
[Class]
load-synthdef-dir
:path string
Synthdef directory to load.
	  (new load-synthdef-dir :path "/path/to/" :time (now))
	
[Class]
node-free
:node {number | list}
Node or list of nodes to free.
	  (new node-free :node 1000 :time (now))
	  (new node-free :node '(1000 1001 1002) :time (now))
	
[Class]
node-run
:node {number | list}
Node(s) to set.
:flag {boolean | list}
True or false referring to node(s).
	  (new node-run :node 1000 :flag #t :time (now))
	  (new node-run :node '(1000 1001 1003) :flag '(#t #f #t) :time (now))
	
[Class]
node-set
:node number
Node to set.
:controls-values list
List of keyword/number pairs indicating what control to set and what value to set it to.
(new node-set :node 1000 :controls-values '(:freq 400.1 :amp .2) :time (now))
	
[Class]
node-setn
:node number
Node to set.
:controls-values list
List of keyword/list pairs indicating what control to start with and values indicating the setting of contiguous controls.
(new node-setn :node 1000 :controls-values '(:freq (440 .1 3) :time (now))
	
[Class]
node-fill
:node number
Node to set.
:control {keyword | list}
Control or controls to set.
:num-controls number
Number of values to fill.
:value number
Value to set control(s) to.
(new node-fill :node 1000 :control :freq :num-controls 2 :value 100.1 :time (now))
(new node-fill :node 1000 :control '(:freq01 :freq20)  
     :num-controls '(2 4) :value '(100.1 20.22) :time (now))
	
[Class]
node-map
:node number
Node to set.
:controls-buses list
List of keyword/number pairs indicating what control to map to what bus..
(new node-map :node 1000 :controls-buses '(:amp 1 :pan 4) :time (now))
	
[Class]
node-mapn
:node number
Node to set.
:control {keyword | list}
Keyword or list of keywords indicating the control names.
:bus {number | list}
Control buses index or indices.
:bus {number | list}
Number of controls to map.
(new node-mapn :node 1000 :control :freq :bus 100 :num-controls 2 :time (now))
(new node-mapn :node 1000 :control '(:freq1 :freq100) :bus '(100 200) 
     :num-controls '(12 24) :time (now))
	
[Class]
node-before
:node number
Node to set.
:before number
the node to place :node before.
(new node-before :node 1001 :before 1000 :time (now))
(new node-before :node '(1001 200) :before '(1000 500) :time (now))
	
[Class]
node-after
:node number
Node to set.
:after number
The node to place :node after.
(new node-after :node 1000 :after 1001 :time (now))
(new node-after :node '(1001 200) :before '(1000 500) :time (now))
	
[Class]
node-query
real-time only
:node {number | list}
Node to set.
(new node-query :node 1000 :time (now))
(new node-query :node '(1000 1001) :time (now))
	
[Class]
synth-get
real-time only
:node number
Synth to get.
:controls {number | string | list}
Control index or name or list of controls
(new synth-get :node 1000  :controls "freq":time (now))
(new synth-get :node '(1000 1001) :controls '(("freq" "amp") ("freq" "duration")) :time (now))
	
[Class]
synth-getn
real-time only
:node number
Synth to set.
:controls {number | string | list}
Control index or name or list of controls
:num-controls number
number of controls to get
(new synth-getn :node 1000  :controls "ampenv" :num-controls 10 :time (now))
	
[Class]
group-new
:id number or list
Id of new group.
:add-action {number | list}
How to add the new group according to following from SuperCollider Server Command Reference:
  • 0 - add the new group to the the head of the group specified by the add target ID.
  • 1 - add the new group to the the tail of the group specified by the add target ID.
  • 2 - add the new group just before the node specified by the add target ID.
  • 3 - add the new group just after the node specified by the add target ID.
  • 4 - the new node replaces the node specified by the add target ID. The target node is freed.
:target {number | list}
The group or node referenced by the :add-action slot.
	  ; adds a new group with id 2 just before node 1000
	  (new group-new :id 2 :add-action 2 :target 1000) 
	  (new group-new :id '(2 3) :add-action '(2 1) :target '(1000 900))
	
[Class]
group-head
:group {number | list}
The group to add :node to the head of.
:node {number | list}
The node to add to the head of :group.
(new group-head :group 2 :node 2000 :time (now))
(new group-head :group '(2 10) :node '(2000 3000) :time (now))
	  
[Class]
group-tail
:group {number | list}
The group to add :node to the tail of.
:node {number | list}
The node to add to the tail of :group.
(new group-tail :group 2 :node 2000 :time (now))
(new group-tail :group '(2 10) :node '(2000 3000) :time (now))
	  
[Class]
group-free-all
:group {number | list}
Frees all nodes in the specified group.
(new group-free-all :group 2 :time (now))
(new group-free-all :group '(2 4) :time (now))
	  
[Class]
group-deep-free
:group {number | list}
Frees all nodes in the specified group(s) and groups below it.
(new group-deep-free :group 10 :time (now))
(new group-deep-free :group '(10 20) :time (now))
	  
[Class]
ugen-command
:node number
Node ugen is in.
:ugen-index number
Index of unit generator.
:command-name string
Command for unit generator.
:args list
Any additional arguments.
[Class]
buffer-alloc
:bufnum number
Buffer number.
:frames number
Number of frames to allocate.
:channels number
Number of channels. Default is 1.
(new buffer-alloc :bufnum 10 :frame 512 :channels 1 :time (now))
	  
[Class]
buffer-alloc-read
:bufnum number
Buffer number.
:file string
Path of sound file.
:start-frame number
The starting frame to read from.
:frames number
Number of frames to read from file. If this is 0 (the default) the entire file will be read.
(new buffer-alloc-read :bufnum 10 :file "/Applications/SuperCollider3/sounds/a11wlk01.wav" 
     :time (now))
	  
[Class]
buffer-read
:bufnum number
Buffer number.
:file string
Path of sound file.
:start-frame number
The starting frame to write from. Defaults to 0.
:frames number
Number of frames to read from file. If this is -1 (the default) the entire file will be read.
:buffer-start-frame number
Frame in buffer to start reading file into. Defaults to 0.
:leave-open? {true | false}
Leave file open. Only should be true when using DiskIn.
(new buffer-read :bufnum 10 :file "/Applications/SuperCollider3/sounds/a11wlk01.wav"
     :time (now))
	  
[Class]
buffer-write
:bufnum number
Buffer number.
:file string
Path of sound file.
:header {:aiff | :next | :wav | :ircam | :raw}
Specifies header format of the file to write. Default is :aiff.
:format {:int8 | :int16 | :int24 | :int32 | :float | :double | :mulaw | :alaw}
Specifies the sample format of the file to write. Default is :int16.
:frames number
Number of frames to write. Default is -1 which writes entire buffer to file.
:start-frame number
The starting frame to write from.
:leave-open? boolean
Leave file open. Only should be true when using DiskOut.
(new buffer-write :bufnum 10 :file "/path/to/file.aiff" :header :aiff
     :format :float)
	  
[Class]
buffer-free
:bufnum number
Buffer number.
[Class]
buffer-zero
:bufnum number
Buffer number.
[Class]
buffer-set
:bufnum number
Buffer number.
:samples-values list
Pairs of sample indices and values to set.
(new buffer-set :bufnum 10 :samples-values '(0 .1 1 .2 3 .1 4 .3)
     :time (now))
	  
[Class]
buffer-setn
:bufnum number
Buffer number.
:samples-values list
Pairs of starting sample index and list of values.
(new buffer-setn :bufnum 10 :samples-values '(0 (0 .1 1 .2 3 .1 4 .3))
     :time (now))
	  
[Class]
buffer-fill
:bufnum number
Buffer number.
:start-sample {number | list}
Starting sample position to fill
:num-samples number or list
Number of samples to fill.
:value{number | list}
Value to use as fill.
(new buffer-fill :bufnum 10 :start-sample 0 :num-samples 10 :value .8
     :time (now))
(new buffer-fill :bufnum 10 :start-sample '(0 256) :num-samples '(10 20)
     :value '(.8 .2) :time (now))
	  
[Class]
buffer-close
:bufnum number
Buffer number.
[Class]
buffer-gen
:bufnum number
Buffer number.
:command { :sine1 | :sine2 | :sine3 | :cheby }
Command to fill the buffer.
:flags keyword or list. possible values :normalize :wavetable :clear
Flags for command.
:args list
Additional arguments to command.
(new buffer-gen :bufnum 10 :command :sine2 :flags :wavetable
     :args '(1 1.0 2 .7 4 .3) :time (now))
	  
[Class]
buffer-get
real-time only
:bufnum number
Buffer to get.
:samples {number | list}
Sample index or indices
(new buffer-get :buffer 10  :samples 1 :time (now))
(new buffer-get :buffer 10 :samples '(1 3 5 7) :time (now))
	  
[Class]
buffer-getn
real-time only
:bufnum number
Buffer to get.
:samples {number | list}
Sample index or indices
:num-samples number
Number of sequential samples to get
(new buffer-getn :bufnum 10  :samples 0 :num-samples 36 :time (now))
(new buffer-getn :bufnum 10  :samples '(0 128) :num-samples '(36 48) :time (now))
	  
[Class]
control-set
:bus {number | list}
Bus number.
:value {number | list}
Control value.
(new control-set :bus 2 :value 2.0 :time (now))
(new control-set :bus '(2 3 4) :value '(.4 .9 1.2) :time (now))
	  
[Class]
control-setn
:bus {number | list}
Bus number.
:value {number | list}
Control value.
(new control-setn :bus 2 :value '(2.0 3.0 .2) :time (now))
(new control-setn :bus '(2 9) :value '((.1 .2 .3) (1.7 1.9 1.01))
     :time (now))
	  
[Class]
control-fill
:bus number
The control bus to start at.
:num-buses number
Number of control buses to fill.
:value number
Value to set control buses to.
(new control-fill :num-buses 2)
	  
[Class]
control-get
real-time only
:bus {number | list}
Control bus or buses to get.
(new control-get :bus 10  :time (now))
(new control-get :bus '(10 11 12) :time (now))
	  
[Class]
control-getn
real-time only
:bus {number | list}
Control bus or buses to get.
:num-buses {number | list}
Number of sequential buses to get
(new control-getn :bus 10 :num-buses 36 :time (now))
(new control-getn :bus '(1 20)  :num-buses '(3 8) :time (now))
	  

Examples:

Example 1. Using node-set to produce continuous changes in panning.

;;; define a scsynth object

(defobject simple (scsynth)
  ((freq :initform 440)
   (dur :initform 1)
   (amp :initform .2)
   (pan :initform 0))
  (:parameters freq dur amp pan time))

;;; define a process to generate simples.

(define (sc-simple-3 num)
  (process repeat num for i from 0
	   output (new simple :time (now) 
		       :freq (between 300 700) 
		       :dur (between 10 20)
		       :node (+ i 1000)
		       :amp .1
		       :pan 1.0)
	   sprout
	   (process repeat 100 for j from 0
		    with node = (+ i 1000)
		    with pan-env = '(0 1.0 50 .4 100 -1.0)
		    output (new node-set :node node
				:controls-values
				(list :pan (interpl j pan-env)) 
				:time (now))
			   wait .1)
	   wait (between 2 3)))

(events (sc-simple-3 10) "sc-simple-3.osc" :pad 20)
 "sc-simple-3.osc"

(define *sc* (sc-open))
(rts (sc-simple-3 10) *sc* )

	  

Auxiliary Functions

CM provides some a few functions and variables to facilitate working with SuperCollider.
[Function]
(sc-open [args] )

Opens a sc-stream called "sc.udp" according to the keyword initialization args passed to the stream.

[Function]
(sc-open?)

Tests to see if "sc.udp" has already been opened.

[Function]
(sc-close [args] )

Closes the sc-stream called "sc.udp" if it is open, otherwise has no effect.

[Function]
(sc-quit [sc-stream] )

Sends a quit message to scsynth listening on "sc.udp" if opened or optional sc-stream.

[Function]
(sc-dumposc boolean [sc-stream] )

Sends a dumpOSC message to scsynth listening on "sc.udp" if opened or optional sc-stream. If boolean is true turns on osc dumping. If false turns it off.

[Function]
(sc-clearsched [sc-stream] )

Sends a clearSched message to scsynth listening on "sc.udp" if opened or optional sc-stream.

[Function]
(sc-notify boolean [sc-stream] )
Sends a notify message to scsynth listening on "sc.udp" if opened or optional sc-stream. If boolean is true turns on status. If false turns it off.

[Function]
(sc-flush [sc-stream] )

Sends a clearSched and a group-free-all message to scsynth listening on "sc.udp" if opened or optional sc-stream.

The file sc.cm contains numerous examples of Supercollider score generation. The file sc-rt.cm contain examples of generating Supercollider events in realtime.

SuperCollider Reply Objects

[Class]
done-reply
slots:
cmd-name
accessors:
done-cmd-name
[Class]
fail-reply
slots:
cmd-name
error
accessors:
fail-cmd-name
fail-error
[Class]
status-reply
slots:
num-ugens
num-synths
num-groups
num-loaded-synths
avg-cpu
peak-cpu
sample-rate
actual-sample-rate
accessors:
status-num-ugens
status-num-synths
status-num-groups
status-num-loaded-synths
status-avg-cpu
status-peak-cpu
status-sample-rate
status-actual-sample-rate
[Class]
synced-reply
slots:
id
accessors:
synced-id
[Class]
synth-get-reply
slots:
node
controls-values
accessors:
synth-get-node
synth-get-controls-values
[Class]
synth-getn-reply
slots:
node
controls-values
accessors:
synth-getn-node
synth-getn-controls-values
[Class]
buffer-get-reply
slots:
bufnum
samples-values
accessors:
buffer-get-bufnum
buffer-get-samples-values
[Class]
buffer-getn-reply
slots:
bufnum
samples-values
accessors:
buffer-getn-bufnum
buffer-getn-samples-values
[Class]
buffer-query-reply
slots:
bufnum
num-frames
num-chans
sample-rate
accessors:
buffer-query-bufnum
buffer-query-num-frames
buffer-query-num-chans
buffer-query-sample-rate
[Class]
buffer-getn-reply
slots:
bus
value
accessors:
control-get-bus
control-get-value
[Class]
control-getn-reply
slots:
bus
value
accessors:
control-getn-bus
control-getn-value
[Class]
node-go-reply
slots:
node
parent-group
previous-node
next-node
type
head-node
tail-node
accessors:
node-go-node
node-go-parent-group
node-go-previous-node
node-go-next-node
node-go-type
node-go-head-node
node-go-tail-node
[Class]
node-end-reply
slots:
node
parent-group
previous-node
next-node
type
head-node
tail-node
accessors:
node-end-node
node-end-parent-group
node-end-previous-node
node-end-next-node
node-end-type
node-end-head-node
node-end-tail-node
[Class]
node-off-reply
slots:
node
parent-group
previous-node
next-node
type
head-node
tail-node
accessors:
node-off-node
node-off-parent-group
node-off-previous-node
node-off-next-node
node-off-type
node-off-head-node
node-off-tail-node
[Class]
node-on-reply
slots:
node
parent-group
previous-node
next-node
type
head-node
tail-node
accessors:
node-on-node
node-on-parent-group
node-on-previous-node
node-on-next-node
node-on-type
node-on-head-node
node-on-tail-node
[Class]
node-move-reply
slots:
node
parent-group
previous-node
next-node
type
head-node
tail-node
accessors:
node-move-node
node-move-parent-group
node-move-previous-node
node-move-next-node
node-move-type
node-move-head-node
node-move-tail-node
[Class]
node-info-reply
slots:
node
parent-group
previous-node
next-node
type
head-node
tail-node
accessors:
node-info-node
node-info-parent-group
node-info-previous-node
node-info-next-node
node-info-type
node-info-head-node
node-info-tail-node
[Class]
trigger-reply
slots:
node
id
value
accessors:
trigger-node
trigger-id
trigger-value

See also: