Examples to work on
Basic use of Sonic Pi as a musical instrument. Try programming these 2-bar loops:
- Dr. Dre

- Kanye West (producer)

Chaining effects for total sonic destruction!
Example from the workshop:
live_loop :asdfadsf do
with_fx :gverb, amp: 0.6 do
with_fx :whammy do
with_fx :autotuner do
with_fx :tremolo, phase: 1 do
with_fx :ping_pong do
with_fx :krush, mix: 0.0 do
with_fx :bitcrusher do
with_fx :echo do
##| with_fx :autotuner, mix: 0.8 do
with_fx :slicer, phase: 1.0/4, mix: 0.2 do
with_fx :octaver, mix: 0.5 do
with_fx :ixi_techno do
with_fx :distortion, distort: 0.9 do
synth :sound_in_stereo, amp: 0.5, sustain: 4
# pipe in your sound
sleep 4
end
end
end
end
end
end
end
end
end
end
end
end
end
Technically, the effects should be outside the live_loop
.
You also probably want to control effect parameters (e.g., filter cutoff frequencies) while they are active.
Also, beyond pure distortion-type effects, experiment with sampling and chopping up the samples, using them for granular synthesis, etc. (the main limitation using pure Sonic Pi is that Supercollider effects need to be pre-compiled).
Smoothing out harmony
This example plays a list of 4-note chords. They are converted to arrays and passed to the
voicelead
function.
puts 'start'
use_synth :fm
use_synth_defaults sustain: 4*0.95, release: 4*0.05
define :soundit do |n, t|
a = 0.05
b = 0.2
use_synth :fm
play n, attack: 0, decay: a, sustain_level: 0.5, release: b, sustain: t-(a+b), pan: 0.2
end
define :myarp do |c|
with_synth :prophet do
play c, sustain: 0.95, release: 0.05, amp: 0.3, pan: -0.4
end
c.ring.reflect.to_a[0..-2].each { |n| soundit n, 0.25 ; sleep 0.25 }
end
use_bpm 120
n=2
TESTLIST = [
(chord :a4, :major, num_octaves: 2).to_a[0..3],
(chord :a4, '7').to_a,
(chord :d4, '7').to_a,
(chord :d4, :major, num_octaves: 2).to_a[0..3],
(chord :a4, :major, num_octaves: 2).to_a[0..3],
(chord :a4, '7').to_a,
(chord :fs4, '7').to_a,
(chord :c4, '7').to_a,
(chord :f3, :major, num_octaves: 2).to_a[0..3],
(chord :a4, :minor, num_octaves: 2).to_a[0..3],#rotate
(chord :f4, :major, num_octaves: 2).to_a[0..3],
(chord :a4, :minor, num_octaves: 2).to_a[0..3].rotate,
(chord :c4, :m7).to_a,
(chord :f4, :minor, num_octaves: 2).to_a[0..3],
(chord :f4, :major, num_octaves: 2).to_a[0..3],
[:bb3, :d4, :ab4, :c5].map! { |n| note(n) }##| (chord :bb3, '7').to_a
].ring
use_random_seed Time.now.to_i.freeze
with_fx :reverb, room: 0.4 do
live_loop :test123 do
if !defined?($tc)
$tc = TESTLIST[0]
end
nc = TESTLIST[tick]
p = voicelead($tc, nc, (knit 1,4,2,1).choose)
$tc = p
$tc = shuffle $tc if one_in(16)
puts $tc
n.times { myarp $tc }
end
end
Sample manipulation from the workshop
THESAMPLE = "PUT YOUR SAMPLE HERE"
load_sample THESAMPLE
use_random_seed Time::now.to_i
live_loop :blabla do
n = rrand_i(16,1024)
sample THESAMPLE, pan: 0.4, compress: 1, pre_amp: 16, num_slices: n, slice: (0..n-1).to_a.choose
sleep sample_duration(THESAMPLE) / n
end
with_fx :ping_pong do
with_fx :bpf, centre_slide: 4, mix: 1.0, amp: 1.2 do |ff|
live_loop :longfart do
mult = (doubles 1,5).choose
n = 16
with_fx :reverb, room: 0.4 do
sample THESAMPLE, beat_stretch: mult, compress: 1, pre_amp: 16, num_slices: n, slice: (0..n-1).to_a.choose
sleep mult*1.0 / n
end
control ff, centre: hz_to_midi(rrand(100,2000)) if one_in(8)
end
end
end
Constraint-based programming
In this example, only the bass notes were specified. Sonic Pi then harmonizes on top of it by calculating all the other notes (only octaves/unisons, thirds, fifths, and sixths were allowed in the following output). Surely you can do better!

Supercollider live-loop example
/*
Supercollider exercise from the workshop
*/
s.boot; // boot the server
StageLimiter.activate; // automatically puts in a global limiter--
// install it from the BatLib quark
// define a couple of patches:
(
SynthDef(\organ_reed, {
//Reed Organ Simulation
|out = 0, freq = 440, amp = 0.1, gate = 1, attack = 0.3, release = 0.3, pan = 0.0|
var snd, blow;
// pulse with modulating width
snd = Pulse.ar((Rand(-0.03, 0.05) + freq.cpsmidi).midicps, 0.48 + LFNoise1.kr(0.06, 0.1), 0.2);
// add a little "grit" to the reed
snd = Disintegrator.ar(snd, 0.5, 0.7);
// a little ebb and flow in volume
snd = snd * LFNoise2.kr(5, 0.05, 1);
// use the same signal to control both the resonant freq and the amplitude
blow = EnvGen.ar(Env.asr(attack, 1.0, release), gate, doneAction: 2);
snd = snd + BPF.ar(snd, blow.linexp(0, 1, 2000, 2442), 0.3, 3);
// boost the high end a bit to get a buzzier sound
snd = BHiShelf.ar(snd, 1200, 1, 3);
snd = snd * blow;
Out.ar(out, Pan2.ar(snd, pan, amp));
//By Nathan Ho aka Snappizz
//http://sccode.org/1-51m
}).add;
SynthDef(\violin, {
| out=0,midinote=60, gate=1, amp=0.8 |
var env = EnvGen.kr(Env.asr(0.1, 1, 0.1), gate, doneAction:2);
var sig = VarSaw.ar(
midinote.midicps,
width:LFNoise2.kr(1).range(0.2, 0.8)*SinOsc.kr(5, Rand(0.0, 1.0)).range(0.7,0.8))*0.25;
sig = sig * env * amp;
Out.ar(out, sig!2);
//It is also used for simulating Farfisa organ and flutes
//by nicolaariutti
//http://sccode.org/1-5as
}).add;
)
(
// define a ProxySpace for convenient live coding
p = p ? ProxySpace.new;
p.quant = 4;
p.fadeTime = 2;
p.push
)
/*
Main example: for the purposes of this exercise, define a simple sequence of chords
and scales for improvised accompaniment
*/
(
var mychords, acc;
mychords = [[-5,0,4,7],[-3,-1,4,8],[-6,1,5,10],[-3,-1,4,9],[-3,-1,4,8]];
// Should be something like: I, V, II, III, V
// You can experiment with different chords; if you do, change acc below so it sounds good
acc = // these notes are defined relative to the root of each chord; see the loop ~x below
// Here we just harmonize with the chord notes; nothing musically exciting
// is going on in terms of melody generation
[Scale.new(#[0, 2, 4, 7, 9, 11], 12),
Scale.new(#[0,2,4,7,9,10],12),
Scale.new(#[0,2,3,5,7,10],12),
Scale.new(#[0,3,5,7,10],12),
Scale.new(#[0,2,4,7,9,10],12),
];
~ch =
Pbind(*[
instrument: \organ_reed,
amp: 0.5,
scale: Scale.major,
root: -12,
degree: Pseq(mychords, inf),
dur: 4,
legato: 0.95,
pan: -0.7
]);
~x =
Pbind(*[
instrument: \violin,
amp: 1.0,
scale: Pstep(Pseq(acc, inf), 4, inf),
root: Pstep(Pseq([0,7,2,4,7],inf), 4, inf),
//degree: Pxrand((-7..7), inf),
degree: Pwalk((-7..7), Pwrand([-3,-2,-1,1,2,3],[1,2,5,5,2,1].normalizeSum,inf), Pseq([1,-1],inf)),
dur: Psubdivide(Pseq(#[1], inf), Prand(#[1,0.5,2],inf));
]);
// some distortion
// Based on code from http://new-supercollider-mailing-lists-forums-use-these.2681727.n2.nabble.com/Distortion-effect-tp5173262p5173287.html
~x[1] = \filter ->
{ |in, amount=0.99|
var amCoef, input;
amCoef= 2*amount/(1-amount);
input = HPF.ar(in, 400)*5;
MidEQ.ar(LPF.ar((1+amCoef)*input/(1+(amCoef*input.abs)), [3800, 3900])*0.5, 120, 0.7, 8);
};
~delayed = ~ch + (0.5*~x);
~all = { // delay effect
// Based on code from http://permalink.gmane.org/gmane.comp.audio.supercollider.user/77153
|imp=1, lag=3, maxLag=0.2, decayTime=6|
var input, newOut, delayTime, laggedDelayTime, outDelay;
input = ~delayed.ar;
// Delay time jumps on impulse
delayTime = Demand.kr(Impulse.kr(imp), 0, Dseq([0.3], inf));
// Amount of time to reach new value
laggedDelayTime = Lag.kr(delayTime, lag);
// CombC - delay with feedback
CombC.ar(input, maxLag, laggedDelayTime, decayTime) + input;
};
~x.set(\amount, 0.9); // distortion amount
~all.set(\imp, 0.15, \lag, 0.25, \maxLag, 0.5, \decayTime, 4); // delay parameters
~all.play;
)
// to fade out the sound:
~all.clear(4);
p.clear;
p.pop;
s.quit;