Building a Breakbeat Drummer with Sonic Pi

- Posted in Music by

Not being able to play the drums and also not having much experience programming them, I need a high-level way of creating rhythms. So let's use Sonic Pi to make the machine take care of the hard part.

The Basic Idea

Here is what we are going to do: Let's randomly chop up the first bar of the Amen Break and assemble it into new patterns.

Moomin Holding Knife meme "Let's chop up that breakbeat"

We are going to use 8 slices - one for each cymbal hit.

The first bar of the Amen Break chopped into 8 slices

First Chops

So here is the code to create the 8 slices outlined above.

slices = 8  # number of slices
slice = 0  # try slices 0 to 7
start = slice  * 1.0/slices
sample :loop_amen, start: start, finish: start + 1.0/slices

Trying this you will get a nice kick for slice 0 and 1 - and a double kick for slice 5. The nice snare hits are - as expected - slice 2 and 6.

Randomized Chops

As a next step let's assemble a whole bar from 8 randomly selected slices. With use_sample_bpm one beat is defined as the length of one of our slices. So we just can do sleep 1 to wait for the next beat.

slices = 8
use_sample_bpm :loop_amen, finish: 1.0/slices
slices.times do
  start = (rrand_i 0, slices - 1)  * 1.0/slices
  sample :loop_amen, start: start, finish: start + 1.0/slices
  sleep 1
end

Looks like our basic idea is working.

Looping it

Whatever the random generator comes up with - we need to hear it again to make it feel like actual music. Repetition legitimizes. To make the bar repeat, we wrap it into a live loop and reset the random seed at the beginning of each bar. Thus the random generator will come up with the same numbers each time.

slices = 8
use_sample_bpm :loop_amen, finish: 1.0/slices
live_loop :drummer do
  use_random_seed 0
  slices.times do
    start = (rrand_i 0, slices - 1)  * 1.0/slices
    sample :loop_amen, start: start, finish: start + 1.0/slices
    sleep 1
  end
end

Composing with Seeds

This is a steady beat you can already play along with. But let's go one step further and compose beats by picking random seeds. Each bar gets's a number representing what is played. Here a simple 8-bar loop based on seed 21 that throws in a break on bar 4 and 8.

| 21 | 21 | 21 |  1 |
| 21 | 21 | 21 |  2 |

And here the code using knit() for shorthand:

rate = 0.7
slices = 8.0
song = knit(
  21, 3, 1, 1,
  21, 3, 2, 1,
)
use_sample_bpm :loop_amen, rate: rate, finish: 1.0/slices
live_loop :drummer do
  use_random_seed song.tick
  slices.times do
    start = (rrand_i 0, slices - 1)  * 1.0/slices
    sample :loop_amen, rate: rate, start: start, finish: start + 1.0/slices
    sleep 1
  end
end

As you will have noticed, we also added a way to set the tempo of the drummer.

Picking the good bars

Trying out random numbers is fun, but I am especially interested in bars starting with a kick. These are slice 0 and 1. Let's list the first few of these:

slices = 8
(0..100).each do |seed|
  use_random_seed seed
  start = (rrand_i 0, slices - 1)
  if start == 0.0 || start == 1.0
    puts seed
  end
end

So apparently I should try the seeds 3, 4, 8, 15, 21 …

More Things to Try

To wrap things up, here are a few ideas, what to explore when playing with this code:

  • Try 2, 4 and 16 slices.
  • Try a different :loop_*, not just the Amen Break.
  • Come up with a generative way to pick random seeds.
  • Write scripts to search for seeds producing bars with specific properties you are interested in.
  • Add rests.
  • Maybe even try crossfading chunks.

Moomin closing his knife

Meta

This blog has been very quiet, but at 38C3 I stumbled into a Sonic Pi workshop. This is where I pieced together the idea above and was reminded how much fun this is. More stuff has been in the pipeline for ages and will hopefully see the light of day soon.