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!
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.
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.
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.
Forked from original by @xavriley with minor tweak to use
_
instead ofnil
for better readability (also shorter).