A great way to add some interest into your music is using some random numbers. Sonic Pi has some great functionality for adding randomness to your music, but before we start we need to learn a shocking truth: in Sonic Pi random is not truly random. What on earth does this mean? Well, let’s see.
A really useful random function is rrand
which will give you a random value between two numbers - a min and a max. (rrand
is short for ranged random). Let’s try playing a random note:
play rrand(50, 95)
Ooh, it played a random note. It played note 83.7527
. A nice random note between 50 and 95. Woah, wait, did I just predict the exact random note you got too? Something fishy is going on here. Try running the code again. What? It chose 83.7527
again? That can’t be random!
The answer is that it is not truly random, it’s pseudo-random. Sonic Pi will give you random-like numbers in a repeatable manner. This is very useful for ensuring that the music you create on your machine sounds identical on everybody else’s machine - even if you use some randomness in your composition.
Of course, in a given piece of music, if it ‘randomly’ chose 83.7527
every time, then it wouldn’t be very interesting. However, it doesn’t. Try the following:
loop do
play rrand(50, 95)
sleep 0.5
end
Yes! It finally sounds random. Within a given run subsequent calls to random functions will return random values. However, the next run will produce exactly the same sequence of random values and sound exactly the same. It’s as if all Sonic Pi code went back in time to exactly the same point every time the Run button was pressed. It’s the Groundhog Day of music synthesis!
A lovely illustration of randomisation in action is the haunted bells example which loops the :perc_bell
sample with a random rate and sleep time between bell sounds:
loop do
sample :perc_bell, rate: rrand(0.125, 1.5)
sleep rrand(0.2, 2)
end
Another fun example of randomisation is to modify the cutoff of a synth randomly. A great synth to try this out on is the :tb303
emulator:
use_synth :tb303
loop do
play 50, release: 0.1, cutoff: rrand(60, 120)
sleep 0.125
end
So, what if you don’t like this particular sequence of random numbers Sonic Pi provides? Well it’s totally possible to choose a different starting point via use_random_seed
. The default seed happens to be 0, so choose a different seed for a different random experience!
Consider the following:
5.times do
play rrand(50, 100)
sleep 0.5
end
Every time you run this code, you’ll hear the same sequence of 5 notes. To get a different sequence simply change the seed:
use_random_seed 40
5.times do
play rrand(50, 100)
sleep 0.5
end
This will produce a different sequence of 5 notes. By changing the seed and listening to the results you can find something that you like - and when you share it with others, they will hear exactly what you heard too.
Let’s have a look at some other useful random functions.
A very common thing to do is to choose an item randomly from a list of known items. For example, I may want to play one note from the following: 60, 65 or 72. I can achieve this with choose
which lets me choose an item from a list. First, I need to put my numbers in a list which is done by wrapping them in square brackets and separating them with commas: [60, 65, 72]
. Next I just need to pass them to choose
:
choose([60, 65, 72])
Let’s hear what that sounds like:
loop do
play choose([60, 65, 72])
sleep 1
end
We’ve already seen rrand
, but let’s run over it again. It returns a random number between two values exclusively. That means it will never return either the top or bottom number - always something in between the two. The number will always be a float - meaning it’s not a whole number but a fraction of a number. Examples of floats returned by rrand(20, 110)
:
Occasionally you’ll want a whole random number, not a float. This is where rrand_i
comes to the rescue. It works similarly to rrand
except it may return the min and max values as potential random values (which means it’s inclusive rather than exclusive of the range). Examples of numbers returned by rrand_i(20, 110)
are:
This will return a random float between 0 (inclusive) and the max value you specify (exclusive). By default it will return a value between 0 and one. It’s therefore useful for choosing random amp:
values:
loop do
play 60, amp: rand
sleep 0.25
end
Similar to the relationship between rrand_i
and rrand
, rand_i
will return a random whole number between 0 and the max value you specify.
Sometimes you want to emulate a dice throw - this is a special case of rrand_i
where the lower value is always 1. A call to dice
requires you to specify the number of sides on the dice. A standard dice has 6 sides, so dice(6)
will act very similarly - returning values of either 1, 2, 3, 4, 5, or 6. However, just like fantasy role-play games, you might find value in a 4 sided dice, or a 12 sided dice, or a 20 sided dice - perhaps even a 120 sided dice!
Finally you may wish to emulate throwing the top score of a dice such as a 6 in a standard dice. one_in
therefore returns true with a probability of one in the number of sides on the dice. Therefore one_in(6)
will return true with a probability of 1 in 6 or false otherwise. True and false values are very useful for if
statements which we will cover in a subsequent section of this tutorial.
Now, go and jumble up your code with some randomness!