Back in part four of the series (The MagPi issue 39), we looked at randomisation while coding some sizzling synth riffs. Since randomisation is an important part of my live-coding DJ sets, we thought it would be useful to cover the fundamentals in detail. So get your lucky hat on; let’s surf some random streams!
The full article can be found in Sonic Pi Essentials along with even more Sonic Pi tutorials! All the Essentials books are now also available in print.
Raspberry Pi running Raspbian
Sonic Pi v2.7+. Update with:
sudo apt-get update && sudo apt-get install sonic-pi
Speakers or headphones with a 3.5mm jack
There is no random
The first surprise when playing with the randomisation functions is that they’re not random. What does this mean? Let’s try some tests. Imagine a number in your head between 0 and 1, but don’t tell me. Now let me guess... was it ‘0.321567’? No? I’m no good at this. Let me try again, but let’s ask Sonic Pi to choose a number. Start Sonic Pi v2.7+ and ask it for a random number, but don’t tell me:
Now for the reveal... was it ‘0.75006103515625’? Yes! I can see you’re sceptical; it was a lucky guess. Let’s try again. Press the Run button again and see what we get... The same again? This clearly can’t be random! You’re right, it’s not.
What’s going on? The fancy computer science term is determinism. This means that nothing is by chance and everything is destined to be. Sonic Pi is destined to always return ‘0.75006103515625’ in the program above. It may sound useless, but in fact it’s one of the most powerful parts of Sonic Pi. If you persevere, you’ll learn how to rely on the deterministic nature of Sonic Pi’s randomisation as a fundamental building block to your compositions and live-coded DJ sets.
A random tune
When Sonic Pi boots, it actually loads into memory a sequence of 441,000 pre-generated random values. When you call a random function such as rand or rrand, this random stream is used to generate your result. Each call to a random function uses a value from this stream, so the tenth call to a random function will use the tenth value from the stream. Also, every time you press Run, the stream is reset for that run. That’s why you can predict the result to rand and why the ‘random’ tune was the same every time. Everybody’s version of Sonic Pi uses the same random stream, which is important when we start sharing our pieces with each other.
Let’s use this knowledge to generate a repeatable random tune:
8.times do play rrand_i(50, 95) sleep 0.125 end
Type this into a spare buffer and press Run. You’ll hear a tune consisting of ‘random’ notes between 50 and 95. When it’s ended, press Run again to hear exactly the same tune again.
Resetting the stream
While repeating a sequence of notes is essential for replaying a riff on the dance floor, it might not be the one you want. Wouldn’t it be great if we could try a number of different riffs and choose the one we liked best? This is where the real magic starts.
We can manually set the stream with the function userandomseed. In computer science, a random seed is the starting point for a new stream of random values. Let’s try it:
use_random_seed 0 3.times do play rrand_i(50, 95) sleep 0.125 end
Great, we get the first three notes of our tune above: 84, 83, and 71. We can now change the seed to something else, like this:
use_random_seed 1 3.times do play rrand_i(50, 95) sleep 0.125 end
We get 83, 71, and 61. You may spot that the first two numbers are the same as the last two numbers before – no coincidence.
The random stream is just a giant list of ‘pre-rolled’ values. Using a random seed simply jumps us to a point in that list. Imagine a big deck of pre-shuffled cards. Using a random seed is cutting the deck at a particular point. The great part of this is that it’s this ability to jump around the random list which gives us power when making music.
Let’s revisit our random eight-note tune with this new power, and also add a live loop so we can experiment live while it’s playing:
live_loop :random_riff do use_random_seed 0 8.times do play rrand_i(50, 95), release: 0.1 sleep 0.125 end end
While it’s still playing, change the seed value from 0 to something else. Try 100, or 999. Try your own values and experiment – see which seed generates the riff you like best.
Bringing it all together
This tutorial has been quite a technical dive into the workings of Sonic Pi’s randomisation functionality. Hopefully, it’s explained how it works and how you can start using randomisation reliably to create repeatable patterns in your music. Crucially, you can use repeatable randomisation anywhere: the amplitude of notes, the timing of the rhythm, amount of reverb, current synth, the mix of an FX, etc. In the future we’ll take a close look at these, but for now I’ll end with a short example.
Type the code below into a spare buffer, press Run, then change the seeds. Press Run again while it’s playing, and explore the different sounds, rhythms, and melodies you can make. When you find a nice one, note the seed number so you can return to it. Once you’ve found a few seeds you like, put on a live-coded performance by simply switching between your favourite seeds to make a full piece.
live_loop :random_riff do use_random_seed 10300 use_synth :prophet s = [0.125, 0.25, 0.5].choose 8.times do r = [0.125, 0.25, 1, 2].choose n = (scale :e3, :minor).choose co = rrand(30, 100) play n, release: r, cutoff: co sleep s end end live_loop :drums do use_random_seed 2001 16.times do r = rrand(0.5, 10) sample :drum_bass_hard, rate: r, amp: rand sleep 0.125 end end