Some notes I made while adding
support for Journey to Silius to my generic MML inserter. They will be sent to the database or the wiki later.
Command List- 00 xx, 01 xx, ... 7F xx: Plays a note for xx ticks; 00 is C2 (MIDI note 36). The high nybble does not seem to have any purpose on the noise track. xx must be omitted if fixed note duration is enabled (see F6).
- E5: Finishes a group of slur notes. E0 to E4 are all unused aliases.
- E6: Disables the current pitch envelope.
- E7 xx yyyy: Sets a pitch envelope; The envelope pointed by yyyy starts xx ticks after each new note.
E8 xx yyyy: (unused)- E9: Begins a group of slur notes; the next note plays as usual, and then all new notes do not retrigger the instrument envelopes until the next E5 command.
- EA xxxx: Sets a volume/duty envelope; the envelope pointed by xxxx starts with all new notes.
- EB xx: Writes xx to the 2A03 pulse sweep register ($4001 / $4005) for all new notes.
- EC xx: On the pulse or noise channel, disables the volume envelope and writes xx to the volume/duty register ($4000 / $4004 / $400C) for all new notes. On the triangle channel, writes xx to the linear counter register ($4008) for all new notes.
- ED xx yy: Waits for yy ticks, decreasing the track volume by 1 every xx ticks.
- EE xx: Forces all new notes to trigger the release envelope xx ticks before it finishes. Unused.
- EF: Disables the release part of the volume/duty envelope.
- F0: Halts the current track.
- F1 xx: Note rest; plays nothing for xx ticks. xx must be omitted if fixed note duration is enabled (see F6).
- F2 xx: Extends the duration of the previous note by xx ticks. xx must be omitted if fixed note duration is enabled (see F6).
- F5 xx: Gate time; behaves like EE, but the release time is at most half the note duration. F3 and F4 are unused aliases.
- F6 xx: Enables fixed note duration; all future note events (00-7F, F1, F2) use xx as the number of ticks.
- F7: Disables fixed note duration.
- F8 xx: Detune; adds (xx - 80) to the channel's period register. Values less than 80 will therefore raise the pitch.
- F9 xx: Transpose; shifts all new notes by xx semitones.
- FA: Leaves the current pattern, if there is one.
- FB xxxx: Invokes the pattern pointed by xxxx.
- FC xxxx: Unconditionally moves the track pointer to xxxx.
- FD xx yyyy: Loop; moves the track pointer to yyyy for xx times.
- FE xx yyyy: Loop; same as FD, but uses different variables, permitting nested loops.
Volume/Duty Envelope Format- Byte pointer to the release point, relative to the beginning of the envelope, or 00 if there is none;
- One byte for each tick, where the entire byte is written verbatim to the volume/duty register;
- The byte 00;
- Byte pointer to the sustain envelope's loop point, relative to the beginning of the envelope (must be positive). If this is negative, decreases the instrument volume by 1 every (xx - 80) ticks, or holds the volume if it is exactly 80;
- If there is a release envelope, the 3 items above are repeated.
Pitch Envelope Format- One byte for each tick, where the most significant bit is the direction, raising the pitch if clear, and the remaining 7 bits are the offset amount for the period register;
- The byte 00; (80 must be used for parts of the envelope with zero pitch offset)
- Byte pointer to the envelope loop point, relative to the beginning of the envelope.
Song Format- Track index, may be 00 to 08, higher values have higher priority (used by sound effects);
- Channel index, may be 00 (Pulse 1), 01 (Pulse 2), 02 (Triangle), or 03 (Noise), omitted for the DPCM track;
- Pointer to the beginning of the track data;
- After all track definitions are placed, the byte FF terminates the song definition.
Lookup Tables- $862F - $86F0: Period lookup table, starting with 97 high bytes followed by the corresponding low bytes. All period values are subtracted by 0x80.
- $BEFB - $BF50: Song / sound effect pointer table, 43 entries.
- $BF51 - $BFC0: DPCM assignment table, 28 entries, where each entry consists of 4 bytes; DPCM pitch, initial delta counter value, sample index (real address is C000 + xx * 40), sample length (real length is xx * 10 + 1).
Caveats- Envelopes may appear anywhere within the music data, so every time a track needs to use a new instrument envelope it must repeat the envelope pointer.
- There are no instrument definitions for the triangle / noise channel's percussion. They are controlled entirely by separate notes and pattern invocations.
- Command FA does nothing if there is not a current pattern in use, which means patterns may be defined within the main track data itself, or even defined on another track (Stage 1 does this for almost the entire Pulse 1 track's echo data). Example taken from the title's triangle track:
$AD3C: 1B 01 1A 01 19 01 F1 07 FA [ (kick8)[o2 d+%1 d%1 c+%1 r%7]
$AD45: FB 3C AD (kick8)
$AD48: F6 01 21 20 1F 1E 1D 1C 1B 1A 19 F1 F7 FA (snare8)[L1 o2 ag+gf+fed+dc+ r L0]
$AD56: FB 3C AD (kick8)
$AD59: FB 3C AD (kick8)
$AD5C: FB 3C AD (kick8)
$AD5F: FB 48 AD (snare8)
$AD62: FB 3C AD (kick8)
$AD65: FE 02 3C AD ]3
$AD69: F6 01 25 24 23 22 21 20 1F 1E 1D F1 F7 FA (tomhi8)[L1 o3 c+c<ba+ag+gf+f r L0]
$AD77: FB 69 AD (tomhi8)
$AD7A: F6 01 1D 1C 1B 1A 19 18 17 16 15 F1 F7 FA (tommid8)[L1 o2 fed+dc+c<ba+a r L0]
$AD88: FB 2E AD (tomlo8) ; defined earlier
$AD8B: FB 12 AD (tomhi16) ; defined earlier
$AD8E: FB 12 AD (tomhi16) ; defined earlier
$AD91: F1 05 r16
$AD93: FB 12 AD (tomhi16) ; defined earlier
$AD96: FB 20 AD (tommid16) ; defined earlier
$AD99: FB 20 AD (tommid16) ; defined earlier
$AD9C: FB 2E AD (tomlo8) ; defined earlier
- Command FC may point to the middle of a loop. This may be used to implement loop breaks, however it does not seem to be used on local loops, only the global loop (the last command of the title's Pulse 1 track does this, skipping over a rest on looping).