- [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)
: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
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
load-synthdef
load-synthdef-dir
node-free
node-run
node-set
node-setn
node-fill
node-map
node-mapn
node-before
node-after
node-query
synth-get
synth-getn
group-new
group-head
group-tail
group-free-all
group-deep-free
ugen-command
buffer-alloc
buffer-alloc-read
buffer-read
buffer-write
buffer-free
buffer-zero
buffer-set
buffer-setn
buffer-fill
buffer-close
buffer-get
buffer-getn
buffer-gen
control-set
control-setn
control-fill
control-get
control-getn
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.
:path
string- Synthdef file to load.
:path
string- Synthdef directory to load.
:node
{number | list}- Node or list of nodes to free.
: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))
: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.
: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.
: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))
:node
number- Node to set.
:controls-buses
list- List of keyword/number pairs indicating what control to map to what bus..
: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))
: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))
: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))
- real-time only
:node
{number | list}- Node to set.
- 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))
- 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
: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))
: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))
: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))
:group
{number | list}- Frees all nodes in the specified group.
:
group
{number | list}- Frees all nodes in the specified group(s) and groups below it.
:
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.
:
bufnum
number- Buffer number.
:frames
number- Number of frames to allocate.
:channels
number- Number of channels. Default is 1.
:
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))
: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.
:
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)
:
bufnum
number- Buffer number.
:
bufnum
number- Buffer number.
:
bufnum
number- Buffer number.
:samples-values
list- Pairs of sample indices and values to set.
:
bufnum
number- Buffer number.
:samples-values
list- Pairs of starting sample index and list of values.
:
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))
:
bufnum
number- Buffer number.
:
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.
- 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))
- 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))
: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))
: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))
: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)
- real-time only
:bus
{number | list}- Control bus or buses to get.
- 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
done-reply
fail-reply
status-reply
synced-reply
synth-get-reply
synth-getn-reply
buffer-get-reply
buffer-getn-reply
buffer-query-reply
control-get-reply
control-getn-reply
node-go-reply
node-end-reply
node-off-reply
node-on-reply
node-move-reply
node-info-reply
trigger-reply
- slots:
- cmd-name
- accessors:
- done-cmd-name
- slots:
- cmd-name
- error
- accessors:
- fail-cmd-name
- fail-error
- 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
- slots:
- id
- accessors:
- synced-id
- slots:
- node
- controls-values
- accessors:
- synth-get-node
- synth-get-controls-values
- slots:
- node
- controls-values
- accessors:
- synth-getn-node
- synth-getn-controls-values
- slots:
- bufnum
- samples-values
- accessors:
- buffer-get-bufnum
- buffer-get-samples-values
- slots:
- bufnum
- samples-values
- accessors:
- buffer-getn-bufnum
- buffer-getn-samples-values
- slots:
- bufnum
- num-frames
- num-chans
- sample-rate
- accessors:
- buffer-query-bufnum
- buffer-query-num-frames
- buffer-query-num-chans
- buffer-query-sample-rate
- slots:
- bus
- value
- accessors:
- control-get-bus
- control-get-value
- slots:
- bus
- value
- accessors:
- control-getn-bus
- control-getn-value
- 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
- 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
- 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
- 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
- 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
- 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
- slots:
- node
- id
- value
- accessors:
- trigger-node
- trigger-id
- trigger-value