The Nintendo Entertainment System (NES) was released in North America in 1985, two years after its release in Japan where it was known as the Family Computer (Famicom). It enjoyed a particularly long life, remaining in production for nearly 10 years. Over these years, hundreds of games were released for the console, and it could certainly be argued that it earned the title of king of the 8-bit generation. One of the most memorable aspects of the NES was its distinctive sound—the cute chip melodies many of us can still easily recall today.
However, maybe it’s time to stop humming the theme from Super Mario Bros. and start composing your own music for this legendary console. This is where MCK/MML comes in, a toolset that provides you with everything needed in order to program original tunes for the NES. So let’s get to it!
The first step is to download the necessary files. The first four files are available from http://www.geocities.co.jp/Playtown-Denei/9628/:
mck_0228.zip
|
mckc025.zip
|
dmcconv005.zip
|
mckc-e.txt
|
This file is available from http://www.magicengine.com/mkit/download.html:
mkit251_dos.zip
|
Create a folder called workspace, and unzip all
files contained in mck_0228.zip and
mckc025.zip into this folder. Now extract only
nesasm.exe from
mkit251_dos.zip into this same folder. Next,
create a new folder inside workspace called
DMCconv, and extract the files from
dmcconv005.zip into this folder.
Create a new text file, call it songdata.mml,
and place it in your workspace folder. This is
the text file from which you will use the Music Macro Language (MML)
to program your tune. First, open make_nsf.txt,
and scroll to the end of the file where you will find several
.include statements. After the last one, add
this line to the file: .include "songdata.h".
Also look for these lines in make_nsf.txt:
.org $800E db "Song Name" db $00 .org $802E db "Artist" db $00 .org $804E db "Maker" db $00
This is the part of the NSF header that identifies the tune. Modify these header fields appropriately, as shown next (be aware that there is a 31-character limit for each):
.org $800E db "My First NES Chip" db $00 .org $802E db "Nullsleep" db $00 .org $804E db "2003 Jeremiah Johnson" db $00
Create a new text file, open it up, and type the following:
mckc_e songdata.mmldel nesmusic.nsfnesasm -raw make_nsf.txtren make_nsf.nes nesmusic.nsf
Save the file, close it, and rename it
build.bat; this is a simple batch file that will
run all the commands to generate an NSF file from the MML data. By
this point, everything should be set up properly, and you can get
started programming MML.
Just like a normal song with a key, a time signature, and musical staves, a MML song needs several pieces of information.
After opening up songdata.mml in your preferred
text editor, you should add header lines to the top of the file;
these identify yourself as the composer and note the title of the
song. For example:
#TITLE My First NES Chip #COMPOSER Nullsleep #PROGRAMER 2003 Jeremiah Johnson
Note that the incorrect spelling of #PROGRAMER is
a typo within MCK itself.
The NES has five channels that are defined in MML as:
First pulse channel
Second pulse channel
Triangle channel
Noise channel
DPCM channel
This hack covers the programming conventions for each channel; because their operation is identical, A and B are covered together.
Tempo can be set individually for each channel; however,
it’s likely that you will usually want all channels
to play at the same speed to keep everything in sync. The tempo for
all channels can be set simultaneously by typing ABCDE t150.
In MML notation, this says: for channels A, B, C, D, and E, set the tempo to 150 beats per minute. The valid range of values for the tempo is 1 to 255.
The pulse wave channels (A and B) and the noise channel (D) of the
NES have volume control, while the triangle wave channel (C) and the
DPCM channel (E) can only be turned on or off. For the pulse and
noise channels, there are two options for setting volume. The first
is to just set a constant volume level: A v15.
This sets the volume level for channel A to 15. However, in most cases, using a volume envelope is a better choice. Here’s a volume envelope example:
@v0 = { 10 9 8 7 6 5 4 3 2 }The volume envelope takes values between 0 and 15. The highest volume is 15; 0 is silence. The last value is held until another note is played. Note that if neither a constant volume nor a volume envelope is defined for the pulse channels (A and B) or the noise channel (D), you won’t hear any sound output on these channels.
The next step is to set up each channel individually with the properties it requires. Here is a standard setup for a pulse wave channel:
A l8 o4 @01 @v0
For channel A, this translates to:
Set the default note length to eighth notes.
Set the octave to the fourth octave.
Set the duty cycle to 01 (25% duty cycle).
Use volume envelope 0 (defined earlier).
Think of a pulse wave as a square wave with a variable width. In a square wave, the width is fixed at 50% (half up and half down), but pulse waves have more flexibility. This flexibility is referred to as the duty cycle (or sometimes the timbre) of the pulse wave. Here are the four possible duty cycle settings for the pulse wave channels on the NES:
_
00 | | | 12.5% thin raspy sound
| |_ _ _ _ _ _ _ _|
_ _ _
01 | | | 25% thick fat sound
| |_ _ _ _ _ _ _|
_ _ _ _
02 | | | 50% smooth clear sound
| |_ _ _ _ _|
_ _ _ _ _ _
03 | | | 75% same as 25% but phase-inverted
| |_ _ _|Now that the pulse channel (A) is set up, here’s an example of a note sequence that can be programmed on it:
A c d e f g4 a16 b16 >c c d e f g4 a16 b16 >c<<
If you know standard music notation, most of this should look familiar. Basically, it’s just note values followed by note lengths. Create sharps or flats by adding either a + or -, respectively, after the note value. The notes in an octave, as seen on a piano keyboard are:
c+ d+ f+ g+ a+ | # # | # # # | additionally: | # # | # # # | r = rest | # # | # # # | w = wait (rest without silencing |__|__|__|__|__|__|__| the previous note) c d e f g a b
Because the default note length for channel A is set to eighth notes, this melody plays c d e f notes for an eighth length each, then the g note for a quarter length, followed by the a and b notes for a sixteenth length each. Next is the > symbol, which switches an octave up (to the fifth octave), and then the c eighth note plays. Now the scale repeats again before finally switching back down two octaves (to the original fourth octave set for the channel). Additionally, in reference to note duration, it’s possible to use dotted notes. Dotting a note increases the duration of that note by half its value. These examples should help illustrate this:
C note played for an eighth plus a sixteenth
D note played for a quarter plus an eighth
E note played for a quarter plus an eighth plus a sixteenth
F note played for a half plus a quarter plus an eighth
Now, getting back to the previous example programmed on the first pulse wave channel (A), notice that this sequence plays only once. The full sequence or small portions of it can be looped using brackets followed by a loop count, as shown here:
A [c d e f g4 a16 b16 >c c d e f g4 a16 b16 >c<<]2
This loops the entire sequence twice, which can be handy for keeping your MML code clean and saving unnecessary typing. To give this sequence a little more of a dynamic feel, set up another volume envelope, and switch between the two. You’ll end up with something like this:
#TITLE My First NES Chip
#COMPOSER Nullsleep
#PROGRAMER 2003 Jeremiah Johnson
@v0 = { 10 9 8 7 6 5 4 3 2 }
@v1 = { 15 15 14 14 13 13 12 12 11 11 10 10 9 9 8 8 7 7 6 6 }
ABCDE t150
A l8 o4 @01 @v0
A [c d e f @v1 g4 @v0 a16 b16 >c c d e f @v1 g4 @v0 a16 b16 >c<<]2This volume envelope switching puts a slight emphasis on the quarter notes because of the higher initial volume setting of the new volume envelope and its slower decay rate. All of this can be applied identically to the second pulse channel (B) as well.
The operation of the triangle wave channel (C) is similar to the pulse wave channels with the exception of volume envelope and duty cycle parameters. The triangle channel has no volume control or duty cycle settings. Taking these things into consideration, the initial setup of the triangle channel is fairly straightforward:
C l4 o3 q6
These settings should be recognizable aside from the q parameter. The
q stands for “quantize,” and it can
take values from 1 to 8. Notes are divided into eight equal parts,
and this value determines how many divisions of the note to play
before cutting it. For example, the q6 setting we
used will cut the note after 6/8 of it has played.
Here’s an example of a bass-line sequence on the triangle channel:
C c e g8 g8 a16 b16 >c8 c e g8 g8 a16 b16 >c8<<
The noise channel (D) can be a fairly versatile instrument with a bit of work. A few possible applications include waves crashing on a beach, rocket engines roaring, dark fiery dungeon sounds, and supplemental percussion to enhance your drum samples. Like the pulse wave channels, volume envelopes are used by the noise channel and are an important part of getting good sounds out of it. Additionally, it has two modes of operation: normal and looped noise. The looped noise setting can generate interesting, somewhat metallic sounds. The pitch range of the noise channel is limited and loops every octave, making octave changing unnecessary. The c note seems to be the high pitch, with the pitch moving slightly downwards over e, f, g, a, and finally to the b note, which seems to be the lowest pitch.
Here are a couple of simple volume envelopes that can be used for some basic percussion on the noise channel:
@v2 = { 15 12 10 8 6 3 2 1 0 }
@v3 = { 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 }After setting up the volume envelopes, initialize the channel:
D l4 o1 @0 @v2
For channel D, this translates to:
Set the default note length to quarter notes.
Set the octave to the first octave.
Set the noise mode to normal (@1 turns on looped
noise).
Use volume envelope 2.
Here is a little sequence of simple noise drums:
D @v2 b @v3 e @v2 b @v3 e @v2 b @v3 e @v2 b @v3 e8 @v2 b8
The DPCM channel, or delta modulation channel (DMC), plays back samples on the NES. This can be useful for programming drums, sampled bass lines, or even vocal samples. Its operation is simple and fairly straightforward, with few parameters. Like the triangle wave channel, there’s no volume control; the DPCM channel is either on or off. Additionally, the NES uses its own one-bit sample format, which you have to convert your samples to before doing anything else.
The DMCconv program converts your samples from
.wav to .bin for use with
MCK. The documentation for DMCconv isn’t in English,
but its operation is simple enough. For example:
DMCconv kick.wav kick.dmc
This converts a kick.wav file into a kickdrum
sample usable by the NES with all the default settings.
Once all desired samples are converted, create a directory called
samples within the
workspace folder to store the samples and
initialize the channel in the MML, as follows:
@DPCM0 = { "samples\kick.dmc",15 }
@DPCM2 = { "samples\snare.dmc",15 }
E o0 l4This maps the first sample, kick.dmc, to
@DPCM0, which corresponds to the c note on octave
0. Notice that the second sample, snare.dmc,
maps to @DPCM2, which corresponds to the d note.
@DPCM1 is skipped over to avoid mapping samples to
sharps/flats and keep the MML more readable:
E c d c d c d c d8 c8
That covers the basics of programming music for the NES, but we have
really only just scratched the surface. For a comprehensive listing
of MML effects and commands, see the mckc-e.txt
file by Virt mentioned at the beginning of this hack. For
troubleshooting help and detailed instructions on how to play your
NSF songs on a real NES console, visit
http://www.8bitpeoples.com or
http://www.nullsleep.com. For
additional help and feedback, check the forums at http://www.2A03.org.
Thanks to Izumi, Manbow-J, Norix, Virt, Memblers, and everyone at 2A03.org and MCK 2ch.