Making 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
:g and the numbers afterwards represent the note octave e.g.
: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
< which mean "down an octave", and "up an octave" respectively
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
nil acts like a rest when using
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.