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

MP3 file


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!

MP3 file


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;