SuperCollider

How to program LNX_Studio

A programming guide to creating instrument & effects in SCCode & SCCodeFX

You can create your own instruments and effects with SC Code and SC Code FX. This is a guide to programming these modules. If you are new to SuperCollider this is the main help page. I recommend becoming familiar with these related topics.

Here is a list of UGens found in SuperCollider. Browse: UGens

The SynthDef

SCCode builds a synth or an effect out of a valid SynthDef object. The auto-gui system will make Widgets for you from the arguments of that SynthDef's ugenGraphFunc. Widgets can use ControlSpecs defined in your metadata. The modules do not support the .play method or sequencing with patterns. All programming must be done within the scope of the SynthDef supplied.

A typical SynthDef will look like this.

// A simple SynthDef template

SynthDef("LNX_Saw1", {|out, amp, vel, freq, midi, pan, gate=1, sendOut, sendAmp, in, inAmp,
                    bpm, clock, i_clock, poll, filtFreq=1800, q=0.5, dur=1 |
    var signal;
    
    signal = Pulse.ar(midi.midicps, 0.5, 0.1);
    signal = DFM1.ar(signal, filtFreq * vel, q);
    signal = signal * EnvGen.ar(Env.new([1,1,0], [0,2], [-4,-4], 1), gate, vel, 0, dur, 2);
    LNX_Out(signal, out, amp, pan, sendOut, sendAmp);
    
    signal.poll(poll); // use for debugging
    
}, metadata: ( specs: ( filtFreq: \freq, q: \unipolar )))

You can call your SynthDef's what you like, for example this one is called "LNX_Saw1". The ugenGraphFunc must meet certain criteria else the build will fail (see below).

Arguments

The arguments of the SynthDef are used to automatically create GUI Widgets when you build the synth. Certain arguments are commonly reserved for special use and some are compulsory. For example the gate argument in SC Code is compulsory and is used to release the synths.

Reserved SC Code arguments

Compulsory...

    out        // audio output channel
    amp        // amplitude / volume of the synth (0..2)
    gate       // used to release the synth, normally used with an EnvGen
    pan        // pan position of the synth (-1..1)

Optional...

    velocity   // velocity of the note played (0..1)
    vel        // the same as velocity
    freq       // frequency of the note played (8..12543 hz)
    midi       // MIDI note of the note played (0..127)
    bpm        // current tempo in bpm (20..999)
    clock      // current song position in beats (increases as song plays)
    i_clock    // initial song position when the note started (static)
    sendOut    // audio send channel
    sendAmp    // audio send amplitude (0..2)
    in         // audio in channel
    inAmp      // audio in amplitude (0..2)
    poll       // trigid for polling to the post view

Sample support, optional...

    bufL          // the buffer number of the left channel
    bufR          // the buffer number of the right channel
    bufRate       // the rate to play the buffer at
    bufAmp        // the amplitude to scale the buffer
    bufStartFrame // the start frame of the buffer, used in Ugens like PlayBuf (frame index)
    bufStartPos   // the start position of the buffer, used in Ugens like GrainBuf (0-1)
    bufLoop       // whether to loop the sample or not (0 or 1)
    bufDur        // the duration of the buffer in seconds

Reserved SC Code FX arguments

Compulsory...

    out        // audio output channel
    amp        // amplitude / volume of the synth (0..2)
    in         // audio in channel
    inAmp      // audio in amplitude (0..2)

Optional...

    on         // turns the fx on/off. When off the fx is bypassed but still sends audio to the output.
    bpm        // current tempo in bpm (20..999)
    clock      // current song position in beats (increases as song plays)
    i_clock    // initial song position when the note started (static)
    sendOut    // audio send channel
    sendAmp    // audio send amplitude (0..2)
    poll       // trigid for polling to the post view

Currently there is no support for literal arrays.

The main body of the ugenGraphFunc

SCCode requires that you are able to release the synth with the gate argument & an EnvGen. The build will fail without this. The example below could do this for you.

signal = signal * EnvGen.ar(Env.new([1,1,0], [0,2], [-4,-4], 1), gate, 1, 0, 1, 2);

I recommend using LNX_Out for sending the audio out to LNX_Studio. Its an easy way of making sure the signal reaches the correct buses and doesn't overload them.

LNX_Out(signal, out, amp, pan, sendOut, sendAmp); // output the signal

You can synchronise to the tempo by using the arguments clock, i_clock & bpm. For example...

(clock/4).floor.wrap(0,8); // using clock to generate values (0..7) on every 4th beat

Impulse.ar(bpm/60);  // or using bpm as a freq input

Rates

You can supply an optional Array of specifications for the ugenGraphFunc's argument rates or use the prefixes a_, i_ or t_ on the argument names. In SCCodeFX if an argument is initial rate, then changing this value will result in a new synth replacing the previous one. This then allows changes to normally static Ugen arguments like fft buffer size.

The specifications can be:

Here we are setting different rates for the arguments of the ugenGraphFunc.

SynthDef("LNX_Synth", {|out, amp, in, inAmp, sendOut, sendAmp, static1, static2|
    // ugenGraphFunc
}, 
rates:[nil,0.1,nil,0.1,nil,0.1,\ir,\ir])

Using samples

In SC Code you can use samples in two ways. Either as bank of samples, like you find in a drum machine or as a collection of samples recorded at regular pitched intervals, like that of a sampled piano. Once you have the samples loaded you need to use slightly different code to play them in your SynthDef.

Each buffer channel (i.e Left or Right) is loaded as a separate Buffer. You will receive the buffer number for each channel independently. This way you can write 1 SynthDef that works for both Mono & Stereo samples, like below.

// A simple SynthDef for playing samples

SynthDef("LNX_SamplePlayer", {|out, amp, vel, freq, midi, pan, gate=1, sendOut, sendAmp, dur=1,
                    bufL, bufR, bufRate, bufAmp, bufStartFrame, bufStartPos, bufLoop, bufDur|
    var signal;
    
    signal = PlayBuf.ar(1,[bufL, bufR], BufRateScale.kr([bufL, bufR]) * bufRate, 
                                loop:bufLoop, startPos:bufStartFrame) * bufAmp;
                                        
    signal = signal * EnvGen.ar(Env.new([1,1,0], [0,2], [-1,-1], 1), gate, vel, 0, dur*bufDur, 2);
    
    LNX_Out(signal, out, amp, pan, sendOut, sendAmp);
    
}, metadata: ( specs: ()))

Here PlayBuf uses bufL & bufR as buffer numbers for each channel, bufRate tells it how fast to play them back, bufLoop whether to loop the sample and bufStartFrame as the start Frame. bufAmp is used to scale the amplitude of each sample. startPos can be used in UGens where an index between 0-1 is required, like in GrainBuf.

Metadata & specs

Use metadata to associate a ControlSpec with a SynthDef argument and attach it to a GUI Widget. You can also use symbols or lists to define a ControlSpec.

SynthDef("LNX_Synth", {|out, amp, in, inAmp, sendOut, sendAmp|
    // ugenGraphFunc
},
metadata: ( specs: (
    filtFreq: \freq, q: [0,1,\lin,0,0], q2: ControlSpec(0.01, 2000, \exp, 0.1, 220, "Hz")
)))

Useful default specs might be:

\unipolar, \bipolar, \switch, \freq, \lofreq, \midfreq, \widefreq, \phase, \rq, \midi, \midinote, \MIDInote, \db, \db2, \db4, \db6, \amp, \boostcut, \pan, \detune, \transpose, \pitchAdj, \pitch, \rate, \beats, \delay, \delayms, \duration, \duration2, \duration4, \fft

Polling

If you need to debug your ugenGraphFunc use the .poll(poll,rate) method to send values to the post view.

amp.poll(poll,10); // will send values to the post view 10 times a second

Keywords

Certain keywords are not allowed in the SynthDef for safety reasons. The post view will inform you if you use any of these words.

Publishing code

I regularly update the Library with my own instruments and effects. One of the reason I designed LNX this way was to encourage users to submit and share their own content. Please contact me at neil_cosgrove@hotmail.com if you want to get your own code included in the on-line library.

A computer language like SuperCollider makes it easy to share code with others. Generally, making software public that is written in sclang or software that includes changes to scserver requires the sourcecode to be publicly available. For more information, see http://www.gnu.org/copyleft/gpl.html

Quite often, code written by others is copied, modified and used in pieces or software. If the code was published without any specific licence, it is always good to at least mention the original authors in your work in order to avoid later conflicts.