Making Chiptune Music using Sonic Pi v2.0
This example shows how to recreate the original NES Mario Bros. theme as chiptune music using Sonic Pi v2.0. It demonstrates the use of four synth types—pulse waves, triangle waves, and FM synthesis—to emulate the NES sound chip, with the melody transcribed from MML notation. The code organizes the music into threads and defines reusable patterns using Ruby lambdas, `play_pattern_timed`, and `nil` rests to structure complex rhythms. It also highlights practical constraints like interpreter size limits and platform-specific performance tweaks.
AI-generated descriptionMaking Chiptune Music using Sonic Pi v2.0
Warning: this might not work on a RaspberryPi yet
I was curious about making retro gaming sounds using Sonic Pi. A couple of months and a lot of Googling later, here's the original Mario Bros theme as it was heard on the NES console.
I'm (just about) old enough to remember rushing home from school to play this game at Philip Boucher's house, sitting cross-legged in front of the TV till my feet got pins and needles. Working out how to recreate it for Sonic Pi was a lot of fun!
Getting the sounds of the NES chip
I'm no expert on this, but the sounds of the NES chip boils down to 4 kinds of sound:
- pulse wave A (AKA square wave)
- pulse wave B
- triangle wave C
- noise D
With just these four synths the games programmers managed to make a staggering variety of sounds. If you want to compose your own chiptunes just fire up Sonic Pi with four threads like this:
in_thread do
use_synth :pulse
play 60
end
in_thread do
use_synth :pulse
play 60
end
in_thread do
use_synth :tri
play 60
end
in_thread do
use_synth :fm
use_synth_defaults divisor: 1.6666, attack: 0.0, depth: 1500, sustain: 0.05, release: 0.0
play 60
end
For the noise channel, you could use one of the noise synths that have been added in v2.0 but I've used a 'noisy' FM synth instead. The reason is that some of the drum-type sounds from the Mario theme are achieved by changing the note given to the noise chip, which produces a slightly different kind of noise. I'm not 100% sure but I think the original NES was using an FM type osciallator too.
The original Mario theme
This version is transcribed from the MML notation here: http://www.mmlshare.com/tracks/view/403
MML is a way of writing out music used in the chiptune community. Generally speaking, the letters a - g represent the notes :a through :g and the numbers afterwards represent the note octave e.g. c4 is :c4 in Sonic Pi. The difference is that notes "remember" the last octave in MML. The default octave is specified in the config line like so:
A l8 o5 @02 @v0
This says "For channel A, make the default length an 8th of a beat, make the default octave 5 (and some other stuff...)". Changes in octave are signalled by > and < which mean "down an octave", and "up an octave" respectively
so c <c e g would be :c4 :c5 :e5 :g5 in Sonic Pi. The other notation to look out for is w which means "rest" or "wait". Numbers after a note or rest indicate how long the note lasts for. w4 means a rest lasting (length of 1 bar) / 4 or one beat in this case. Hopefully that should be enough to start you transcribing any other tunes you like.
What's with all the nils?
nil acts like a rest when using play_pattern_timed
play_pattern_timed([:e5,:e5,nil,:e5,nil,:c5,:e5,nil,:g5], [0.25])
is the same as
play :e5
sleep 0.25
play :e5
sleep 0.25
# nil
sleep 0.25
play :e5
sleep 0.25
# nil
sleep 0.25
play :c5
sleep 0.25
play :e5
sleep 0.25
# nil
sleep 0.25
play :g5
sleep 0.25
You can see that using play_pattern_timed is a lot more compact for writing longer tunes! Using nil like this helps to make the rhythms more obvious too.