// Auto complete brackets, and other stuff
preferences => Behavior => Auto insert Matching...
// evaluate line or region of code within
// (
// some code here
// )
cmd + enter
// evaluate single line of code
cmd + shift + enter
// quit everything
cmd + .
// get help in the help browser
cmd + d (with cursor over a function)
// start the server
s.boot;
// quit the server
s.quit;
// free all the nodes on the server, remove sound without quitting the server
s.freeAll;
// show the meter
s.meter
// SuperCollider is not typed, any variable can be anything
// similar behavior can be find in languages like JavaScript
// and Python 🐍
// scoped variables. to use within functions without exiting
// parenthesis region
var osc = SinOsc.ar(440)
// arguments for functions
arg value
// global variables
~osc = SinOsc.ar(440)
// [a => z] are global variables available, that do not
//require initialization by prepending var. Exeption is made
//for the global variable s that is reserved for server actions
// follows the same logic as other programming languages
1 == 1 // true
1 > 0 // false
1 < 2 // true
1 >= 2 // false
1 <= 1 // true
if statement syntax
(
if(
[0, 1].choose == 0, // statement to evaluate
{"0 was chosen".postln;}, // if true do this
{"1 was chosen".postln;} // if false do this
);
)
// for loop
for (
3,
7,
{ arg i; i.postln }
); // prints values 3 through 7
// do loop [maybe better suited for musical stuff]
// assumes you know how to build an array
[
note_val_1,
note_val_2,
note_val_3,
note_val_4,
note_val_5,
note_val_6,
].do(
{
arg item, index;
// do something with item and index
}
)
~function = {
arg freq
{SinOsc.ar(freq)}.play;
}
~function.value(440)
[
your,
items,
go,
here
].size // returns length
// arrays shortcut that are useful later for making sound
// fill array with same item
7.dup(2) // [7, 7]
7!5 // [7, 7, 7, 7, 7]
// make an array of n items in sequence
~myarr = (1..100)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].sputter(0.5, 16).postln;
Array.fill([2, 2, 3], { arg i, j, k; i * 100 + (j * 10) + k });
Array.fill(10, { arg i; 2 ** i });
Array.newFrom(Set[4, 2, 1]);
Array.geom(5, 1, 3).postln;
Array.interpolation(5, 3.2, 20.5);
// Array.rand(size, minVal, maxVal);
Array.rand(8, 1, 100);
// Array.linrand(size, minVal, maxVal);
Array.linrand(8, 1, 100);
// Array.exprand(size, minVal, maxVal);
Array.exprand(8, 1, 100);
(
// z and y are the same object
var y, z;
z = [1, 2, 3];
y = z.add(4);
z.postln;
y.postln;
)
// return random value between two numbers
rrand(-10, 30)
// to include floats
rrand(0.5, 20)
// exponential distribution of randomness towards the
// lower value in the function to be used with frequency and
// amplitude. It always returns floats!
exprand(10, 30)
// very basic
(
~firstsound = {
arg freq;
SinOsc.ar(freq, 0, 0.2, 0);
};
)
// play sound
x = ~firstsound.play(args: [\freq, 400]);
// set frequencies
x.set(\freq, 300);
x.set(\freq, 200);
x.free;
(
SynthDef.new(\saw, {
arg freq=200, amp=0.2, gate=1, out=0;
var sig, env;
// here we build the envelope
env = EnvGen.ar(
Env.new(
[], // < = amplitudes at various stages values between 0 = > 1
[], // < = duration of the stages in seconds amplitudes.zizes - 1
[] // < = shape of the curves values between - infinity = > + infinity but \lin || \exp will also work or a single +- integer
gate,
doneAction: 2
).plot // shows the envelope
)
sig = saw.ar(freq);
sig = sig * amp;
sig = sig * env;
Out.ar(out, sig) // < = mono
}).add; // < = very important
)
// general purpose envelope
Env.new(
[0, 1, 0.5, 0.5, 0],
[0.25, 1, 2.5, 1],
-2
).plot
)
(
// good for arps?
Env.linen(0.1, 0.001, 0.1, 0.6, -2).plot
)
(
// useful for percussions
Env.perc(0.01, 1.0, 1.0, -2).plot
)
(
SynthDef.new(\saw, {
arg freq=200, amp=0.2, gate=1, out=0;
var sig, env;
// build the envelope
env = EnvGen.ar(
Env.new(
[0, 1, 0.5, 0], // amplitudes
[0.25, 1, 1], // segment durations
-2, // curve of the segment
2 // segment to be sustained
),
gate,
doneAction: 2
);
// build the sound source
sig = Saw.ar([freq, freq + 2]);
// attenuate the signal
sig = sig * amp;
// pass it trough the envelope
sig = sig * env;
Out.ar(out, sig);
}).add;
)
x = Synth.new(\saw);
x.set(\gate, 0);
// create a clock in sc
// sc tempo is in seconds, therefore divide by 60
t = TempoClock.new(185/60);
// make a clock that survives `cmd + .`
t = TempoClock.new(185/60).permanent_(true);
t.beats;
// set clock dynamically
t.tempo_(185/60);
// basic sequencer
(
p = Pbind(
\instrument, \supasaw,
\dur, 1, // patterns speed
\amp, 0.2,
\freq, Pseq([200, 100, 300], inf)
);
~seq = p.play(t);
~seq = p.play(t, quant: 4); // very important: quantization and pattern syncing!
)
~seq.stop;
~seq.resume;
SynthDef.new(\slicer, {
arg t_trig=1, buf=0, amp=0.5, slice=0, rate=1, out=0, fold_amt=0.15, clip_amt=0.15;
var sig, env, clip, fold, frames, start, duration, sustain;
rate = BufRateScale.ir(buf) * rate;
frames = BufFrames.kr(buf);
duration = frames / 32;
start = slice * duration;
sig = PlayBuf.ar(2, buf, rate, startPos: start, loop: 0);
sustain = duration/rate/s.sampleRate;
env=EnvGen.ar(
Env.new(
levels: [0,1,1,0],
times: [0,sustain-0.01,0.01],
curve:\sine,
),
gate: t_trig,
doneAction: 2;
);
fold = Fold.ar(sig, 0.0, fold_amt);
clip = Clip.ar(sig, 0.0, clip_amt);
sig = Mix.ar([sig * amp, clip, fold]);
sig = sig * amp * env;
Out.ar(out, sig);
}).add;
SynthDef.new(\slicer, {
arg t_trig=1, buf=0, amp=0.5,
slice=0, num_slices=1, rel=0.05, loops=1,
rate=1, out=0, fold_amt=0.15, clip_amt=0.15;
var sig, env, pos, clip, fold, frames, start, end, duration, sustain, pos_rate;
pos_rate = BufRateScale.ir(buf) * rate;
frames = BufFrames.kr(buf);
duration = (frames / 32) * num_slices;
start = slice * duration;
end = start + duration;
sustain = (duration / rate.abs / BufSampleRate.ir(buf)) * loops;
env = EnvGen.ar(
Env.new(
levels: [0,1,1,0],
times: [0, sustain - rel, rel],
curve: \lin
),
gate: t_trig,
doneAction: 2,
);
// phasor
pos = Phasor.ar(
trig: t_trig,
rate: pos_rate,
start: (((rate>0)*start)+((rate<0)*end)),
end: (((rate>0)*end)+((rate<0)*start)),
resetPos:(((rate>0)*start)+((rate<0)*end))
);
sig = BufRd.ar(
numChannels: 2,bufnum: buf, phase: pos, loop: 0, interpolation: 4
);
fold = Fold.ar(sig, 0.0, fold_amt);
clip = Clip.ar(sig, 0.0, clip_amt);
sig = Mix.ar([sig * amp, clip, fold]);
sig = sig * amp * env;
Out.ar(out, sig);
}).add;
// assign busses for FX
~fx0 = Bus.audio(s, 2);
~fx1 = Bus.audio(s, 2);
~fxn = Bus.audio(s, 2);
(
SynthDef.new(\saw_send, {
arg out=0, t_trig=1, freq=220, amp=0.5, fx0_mix=0.0, fx1_mix=0.0, fxn_mix=0.0;
var sig, env, detune;
detune = LFNoise1.kr(0.2!8).bipolar(0.2).midiratio;
env = EnvGen.ar(Env.Perc(0.05, 1.0, 1.0, -2), t_trig, doneAction: 2);
sig = Saw.ar(freq * detune);
sig = Splay.ar(sig) * 0.5;
sig = sig * env;
Out.ar(out, sig);
// send channels
Out(~fx0, sig * fx0_mix);
Out(~fx1, sig * fx1_mix);
Out(~fxn, sig * fxn_mix);
}).add
)
- add description to examples
- in
examples/sample-slicer/better_slicer.scd
revert to version with Clip.ar and Fold.ar for distortion to prevent errors if quarks are not compiled - Build akai style realtime stretch ✅
- reverse time stretch needs improvement 🤔
- Control Busses
- Midi connection