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
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).
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.
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
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.
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
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])
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.
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
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
Certain keywords are not allowed in the SynthDef for safety reasons. The post view will inform you if you use any of these words.
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.