Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Variables and Functions

Clean code makes complex music manageable. Functions are the building blocks of every track in this album.

Why Functions?

Without functions, a drum pattern looks like this:

sample :bd_tek, amp: 2, rate: 0.9
sample :bd_boom, amp: 0.5, rate: 1.2
sleep 1
sample :bd_tek, amp: 2, rate: 0.9
sample :bd_boom, amp: 0.5, rate: 1.2
sleep 1
# ... repeated dozens of times

With functions:

define :kick do
  sample :bd_tek, amp: 2, rate: 0.9
  sample :bd_boom, amp: 0.5, rate: 1.2
end

kick; sleep 1
kick; sleep 1
# Much cleaner!

Defining Functions

Basic syntax:

define :function_name do
  # Code here
end

Then call it:

function_name

Example: Kick Drum

define :kick do
  sample :bd_tek, amp: 2, rate: 0.9
end

# Use it
4.times do
  kick
  sleep 1
end

Functions with Parameters

Parameters make functions flexible:

define :kick do |volume|
  sample :bd_tek, amp: volume, rate: 0.9
end

kick 2      # Loud kick
kick 0.5    # Quiet kick
kick 1      # Normal kick

Multiple Parameters

define :kick do |volume, pitch|
  sample :bd_tek, amp: volume, rate: pitch
end

kick 2, 0.9    # Loud, slightly lower
kick 1, 1.2    # Normal volume, higher pitch

Default Parameters

This is the pattern used throughout the album:

define :kick do |v=1|
  sample :bd_tek, amp: 2*v, rate: 0.9
end

kick        # Uses default v=1, so amp = 2*1 = 2
kick 0.5    # v=0.5, so amp = 2*0.5 = 1
kick 1.2    # v=1.2, so amp = 2*1.2 = 2.4

The v=1 means “if no value provided, use 1”.

Multiple Defaults

define :bass do |n, v=1, c=80|
  use_synth :tb303
  play n, amp: v, cutoff: c
end

bass :d2           # note=D2, v=1, cutoff=80
bass :d2, 0.5      # note=D2, v=0.5, cutoff=80
bass :d2, 0.5, 60  # note=D2, v=0.5, cutoff=60

The Sound Functions Pattern

Every track defines sound functions first:

# SOUND DEFINITIONS
define :kick do |v=1|
  sample :bd_tek, amp: 2*v, rate: 0.9
  sample :bd_boom, amp: 0.5*v, rate: 1.2
end

define :snare do |v=1|
  sample :sn_dub, amp: v, rate: 0.85
end

define :hat do |v=1|
  sample :drum_cymbal_closed, amp: 0.3*v, rate: 2.2
end

define :bass do |n, v=1, c=80|
  use_synth :tb303
  play n, amp: 0.8*v, cutoff: c, res: 0.3
  use_synth :sine
  play n-12, amp: v
end

Then pattern functions:

# PATTERN DEFINITIONS
define :drums do |k=1, s=1, h=1|
  # Uses the sound functions defined above
  in_thread do
    4.times { kick k; sleep 1 }
  end
  in_thread do
    sleep 1; snare s; sleep 1; snare s; sleep 2
  end
  in_thread do
    8.times { hat h; sleep 0.5 }
  end
  sleep 4
end

define :bassline do |v=1, c=80|
  bass :d2, v, c; sleep 1
  bass :d2, v*0.7, c-10; sleep 1
  bass :f2, v*0.9, c; sleep 1
  bass :d2, v, c; sleep 1
end

Variables

Variables store values for reuse:

my_note = :c4
my_volume = 0.8

play my_note, amp: my_volume

Variables in Patterns

define :melody do |v=1|
  notes = [:d4, :f4, :a4, :g4, :f4, :d4]
  
  notes.each do |n|
    play n, amp: v
    sleep 0.5
  end
end

Arrays for Patterns

define :arp do |v=1|
  pattern = [:d4, :f4, :a4, :d5, :a4, :f4, :d4, :a3]
  
  pattern.each do |n|
    use_synth :pulse
    play n, amp: 0.25*v, release: 0.1
    sleep 0.5
  end
end

Local vs Global

Variables inside define are local:

define :example do
  x = 10  # Only exists inside this function
end

# x doesn't exist here

Variables outside are global:

$global_volume = 0.8  # Available everywhere

define :example do
  play :c4, amp: $global_volume
end

We rarely use global variables — parameters are cleaner.

The Complete Pattern

Here’s the structure used in every album track:

use_bpm 100

# 1. SOUND DEFINITIONS
define :kick do |v=1|
  # ...
end

define :snare do |v=1|
  # ...
end

define :bass do |n, v=1, c=80|
  # ...
end

# 2. PATTERN DEFINITIONS
define :drums do |k=1, s=1, h=1|
  # Uses sound functions
end

define :bassline do |v=1, c=80|
  # Uses bass function
end

# 3. ARRANGEMENT
# Intro
8.times { drums 0.7, 0, 0.5 }

# Main
16.times { drums 1, 0.9, 0.8 }

This separation makes code:

  • Readable — Clear what each section does
  • Reusable — Same sounds, different patterns
  • Tweakable — Change one function, affect everywhere

Next: Threads — how to play multiple parts simultaneously.