Ultimate PPMCK MML Reference

Version: 1.1.3 - 2007/08/14


Table of Contents

Top

What is PPMCK?

H7's PPMCK is a third expansion of the famous MCK, a program that will convert your Music Markup Language (MML) text files into NES music instructions. You can play the generated file in various NSF players and plugins. With this new expansion, you get access to tons of tracks. The original NES only has a few sound-generating channels. Various third-party chips were included in some games to expand this. PPMCK, to my knowledge, takes advantage of all of them. This allows for rich, complex chiptunes not available in the original MCK.

I had trouble learning MML because the documentation out there was sparse and mostly in other languages. So this effort is to help everyone reference the different commands using MML under h7's PPMCK. After reading this I hope you gain a greater understanding of utilizing all of PPMCK's channels so you can make great chiptunes efficiently!

Available Tracks/Chips in PPMCK
Track Letter Description
A,B 2A03 Square Wave
C 2A03 Triangle Wave
D 2A03 Noise
E 2A03 DPCM Sample Playback
F FDS Wavetable Synth
G,H,I,J,K,L VRC7 FM Synth
M,N VRC6 Square Wave
O VRC6 Sawtooth Wave
P,Q,R,S,T,U,V,W N106 Wavetable Synth
X,Y,Z FME7 Multisound Synth
a,b MMC5 Square Wave

Download PPMCK software from http://takamatsu.cool.ne.jp/dutycycle/ppmck.html.


Headers


Compiler Instructions


#TITLE <string>

<string>
The title of your tune. It will probably display in most players.
31 characters maximum.
You cannot comment anything out on this line.


#COMPOSER <string>

<string>
The person who composed the actual music. This may also display in players.
Save your musical pseudonym for #PROGRAMER
31 characters maximum.
You cannot comment anything out on this line.


#PROGRAMER <string>

<string>
The person who typed the MML. Will not necessarily display in players.
The typo "PROGRAMER" is actually correct usage.
31 characters maximum.
You cannot comment anything out on this line.


#OCTAVE-REV <num>

<num> (0 or 1)
If set to 0, a ">" will raise the track one octave. "<" will lower one octave.
If set to 1, a "<" will raise the track one octave. ">" will lower one octave.
If this instruction is left out, a 0 is assumed.

#EX-DISKFM

Enables the Famicom Disk System channel F.


#EX-NAMCO106 <num>

Enables Namco106 channels P,Q,R,S,T,U,V, and W.

<num> (1 to 8)
This is the number of channels you want to enable simultaneously. For example, entering 3 will enable P, Q and R only. Entering 8 will enable all of its channels: P through W.


#EX-VRC6

Enables VRC6 channels M, N and O.


#EX-VRC7

Enables VRC7 channels G, H, I, J, K and L.


#EX-MMC5

Enables MMC5 channels a and b.


#EX-FME7

Enables FME7 channels X, Y, and Z.


#BANK-CHANGE <num>

<num> (1 to 14)
The number of the track you'd like to enable bank-switching on. Entering a 1 will bankswitch track A, 2 for B, 3 for C, and so on.

If you're working on a complex piece, you might see this error from NESASM:

Bank overflow, offset > $1FFF!

NESASM has to organize data into 8 kilobyte banks. If a track takes up more than 8K, a bank will overflow. If you get this error and see a track that has a lot of data, try bankswitching it so the data can continue into a another bank.


#BANK-CHANGE <num1> <num2>

<num1> (0 to 2)
The bank you are switching into.

<num2> (1 to 14)
The track you'd like to switch into the bank specified by <num1>.

This is simply a more detailed usage of #BANK-CHANGE <num>. If you're using the DPCM track E, don't use 0 as DPCM samples are stored in banks 1 and 2.


#EFFECT-INCLUDE

WARNING! OPTIONAL! This will replace the file "effect.h" you allegedly wrote for special instructions in assembly. Usually it is automatically generated for you per ppmck. It defines various macros so don't mess with it unless you know what you are doing.


#NO-BANKSWITCH

Disables bankswitching. When used, you will specify a specific bank using #SETBANK.


#SETBANK <letter>,<num>

<letter> (A to Z, a, or b)
The track you'd like to bankswitch.

<num>
The bank you'd like to use for the track specified with <letter>.

Just calling #SETBANK with no parameters will assume you want all tracks to be on bank 0.


#SETBANK <num1>,<num2>

<num1> (Usually 1 - 3)

The bank you'd like to move.

<num1> (Any number)

The destination bank. Note that if you pick a bank number higher than the previous filesize divided by 8192 plus one, it will pad unused banks with $FF.


Example

Original File Structure
Bank Number Address Range Data
0 $0000 - $1FFF Song Data 1
1 $2000 - $3FFF Song Data 2
2 $4000 - $5FFF Song Data 3


Bankswitched File Structure
Bank Number Address Range Data
0 $0000 - $1FFF Song Data 1
1 $2000 - $3FFF Padded with $FF
2 $4000 - $5FFF Song Data 3
3 $6000 - $7FFF Song Data 2


#DPCM-RESTSTOP

When used, it will cause the DPCM track E to stop playing instantaneously when using a rest note "r", instead of letting the sample play out until its end or until retriggered by another note.

Top

Macro Definitions

Unless otherwise noted, You can use up to 512 different values in the { } total. Any values placed after a "|" will be looped, but the first set of values will be gone through first. A case where this does not apply is a wavetable definition for the FDS (See @FM<num>).


@<num> = { ~ | ~ }

<num> (0 - 127)
A number you set for your reference when calling throughout your MML.

Valid parameter values for tracks A, B, a, b: (0 - 3)
Valid parameter values for tracks M and N: (0 - 7)

This will define a duty cycle envelope macro.

@@<num> to call.

For tracks A, B, a, and b, you must use integers 0 to 3 in the { }. They correspond to these duty cycles:

Tracks A, B, a and b Duty Cycle Envelope Parameters
<num> Duty Cycle
0 12.5%
1 25%
2 50%
3 75%

Tracks M and N can use 8 different duty cycles. Use integers 0 through 8.

Tracks M and N Duty Cycle Envelope Parameters
<num> Duty Cycle
0 6.25%
1 12.5%
2 18.75%
3 25%
4 31.25%
5 37.5%
6 43.75%
7 50%

Example

@0 = { 0 1 1 1 1 3 0 0 1 3 | 2 }
@1 = { 0 1 1 1 1 3 0 0 1 3 2 } ;this line does the same as line one.

@v<num> = { ~ | ~ }

<num> (0 - 127)
A number you set for your reference when calling throughout your MML.

Valid parameter values: (varies per track/chip)

Track Volume Restrictions
Track Letter Volume Range
A,B 0 - 15
C N/A
D 0 - 15
E N/A
F 0 - 63
G - L 0 - 15
M,N 0 - 15
O 0 - 63
P - W 0 - 15
X - Z 0 - 15
a,b 0 - 15

This will define a volume envelope macro.

@v<num> to call.

Example

;a nice, sweep fade-in
@v0 = { 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 9 10 11 | 12 }

@EP<num> = { ~ | ~ }

<num> (0 - 127)
A number you set for your reference when calling throughout your MML. T

Valid parameter values: (-127 - 126)

This will define a pitch envelope macro.

EP<num> to call.
ENOF to turn off.

The pitch macro is useable on most channels except DPCM playback track E. It's a different kind of envelope really, in that each value will begin a note slide and will continue sliding in the same fashion until either the next value is read in the envelope or it is turned back off in the track. Parameters in the negatives will slide down, positives slide up. The higher the parameter value the faster it will slide.

Example

@EP0 = { -15 } ;a slow glide downwards.

@EN<num> = { ~ | ~ }

<num> (0 - 127)
A number you set for your reference when calling throughout your MML.

This will define an arpeggio envelope macro.

EN<num> to call.
ENOF to turn off.

The arpeggio macro will rapidly progress through the series of notes. You can in fact use this on the Triangle track C as well. Sometimes this is used to simulate a chord. The parameters you put in will step the note up or down in semitones relative to the note called on the track.

Example

@EN0 = { 0 0 | 4 0 3 0 -7 0 } ; A major triad.

;Playing a C note, it will increase 4 semitones to E,
;then 3 semitones to G, then down 7 semitones back to C. Loops.

@MP<num> = { <param1> <param2> <param3> }

<num> (0 - 63)
A number you set for your reference when calling throughout your MML.

<param1> (0 - 255)
Delay until vibrato starts.

<param2> (1 - 255)
Vibrato speed.

<param3> (0 - 255)
Vibrato depth.

This will define a vibrato macro.

MP<num> to call.
MPOF to turn off.

You can modulate the pitch with a sort of sine wave with the vibrato macro. The vibrato macro is useable on most channels except DPCM track E. <param1> will dictate the time to wait after the note attack to start the vibrato. <param2> dictates how quickly to vibrate the pitch. Finally, <param3> dictates how far from the root note to swing.

Example

@MP0 = { 8 2 6 } ; A nice violin-like vibrato.

@DPCM<num> = { "<str>", <param1>, <param2>, <param3>, <param4> }

<num> (0 - 63)
The note [semitone] to map the sample to in the E track. Starts with note c0. Because it maps to semitones, it's recommended to use values that correspond to the "white keys" of a keyboard (e.g. DPCM0, DPCM2, DPCM4 for C0, D0 and E0 respectively, and so on). It's easier to type and read.

<str>
The file path to the DMC sample file relative to the location of ppmck_e.exe.

<param1> (0 - 15)
Changes the pitch of the sample. 15 is normal. 0 is slow/low. Steps are in semitones.

<param2> (0 - 4081)
OPTIONAL. The playback size of the sample. Specifying 0 or leaving this parameter out will make playback size equal filesize, which is ok. If the sample filesize is less than the size you specify here, the sample will be padded to it at playback.

<param3> (0 - 15)
OPTIONAL. To use, you must specify param1 and 2 also. This param3 is the Initial Delta Counter value, which is written to $4011 on note trigger. $ff is recommended. If you put in $00, you may get clicks. Using a non-zero value may change the volume of Triangle track C and and Noise Track D.

<param4> (0 - 2)
OPTIONAL. To use, you must specify param1, 2 and 3 also. DMC Playback mode.
0 = normal playback mode.
1 = looped playback mode.
2 = normal playback mode with IRQ (not recommended).

Defines the path to and paramaters for a delta pulse modulation channel (DPCM) sample to be played on track E. The DPCM channel will play back 1-bit samples. Useful for drums and other short sound effects. There is no volume control, so adjust your volumes accordingly before conversion to the DMC format.

Example

; A standard DPCM definition to note C0.
@DPCM0 = { "..\..\examples\dmc\snare.dmc", 15 }

; expanded definition, LOOPED playback.
@DPCM1 = { "..\..\examples\dmc\snare.dmc", 15, 0, 0, 1 }

@FM<num> = { ~ }

<num> (0 - 127)
A number you set for your reference when calling throughout your MML.

Valid parameter values: (0 - 63)

Must use 64 two-digit parameters.

This will define a wavetable for the FDS track F. A 0 corresponds to the lowest sample value, 63 the highest. You can create some cool wave patterns with 64 samples.

@@<num> to change to this instrument on track F. Be careful not to get confused. This is the same way to change a duty cycle on a square wave channel. You can use a utility like MUMEM to help you make a wave visually, then copy a list of sample values to the clipboard. Check out these example definitions.

Example FDS Waveforms
; 12.5% Duty Cycle Square Wave
@FM0 = {
63 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 }

; 25% Duty Cycle Square Wave
@FM1 = {
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 }

; 50% Duty Cycle Square Wave
@FM2 = {
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 }

; 50% Duty Cycle Square Wave
@FM3 = {
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 }

; Triangle Wave
@FM4 = {
00 02 04 06 08 10 12 14 16 18 20 22 24 26 28 30
32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62
63 61 59 57 55 53 51 49 47 45 43 41 39 37 35 33
31 29 27 25 23 21 19 17 15 13 11 09 07 05 03 01 }

; Bell-like sound
@FM5 = {
00 16 44 46 39 41 43 42 40 37 41 47 45 44 42 34
36 52 63 49 45 58 59 39 18 10 31 44 39 35 40 34
30 34 40 35 39 44 31 10 18 39 59 58 45 49 63 52
36 34 42 44 45 47 41 37 40 42 43 41 39 46 44 16 }

; Whistle-like sound
@FM5 = {
00 01 02 03 04 06 07 09 11 14 16 19 24 32 43 52
60 63 63 62 61 58 54 50 47 44 41 38 36 33 30 24
25 24 30 33 36 38 41 44 47 50 54 58 61 62 63 63
60 52 43 32 24 19 16 14 11 09 07 06 04 03 02 01 }

; Rhodes or Choir perhaps
@FM6 = {
00 00 01 03 06 09 13 20 25 33 37 45 49 53 56 58
60 61 61 62 61 61 59 58 56 53 51 50 46 45 43 43
43 43 43 45 46 50 51 53 56 58 59 61 61 62 61 61
60 58 56 53 49 45 37 33 25 20 13 09 06 03 01 00 }

; Steel Guitar
@FM7 = {
00 01 12 22 32 36 39 39 42 47 47 50 48 51 54 58
54 55 49 50 52 61 63 63 59 56 53 51 48 47 41 35
35 35 41 47 48 51 53 56 59 63 63 61 52 50 49 55
54 58 54 51 48 50 47 47 42 39 39 36 32 22 12 01 }

; Clav or Banjo
@FM8 = {
00 02 20 39 52 57 52 46 43 48 54 63 63 57 51 43
35 35 32 30 55 29 26 32 36 45 45 46 43 45 45 46
48 46 45 45 43 46 45 45 36 32 26 29 55 30 32 35
35 43 51 57 63 63 54 48 43 46 52 57 52 39 20 02 }

; Wurlitzer with a tad overdrive
@FM9 = {
00 04 21 38 44 50 54 57 51 50 48 54 54 58 60 63
63 63 62 51 56 56 52 54 55 58 58 54 48 42 25 08
04 08 25 42 48 54 58 58 55 54 52 56 56 51 62 63
63 63 60 58 54 54 48 50 51 57 54 50 44 38 21 04 }


@N<num> = { <param1>, ~ }

<num> (0 - 127)
A number you set for your reference when calling throughout your MML.

<param1> (0 - 31*)
The buffer number for the N106 chip. *The maximum buffer number varies with the number of parameters (samples) you are specifying. Short samples (few parameters specified) can use more buffers. See below.

Valid parameter values: (00 - 15) or you can use hex ($00 - $0F)

You can specify 4 - 32 samples, in increments of 4. You have to use certain buffers (<param1>) with certain numbers of specified samples. Check this chart:

N106 Definitions: Buffers and Samples
Number of samples specified Useable Buffers
4 00 - 32
8 00 - 15
12 00 - 09
16 00 - 07
20 00 - 05
24 00 - 04
28 00 - 03
32 00 - 03
Example N106 Instruments
; 12.5% Duty Cycle square wave
@N00 = {00, 15 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 }

; 25% Duty Cycle square wave
@N01 = {00, 15 15 15 15 0 0 0 0 0 0 0 0 0 0 0 0 }

; 50% Duty Cycle square wave
@N02 = {00, 15 15 15 15 15 15 15 15 0 0 0 0 0 0 0 0 }

; 75% Duty Cycle square wave
@N03 = {00, 15 15 15 15 15 15 15 15 15 15 15 15 0 0 0 0 }

; Triangle wave
@N03 = {00, 0 2 4 6 8 10 12 14 15 13 11 9 7 5 3 1 }

; Triangle wave twice as long
@N03 = {00, 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0}

; Sawtooth wave
@N03 = {00, 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 }

; Sawtooth wave twice as long
@N03 = {00, 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15}

; Thin, half-sawtooth wave
@N03 = {00, 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}

; Sliced Triangle wave
@N03 = {00, 0 1 2 3 4 5 6 7 8 9 10 10 10 10 10 10 10 10 10 10 10 10 9 8 7 6 5 4 3 2 1 0 }

; Bell
@N03 = {00, 0 10 9 10 9 10 11 10 8 15 10 13 4 7 8 9 7 9 8 7 4 14 10 15 8 10 11 10 9 11 9 10 }

; Choir
@N03 = {00, 0 0 1 2 5 8 11 13 14 15 15 14 14 13 12 11 10 10 11 12 13 14 15 15 14 13 11 8 5 2 1 0 }

; Flute
@N03 = {00, 0 0 0 1 2 3 5 10 14 15 14 13 11 9 8 7 5 7 8 9 11 13 14 15 14 10 5 3 2 1 0 0 }

; Scratchy, hollow square wave
@N03 = {00, 4 10 2 7 15 0 1 6 15 11 5 3 13 6 9 12 }

; Organ
@N03 = {00, 11 15 9 13 5 10 9 8 7 6 5 10 2 6 0 4 }

; Remember you can put these numbers in as hex ... $##

@OP0 = { ~ }

Valid parameter values: ($00 - $FF)

Must use 8 parameters.
e.g. { $00 $00 $00 $00 $00 $00 $00 $00 }

This will define the custom user instrument for the VRC7.

@@<num> to call up instrument for the track. Special procedures are necessary to call up the custom user-defined instrument.
@@1 - @@15 are built-in instruments listed below.
@@17 - @@31 are the same built-in instruments as @@1 - @@15.

Keep in mind that calling @@0 in the actual track is reserved: it's a shortcut for the last VRC7 instrument you called within the track. If you want to call on your user-defined VRC7 instrument, first use @@64. To call your second user-defined instrument (OP1) then use @@65 and so on. Calling a different instrument will override the last called. You can use the @@0 shortcut on other VRC7 tracks as long as you've selected one of the instruments as stated above.

The eight parameters you enter correspond to the VRC7's 8 registers for controlling its FM synthesis. You can read more about this in Kevin Horton's VRC7 Documentation (See references).

Descriptions of VRC7 Built-in Instruments
VRC7 Instrument Descriptions
Macro Description
@@1 Buzzy bell
@@2 Jazz electric guitar
@@3 Fretless bass
@@4 Tuba/trombone
@@5 Recorder/Clarinet
@@6 Strange chime
@@7 Trumpet
@@8 Violin
@@9 Soft bell
@@10 Music Box
@@11 Vibraphone
@@12 Violin 2
@@13 Organ/Wurly
@@14 Chimey Trumpet
@@15 Acoustic Guitar

Example

; G track using user-defined instrument
G @@64 c4 d4

; H track doesn't need full call since we did with the G track
H @@0 e4 f4

; The same goes for the I track.
I @@0 g8 a4

; Just calling a built-in instrument
J @@4 e4 c4

;@@16 is the same as @@0.

@MW<num> = { ~ }

<num> (0 - 7)
A number you set for your reference when calling throughout your MML.

Valid parameter values: (0 - 7)

You must use 32 parameters.

This is a 32 parameter wavetable-like envelope for modulating FDS track F's pitch. It's similar to the @EP macro, but the values don't correspond semitone-for-semitone. Check out this chart which shows how the values change the pitch per frame.

@MW Macro Parameters
Parameter value Adjustment in Semitones
0 0 st
1 +1 st
2 +2 st
3 +4 st
4 Reset to original pitch
5 -4 st
6 -2 st
7 -1 st

You will not "call" this effect with @MW or MW. This definition merely sets up the actual effect, @MH, which needs its own definition for delay, speed and depth. @MW is an envelope for modulating the FDS pitch and @MH is a macro for modulating the amount that @MW envelope modulates the pitch. It's like taking a xerox of a xerox. Crazy stuff happens.

Example

; a simple "blerp" in pitch (still needs @MH definition)
@MW0 = { 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 }

@MH<num> = { <param1>, <param2>, <param3>, <param4> }

<num> (0 - 15)
A number you set for your reference when calling throughout your MML. Needs to have a corresponding @MW<num> definition to put into action.

<param1> (0 - 255)
Delay until corresponding @MW<num> pitch envelope kicks in.

<param2> (0 - 4095)
Speed at which corresponding @MW<num> pitch envelop progresses.

<param3> (0 - 63)
Depth at which corresponding @MW<num> pitch envelop swings.
0 = 0% of any possible swing defined in the @MW envelop,
63 = 100% of any possible swing defined in the @MW envelop.

<param4> (0 - 7)
Chooses which @MW<num> envelop definition to use for the effect. To use @MW0, which you defined beforehand, you just put a 0 here.

This will define a "vibrato" modulator for the chosen @MW envelope you want to use (param4). Once you have both an @MW<num> and this @MH<num> defined, you're ready to apply it to the FDS F track.

MH<num> to call.
MHOF to turn off the effect. You can reenable with the same one or another if you like, of course.

Example

;This should make some wack boioioioioioinngg sound

;Activate the FDS extension
#EX-DISKFM

@v0 = { 21 14 8 }

;A nice buzzy envelop for the FDS
@FM0 = {
00 04 21 38 44 50 54 57 51 50 48 54 54 58 60 63
63 63 62 51 56 56 52 54 55 58 58 54 48 42 25 08
04 08 25 42 48 54 58 58 55 54 52 56 56 51 62 63
63 63 60 58 54 54 48 50 51 57 54 50 44 38 21 04 }

; a simple "blerp" in pitch
@MW0 = { 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 }

;Moderate delay, medium speed, maximum depth, uses @MW0
@MH0 = { 0, 500, 63, 0 }

;Apply to sample grammy-winning jingle
F t120 L
F @@0 @v0 q8 l4 o2 MH0
F c d e f g MHOF c d e f g
Top

Commands


Commenting Methods


Group Commenting: /* ~ */

This will treat everything in between these as commenting and will not be compilied with the assembler.


Line Commenting: ;

Anything after a ";" in a line will be commented out.

Example

A c d e f g a ; part1

;This next line is ignored by the compiler
;A a b b a
Top

Musical Notation


Entering Notes: <note><sharp/flat><len>

<note> (c, d, e, f, g, a or b)
The note of the scale you'd like to play.

<sharp/flat> (+ or -)
OPTIONAL. Insert a "+" here to raise the note one semitone. Insert a "-" to lower one. This is essentially "sharp" and "flat".

<len> (1 - 99999999999)
The length of the note you'd like to play. This number is the length of a measure divided by this number. For example, a c4 will play a quarter note C.

If no length is given, a the length you specified with the l<len> command is assumed.

Example

;Plays a C scale in quarter notes
c4 d4 e4 f4 g4 a4 b4 c4

;A piece of a symphony you may know
A d+16 d16 d8 d+16 d16 d8 d+16 d16 d8 b-4
A b-16 a16 g8 g16 f16 e-8 e-16 d16 c8 c4
A d16 c16 c8 d16 c16 c8 d16 c16 c8 a4
A a16 g16 f+8 f+16 e-16 d8 d16 c16 < b-8 b-4 >
A b-16 a16 a8 > c8 < f+8 a8 g8 d4
A b-16 a16 a8 > c8 < f+8 a8 g8 b-8 a16 g16 f16 e-16
A d2 c+2 d4 c+4 d8 r8 r8

Rests: r<len>

<len> (1 - 99999999999)
The length of the note you'd like to rest. This number is the length of a measure divided by this number. For example, a c4 will play a quarter note C.

If no length is given, a the length you specified with the l<len> command is assumed.

Example

;An example from earlier
A d2 c+2 d4 c+4 d8 r8 r8
Top

Tempo and Note Length


Tempo: t<num>

<num> (1 - 255)
The tempo of the track, not the entire song.

You'll use this after a track header to set its tempo. It won't set all tracks simulataneously unless you type every track letter you're using before this command. Strange? Check the example.

120 bpm is assumed if you don't specify a tempo.

Example

;set all five tracks to 120 bpm
ABCDE t120

;setting tracks to different tempi
ABC t85
DE t150

Tempo: @t<len>,<num>

<len> (1 - 99999999999)
Default note length per measure (see entering notes).

<num> (1 - 99999999999)
Number of frames per measure.

This is a more specific tempo assignment. It follows the following formula:
14400/<num>/<len>

It's essentially <len> notes every <num> frames.

Example

;set all five tracks to 150 bpm, 4 notes per 24 frames
;14400 / 4 / 24 = 150
ABCDE @t4,24


Default Note Length: l<len>

<len> (1 - 99999999999)
The default note length for the track you specify. Same rules as entering a note.

Leaving this out will assume you want quarter notes.

Example

;default sixteenth notes for tracks A and B
AB l16

;default eigth notes for track C
C l8

;and so on.

Quantize Note: q<num1>, <num2>

<num1> (1 - 8)
Divides lengths of entered notes by this number per the formula listed below. Won't affect attack times.

<num2> (1 - 8)
OPTIONAL. Adds to divisor per the formula below. If not specified, 0 assumed.

<num1> / (8 + <num2>) = Quantized Note Length

This will quantize the length of notes played, but not when they are played.

q4 is assumed if you don't specify any quantization for a track.

Example

;Play eigth notes in length, but quarter notes in placement
A l4 q1
A c c c c

Quantize Note: @q<num>

<num> (0 - 65535)
Number of frames to cut off of each note.


Note tie: &

Ties two of the same notes together.

Example

;two quarter notes combined = one half note
A c4&c4

;this sounds the same
A c2

;this is INCORRECT for the "&" tie
A c2&2

Note tie: ^

Ties two of the same notes together, but you only need to tie lengths, note completely written out notes. Recommended over &.

Example

;two quarter notes combined = one half note
A c4^4

;this sounds the same
A c2

;this is INCORRECT for the "^" tie
A c2^c2
Top

Octaves and More Notation


Octave: o<num>

<num> (varies per track/chip)
Sets default octave for a track.

Track Octave Restrictions
Track Letter Octaves Range
A - C 2 - 7
D 0 and high notes of -1 for low rumbles
E 0 - 3
F 0 - 6
G - L 0 - 7
M,N 0 - 8
O 1 - 8
P - W 0 - 8
X - Z 0 - 8
a,b 2 - 8

Example

;Set Noise Track D's only possible octave
D o0

Octave raise: >

This will raise the notes following one octave, unless you messed with #OCTAVE-REV. You can use more than one in a row.

Example

A b-16 a16 a8 > c8 < f+8 a8 g8 d4

Octave lower: <

This will lower the notes following one octave, unless you messed with #OCTAVE-REV. You can use more than one in a row.

Example

A b-16 a16 a8 > c8 < f+8 a8 g8 d4

Direct Notation: n<num>,n<len>

<num> (0 - 99)
A specific note number, unlike entering letters you're entering in semitones from c0.

<len> (0 - 99999999999)
The same note length you'd use with regular notation

A different way to enter notes instead of letters, per the following chart:

Abridged direct notation chart
Command Note
n0 C0
n1 C#0
n2 D0
n3 D#0
n4 E0
n5 F0
n6 F#0
n7 G0
n8 G#0
n9 A0
10 A#0
n11 B0
n12 C1
n13 C#1
n# and so on...

Remember each tracks octave restrictions.

Example

;Plays a C0 quarter note
A n0,4

Super Direct Notation: @n<num>,<len>

<num> (8 - 2034) ($0008 - $07f2)
Value to write to the frequency register directly.

<len> (0 - 99999999999)
The same note length you'd use with regular notation

This will let you choose a note by writing directly to the frequency register. Why you'd want to do this I don't know. You could get some pretty strange pitches by tinkering. But here is a chart showing you which notes correspond roughly. The higher the <num>, the lower the pitch. You can get higher frequencies. For example, to get C3, just divide C2's value $06AE by two. $06AE/2 = $0357.

Abridged super direct notation chart
<num> Note
$07F2 A1
$0780 A#1
$0714 B1
$06AE C2
$064E C#2
$05F4 D2
$059E D#2
$054E E2
$0501 F2
$04B9 F#2
$0476 G2
$0436 G#2
$#### ...and so on.

The FDS behaves differently. As <num> increases, pitch increases. To get C3, you'd just divide C2's value by two: $0983/2 = $04C1 = C3.

FDS abridged super direct notation chart
<num> Note
$0983 C6
$0A14 C#6
$0AAE D6
$0B50 D#6
$0bFD E6
$0CB3 F6
$0D74 F#6
$0E41 G6
$0F1A G#6
$1000 A6
$10F4 A#6
$11F6 B6
$#### ...and so on.

The N106 doesn't work with this method.


Transpose: K<num>

<num> (-99 - 99)
Transposes the notes that follow <num> semitones relative to the notes entered (remember your default octave).

Top

Loops and Other Commands


Set static volume: v<num>

<num> (Varies per track/chip)
Value that sets the track volume, overriding any volume envelopes you have. You can call back any envelope you want, of course. Remember each track's volume restrictions:

Track Volume Restrictions
Track Letter Volume Range
A,B 0 - 15
C N/A
D 0 - 15
E N/A
F 0 - 63
G - L 0 - 15
M,N 0 - 15
O 0 - 63
P - W 0 - 15
X - Z 0 - 15
a,b 0 - 15

Example

;Set Track O to its max volume (this is really loud)
O v63 c d e f g

Increase Volume: v+<num>

<num> (Varies per track/chip)
The number of levels you want to increase the volume by. Keep in mind tracks' volume minimum and maximum (see @v or v commands).

You must specify a static volume with v<num> before using this.

Example

;Increase Track O's volume by 10
O v10 c d e v+10 f g a

Decrease Volume: v-<num>

<num> (Varies per track/chip)
The number of levels you want to decrease the volume by. Keep in mind tracks' volume minimum and maximum (see @v or v commands).

You must specify a static volume with v<num> before using this.

Example

;Decrease Track O's volume by 10
O v15 c d e v-10 f g a

FDS Hardware Envelope: EH<fade>,<num>

<fade> (0 or 1)
0 fades FDS Track F's volume downward.
1 fades it upward.

<fade> (0 - 63)
The speed at which the FDS Hardware envelope changes.

Doesn't appear to be retriggered with each note. It'll just keep looping through, so call and turn off carefully.

EH<fade>,<num> calls,
EHOF turns off.


FDS @v Retrigger: @vr<num>

<num> (0 or 1)
The envelope to retrigger at the time quantization happens.

This will launch @v<num> volume envelope when the note is cut off by the quantization you specify. Instead of cutting the note off like quantization should, it will instead launch @v<num> at that moment. By choosing a different volume envelope here, you can in effect have two volume envelopes per note.

You can choose a new "first" envelope with another @v<num> command. Calling a static volume using v<num> will deactivate the effect until you call it again.

Example

;This will start out with @v0, then go into @v1 about halfway through the note
@v0 = { 7 5 5 4 }
@v1 = { 14 10 0 | 10 0 }

F @@0 @v1 @vr2 q4 l4 o2
F c d e f g

Time Shift: k<len>

<len> (0 - 99999999999)
How much you want to shift the following notes forward in time, in the same terms as notes. Leaving this out will assume you want to use your l<len> value.

This is a way to create echoes in your songs using two tracks, where one is using a lower volume. Check out this example for a nice bounce echo effect commonly used in many chiptunes.

You might want to use a rest command, because this command seems to be permanent. Consider using rests and thinking how much a track is ahead if you want to adjust the echo back to unison.

Using this effect andrests can shift your echo effect.

Example

;Classic Chippy Tap Echo
A o3 @1 v10 l8 q4
B o3 @1 v3 l8 q4

AB t100

A c d e f g
B k11 c d e f g

Loop Position: L

This will set the loop position in the song. In some cases, tracks may not syncronize at certain tempos because of minute differences in track length. Bracket loops appear not to have this problem.


Repeat Loop: [ ~ ]<num>

<num>
Will loop the notation inside the [ ] <num> times. A space saver. You can nest loops within loops.


Multi Repeat Loop: |: ~ \ ~ \ ~ ... :|<num>

<num>
Will loop the notation before the first\ <num> times, then loops the next section <num> times and so on. A real space saver. You can nest loops within loops.

Example

;Will loop "c d e f g" 4 times, then "a b a b a" 4 times.
A |: c d e f g \ a b a b a :|4

;Will loop 4 times, just like [ ~ ]
A |: c d e f g :|

Self Delay: SD<num>

<num> (1 - ?)
The number of delays.

This is some self-delay effect on a track. I've never gotten it to sound like I want, but it is there. To those trying to achieve this effect it is a space saver I suppose.

SD<num> calls.
SDOF turns off.

Example

;This
SD1 @v0 @vr1 l4 q4 cdefg

;Is the same as this:
l8 q8 @v0c@v1w@v0d@v1c@v0e@v1d@v0f@v1e@v0g@v1f

;You can see the space-saving qualities of this command.
Top

Quick Track Table

Quick Track Table.
Letter Description Commands (May be incomplete)
A,B 2A03 Square l#, o#, q#, @##, @v#, v# @@#, @#, EN#, ENOF, EP#, EPOF, MP#, MPOF, k, K
C 2A03 Triangle l#, o#, q#, EP#, EPOF, MP#, MPOF, k, K
D 2A03 Noise l#, o#, @#, @V#, v#, EN#, ENOF, EP#, EPOF, MP#, MPOF, k, K
E 2A03 DPCM l#, o#, k, K
F FDS Wavetable l#, o#, q#, @v#, v#, EN#, ENOF, EP#, EPOF, MP#, MPOF @@#, @FM#, @MW, @MH, MH#, MHOF, k, K
G,H,I,J,K,L VRC7 FM Synth l#, o#, q#, @v#, v#, @@#, EN#, ENOF, EP#, EPOF, MP#, MPOF, @OP#, k, K
M,N VRC6 Square l#, o#, q#, @v#, v#, @@#, @#, EN#, ENOF, EP#, EPOF, MP#, MPOF, k, K
O VRC6 Sawtooth l#, o#, q#, @v#, v#, EN#, ENOF, EP#, EPOF, MP#, MPOF, k, K
P,Q,R,S,T,U,V,W N106 Wavetable l#, o#, q#, @v#, v#, EN#, ENOF, k, K
X,Y,Z FME7 Multisound l#, o#, q#, @v#, v#, EN#, ENOF, EP#, EPOF, MP#, MPOF, k, K
a,b MMC5 Square l#, o#, q#, @##, @v#, v# @@#, @#, EN#, ENOF, EP#, EPOF, MP#, MPOF, k, K
Top

Multisong NSF Tutorial

With PPMCK release 9, multisong nsf creation is built-in! Which means this tutorial was obsolete! Ho ho! All it takes is a change in command-line arguments. Needless to say, this tutorial will be short.

Basically, when calling ppmckc, just use the -u argument for multisong nsf creation, like so.

ppmckc -i -u song1.mml song2.mml song3.mml

This is all you need to change. If you want 5 songs, go right on ahead and put 5 in. If it blows up, it's not my fault! Then, as usual, call nesasm to create the rom. The headers ppmckc produces will contain the necessary data. Just make sure you keep your paths straight.

export NES_INCLUDE="path to nes_include folder"
nesasm -s -raw ppmck.asm
mv ppmck.nes *yoursong.nsf*

That's it! Whew!


TODO


Version History

Special Thanks


References

  1. MML Reference - MCK Wiki
  2. MCK/MML Beginners Guide - nullsleep
  3. DPCM (DMC) Howto - nullsleep
  4. VRCVI Chip Info - Kevin Horton
  5. VRCVII Chip Info - Kevin Horton
  6. Namco 106 Mapper Information - goroh
  7. 2A03 Sound Channel Hardware Documentation - Brad Taylor
  8. 2A03 Technical Reference - Brad Taylor
  9. About NSF - hirooka
  10. NES Music Format Spec - Kevin Horton
  11. 20 Levels of NSF Ripping - gil galad
Top | Home