Way back in part three of this Sonic Pi series, we looked at how to loop, stretch, and filter one of the most famous drum breaks of all time: the Amen Break. In this tutorial, we’re going to take this one step further and learn how to slice it up, shuffle the slices, and glue it back together in a completely new order. If that sounds a bit crazy to you, don’t worry: it will all become clear and you’ll soon master a powerful new tool for your live‑coded sets.
The full article can be found in The MagPi 45 and was written by Sam Aaron
Sound as data
Before we get started, let’s just take a brief moment to understand how to work with samples. By now, you have all hopefully played with Sonic Pi’s powerful sampler. If not, there’s no time like the present! Boot up your Raspberry Pi, launch Sonic Pi from the Programming menu, type the following line into a fresh buffer, and then hit the Run button to hear a pre-recorded drum beat:
sample :loop_amen
A recording of a sound is simply represented as data: lots of numbers between -1 and 1, which represent the peaks and troughs of the sound wave (see the boxout to the right for more information). If we play those numbers back in order, we get the original sound. However, what’s to stop us from playing them back in a different order and creating a new sound?
How are samples actually recorded?
It’s actually pretty simple once you understand the basic physics of sound. When you make a sound - for example, by hitting a drum –the noise travels through the air in a similar fashion to the way the surface of a lake ripples when you throw a pebble into it. When those ripples reach your ears, your eardrum moves sympathetically and converts those movements into the sound you hear. If we wish to record and play back the sound, we therefore need a way of capturing, storing, and reproducing those ripples. One way is to use a microphone, which acts like an eardrum and moves back and forth as the sound ripples hit it. The microphone then converts its position into a tiny electric signal, which is then measured many times a second. These measurements are then represented as a series of numbers between -1 and 1.
If we were to plot a visualisation of the sound, it would be a simple graph of data with time on the x axis and microphone/speaker position as a value between -1 and 1 on the y axis. You can see an example of such a graph at the top of the image above.
Playing part of a sample
So, how do we code Sonic Pi to play a sample back in a different order? To answer this question, we need to take a look at the start: and finish: opts for sample. These let us control the start and finish positions of our playback of the numbers which represent the sound.
The values for both of these opts are represented as a number between 0 and 1, where 0 represents the start of the sample and 1 is the end.So, to play the first half of the Amen Break, we just need to specify a finish: of 0.5:
sample :loop_amen, finish: 0.5
We can add in a start: value to play an even smaller section of the sample:
sample :loop_amen, start: 0.25, finish: 0.5
For fun, you can even have the finish: opt’s value set before start:, in which case it will play the section backwards:
sample :loop_amen, start: 0.5, finish: 0.25
Reordering sample playback
Now that we know that a sample is simply a list of numbers that can be played back in any order, and also how to play a specific part of a sample, we can start having fun playing a sample back in the ‘wrong’ order.
Let’s take our Amen Break and chop it up into eight equally sized slices, and then shuffle those pieces around to create a new drum break.
Take another look at the image at the top of this page: at the top, A) represents the graph of our original sample data. Chopping it into eight slices gives us B) – notice that we’ve given each slice a different colour to help distinguish them. You can see each slice’s start and finish values at the top. Finally, C) is one possible reordering of the slices. We can then play this back to create a new beat. Take a look at the code to do this:
live_loop :beat_slicer do slice_idx = rand_i(8) slice_size = 0.125 s = slice_idx * slice_size f = s + slice_size sample :loop_amen, start: s, finish: f sleep sample_duration :loop_amen, start: s, finish: f end
Let’s analyse this piece of code to see precisely what is going on at each stage…
We choose a random slice to play, which should be a random number between 0 and 7 (remember that we start counting at 0). Sonic Pi has a handy function for exactly this: randi(8). We then store this random slice index in the variable sliceidx.
We define our slicesize, which is 1 divided by the number of slices (8), or 0.125. We need this to convert our sliceidx into a slice starting position, as a value between 0 and 1. For example, the slice with index 3 starts three slices into the sample: 3 * 0.125, or 0.375.
We calculate the start position s by multiplying the sliceidx by the slicesize.
We calculate the finish position f by adding the slice_size to the start position s.
We can now play the slice by plugging in the s and f values into the start: and finish: opts for sample.
Before we play the next slice, we need to know how long to sleep, which should be the duration of the sample slice. Luckily, Sonic Pi has us covered with sampleduration, which accepts all the same opts as sample and simply returns the duration. So, by passing sampleduration to our start: and finish: opts, we can find out the duration of a single slice.
We wrap all of this code in a live_loop so that we continue to pick new random slices to play.
Bringing it all together
Let’s combine everything we’ve seen so far into a final example which demonstrates how we can take a similar approach to combine randomly sliced beats with some bass to create the start of an interesting track. Now it’s your turn: take this code as a starting point and see if you can create something new...
liveloop :slicedamen do
n = 8
s = line(0, 1, steps: n).choose
f = s + (1.0 / n)
sample :loopamen, beatstretch: 2, start: s, finish: f
sleep 2.0 / n
end
liveloop :acidbass do
with_fx :reverb, room: 1, reps: 32, amp: 0.6 do
tick
n = (octs :e0, 3).look - (knit 0, 3 * 8, -4, 3 * 8).look
co = rrand(70, 110)
synth :beep, note: n + 36, release: 0.1, wave: 0, cutoff: co
synth :tb303, note: n, release: 0.2, wave: 0, cutoff: co
sleep (ring 0.125, 0.25).look
end
end