I'm teaching some more 101 level programmer classes and this time we're looking at Sonic Pi as an introduction to text-based languages after playing with the building blocks of Scratch. I chose Sonic Pi because of it's immediacy of interaction and fast feedback going from typing code to seeing (or hearing) a result.

First Steps

The first and simplest program you can write is a one liner to play a single note. Like this


play 60

Changing the numeric value changes the pitch of the note, lower values are lower in pitch, higher values are higher in pitch.

You can play two notes separated by small pause like this:


play 60
sleep 0.5
play 62

Notes are processed top to bottom in order. Sleep puts a pause in the program of that many seconds before playing the next note. If the sleep wasn't there, both notes would play together. Increasing and decreasing the sleep value changes length of the piece.

Columbo Moment

One thing to mention before we go too far, as this is a text based language, spelling, case (upper and lower and mixed) and punctuation really matter. Things which are spelled differently really are different things to the computer, even if you didn't intend them to be different.

Repeats

Music is often about repetition so it's good to be able to repeat phrases and there are a number of different ways that Sonic Pi supports this. An easy one is repeating something a number of times:


5.times do
  play 60
  sleep 1
end

Maybe not terribly exciting but we can move on from there to do scales:


# play a chromatic scale
note = 60

12.times do
  play note
  note = note + 1
  sleep 0.5
end

C Chromatic scale


10.times do
  play chord(:E3, :major).choose
  sleep 1
end
  
root = 55
  
play root # C3
sleep 0.5
play root + 1
sleep 0.5
play root + 2
sleep 0.5
play root + 3
sleep 0.5
play root + 4
sleep 0.5
play root + 5
sleep 0.5
play root + 6
sleep 0.5
play root + 7
sleep 0.5
play root + 8
sleep 0.5
play root + 9
sleep 0.5
play root + 10
sleep 0.5
play root + 11
sleep 0.5
play root + 12 # C4
sleep 0.5
  
root = 50
note = root

12.times do
  play note
  sleep 0.5
  note = note + 1
end
  

use_bpm 52

live_loop :bass do
  [:d2, :a2, :b2, :g2].each do |n|
    8.times do
      #      with_fx :rlpf do
      play n, release: 0.2
      #      end
      sleep 0.25
    end
  end
end

live_loop :kick do
  #  sync :bass
  sample :drum_bass_hard
  with_fx :slicer do
    sample :drum_bass_hard
  end
  sleep 0.5
end

chord(:e3, :major7).each do |n|
  play n
  sleep 0.5
end
live_loop :test do

  sample :bd_haus, rate: 1
  sleep 0.5

end

loop do
  play choose(chord(:e3))
  sleep 2
end

loop do
  with_fx :flanger do
    sample :ambi_haunted_hum, rate: (rrand 1.0, 2.5)
    sleep (rrand 0, 2)
    sample :perc_bell, rate: (rrand 1.0, 2.5)
    sleep rrand(0, 2)
  end
end


live_loop :foo do
  use_synth :prophet
  play :e2, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

live_loop :bar do
  #use_synth :dark_ambience
  #play :c5
  #sample :bass_voxy_hit_c
  #sample :guit_e_fifths
  #sample :bd_haus
  play (ring :d, :r, :r, :a, :f5, :r, :a, :r).tick
  sleep 0.25
end