Live Performance with Sonic Pi
In the past I did a 15 minute introduction for Sonic Pi for students at my University. In the following text I want to give the same short introduction either for students to look the information up or for people interested in algorithmic composition. The aim here is to show how easy it is to make a beat in Sonic Pi. The implementation is inspired by the beat grid.
Building a Beat
First we define an array containing different drum-like samples. These samples come with Sonic Pi but you can extend the sample library by your own samples.
instruments = [
:bd_haus, #1
:sn_zome, #2
:drum_cymbal_closed, #3
:drum_cymbal_pedal,
:drum_bass_soft,
:drum_bass_hard
]
We build a four by four beat, i.e., one unit is 0.25
beat.
The beat is modelled by an array of length 16
.
beats1 = [
1,0,1,0,
2,0,0,0,
1,0,0,0,
2,1,0,0
]
The idea is to address a specific sample by a number between 1
and 6
.
Zero means silence!
Therefore, beat1
starts with the sample :bd_haus
followed by silence followed by :bd_haus
and so on.
To run the beat we define a live_loop
which is a special thread of Sonic Pi.
The content of the thread can be updated dynamically, that is, the user can
- change the content,
- re-evaluate,
and the live_loop
will change accordingly.
In the loop/thread we iterate from i = 0 ... 15
.
For each iteration we play the beat according to beat1
and sleep for 0.25
beat, since we want to have a 4 times 4 beat.
live_loop :drummer1 do
16.times do |i|
sample instruments[beats1[i]-1] if beats1[i] != 0
sleep 0.25
end
end
Building a Melody
To bring a little more dynamic into the piece, we introduce a randomly generated melody. In algorithmic composition we have to find a balance between complete chaos and structure. To much chaos will sound unpleasant while too much structure is boring. Therefore, I shuffle a specific scale which gives us notes that fit together:
melody = shuffle(scale(:e4, :minor))
To play the melody we need another live_loop
.
Furthermore, I use a simple sine wave for the melody.
Also note that we play the first and second harmonic as well such that the sound is a little more complex.
It is still very simple!
use_synth :sine
live_loop :pianist do
play melody.tick, amp: 0.4
play melody.look-12, amp: 0.3
play melody.look-24, amp: 0.2
sleep 0.5
end
Building another Beat
Finally, we add another beat and therefore another live_loop
:
beats2 = [
6,0,6,0,
6,0,6,0,
6,0,6,5,
5,3,3,5
]
live_loop :drummer2 do
16.times do |i|
sample instruments[beats2[i]-1] if beats2[i] != 0
sleep 0.25
end
end
And we change the beat per minute to 98 which speeds up the whole piece:
use_bpm 98
Putting everything together
The complete code is given by the following listing:
use_bpm 98
use_synth :sine
instruments = [
:bd_haus, #1
:sn_zome, #2
:drum_cymbal_closed, #3
:drum_cymbal_pedal,
:drum_bass_soft,
:drum_bass_hard
]
beats1 = [
1,0,1,0,
2,0,0,0,
1,0,0,0,
2,1,0,0
]
beats2 = [
6,0,6,0,
6,0,6,0,
6,0,6,5,
5,3,3,5
]
melody = shuffle(scale(:e4, :minor))
live_loop :pianist do
play melody.tick, amp: 0.4
play melody.look-12, amp: 0.3
play melody.look-24, amp: 0.2
sleep 0.5
end
live_loop :drummer1 do
16.times do |i|
sample instruments[beats1[i]-1] if beats1[i] != 0
sleep 0.25
end
end
live_loop :drummer2 do
16.times do |i|
sample instruments[beats2[i]-1] if beats2[i] != 0
sleep 0.25
end
end
Performing Live
Of course this gets boring pretty fast but now we can start our live programming to change the sound over time. For example we can start by one beat, after a while start the second and the melody. Then we might want to change the melody, for example, the scale. We can change the beats as well and introduce complete new elements. Time to play ;)!