Skip to content
On This Day:

Nintendo Entertainment System · Audio Hacking

Final Fantasy III (NES) Sound Format

By Justin Olbrantz (Quantam)

Final Fantasy III · All hacks & resources →

About this project

This specification describes the music and sound effect format used by Final Fantasy III (NES) in sufficient detail to create new music or sound effects and insert them into the games, or to extract and convert music/sound effects from the games to other formats.

Original game requirements

See the release instructions.

Creator credits

Justin Olbrantz (Quantam)
Listed creator

RELEASE 1.0

Readme & instructions

[880]Final Fantasy III (NES) Sound Format.txt

FINAL FANTASY III (NES) SOUND ENGINE FORMAT v1.0 By Justin Olbrantz (Quantam) The permanent home of this specification and others, with the latest updates, is https://github.com/TheRealQuantam/RetroDocs. The Final Fantasy III sound engine, like that of Final Fantasy II, was developed by Hiroshi Nakamura. However, both engines, as well as that of the original Final Fantasy developed by Toshiaki Imai, all show a clear evolution of features and music format over time; Final Fantasy II builds on Final Fantasy, and III then builds on II.

Read moreRead less
FINAL FANTASY III (NES) SOUND ENGINE FORMAT
v1.0

By Justin Olbrantz (Quantam)

The permanent home of this specification and others, with the latest updates, is https://github.com/TheRealQuantam/RetroDocs.

The Final Fantasy III sound engine, like that of Final Fantasy II, was developed by Hiroshi Nakamura. However, both engines, as well as that of the original Final Fantasy developed by Toshiaki Imai, all show a clear evolution of features and music format over time; Final Fantasy II builds on Final Fantasy, and III then builds on II.

The FF3 engine is not entirely abstracted from the NES' Audio Processing Unit hardware. In particular, while it is unclear whether this was intended for music or only sound effects, FF3's engine allows direct access to the pitch slide register which provides pitch linear pitch slide for square wave channels but can potentially interfere with pitch envelopes. The details of this will be discussed under the corresponding command. For further information see a proper APU programming reference such as https://www.nesdev.org/wiki/APU_registers

Basic Features:
- Compact single-byte notes and rests
+ Staff notation style divisive rhythm system
	- 6-octave chromatic scale from C2 (65.4 Hz) to B7 (7457 Hz) for square wave (triangle is 1 octave lower)
	- 16 note lengths from whole notes through 64th notes with dots and triplets for some lengths
	- Length tie to create arbitrary lengths
	- High-precision tempo from 1 to 255 BPM
+ Complex timbre support
	Square channels: Duty cycle, channel volume, pitch linear pitch slide, ASR volume envelope, and linear period pitch envelope
	Triangle channel: Linear period pitch envelope
	Noise channel: Channel volume, ASR volume envelope, and linear period pitch envelope
- 5 channels - square 1 and 2, triangle, noise, and a kick drum-like pop - each with separate event sequences
- Note auto-release
- Dual-level nested loops, with loop break points possible for "play twice" loops
- Nearly identical formats for music and sound effects

Major Differences with Final Fantasy:
- 2 additional octaves
- Proper tempo system
- Proper implementation of rests and tied length
- Note auto-release
- Dual-level nested loops with break points
- Support for noise and kick drum channels
+ Drastically improved expression
	- Selection of square wave duty cycles
	- Channel volume selection for square and noise channels
	- ASR volume envelopes and linear period pitch envelopes
	- Looping envelopes
- Nearly identical formats for music and sound effects
	
Major Differences with Final Fantasy II:
- No explicit access to ctrl 1 registers ($4000, $4004, etc.)
- Access to pitch linear pitch slide registers ($4001, $4005, etc.) for square wave channels
- Volume envelopes are partially required
- ASR volume envelopes on square wave and noise channels
- Note auto-release
- Dual-level nested loops
- Nearly identical formats for music and sound effects

Some general notes in interpreting this specification:
- All word (16-bit) values in the format are little-endian, with the least-significant byte preceding the most-significant.
- All values are unsigned unless noted otherwise.
- All numbers preceded by $ are hex, and in general unless they represent byte strings or addresses most numbers without $ are in decimal.
- Byte values are generally shown as hex "ab" where "a" is the high nibble and "b" is the low nibble (standard mathematical digit ordering). However, when it is necessary to show bit fields, bytes are shown in binary as "abcd efgh" (mathematical order); in bit fields "-" means that the value of the bit does not matter in the given context.
- Many command lists (e.g. channel data commands) are encoded ambiguously, where 1 value could be interpreted as multiple different commands (e.g. 00 could match 0n). These lists are ordered such that the first matching command is the correct interpretation.
- A wave's "period" is inversely proportionate to its frequency; in the NES the square wave channel's period = 1789773/16 / frequency (triangle channel is 1 octave lower for the same period), and the value actually written to the hardware is 1 less than this. Here "pitch" is used as proportionate to key number, is what humans perceive, and frequency doubles (period halves) with each pitch increase of 1 octave. As such "linear period", "linear frequency", and "linear pitch" are all very different things, and linear pitch is what sounds linear to the ear.

MUSIC FORMAT

FF3's sound system stores all its code, global data, and sound effects in bank $36 in the $8000-$9fff region. Music data as well as track tables are distributed across multiple banks that are mapped to $a000-$bfff as necessary.

To convert addresses to file offsets:
	For addresses $8000-$9fff: file offset = addr + $64010
	For addresses $a000-$bfff: file offset = bank * $2000 + addr - $9ff0
	
Music Header Structure:
+0 word[5]: Channel data addresses in order of square 1, square 2, triangle, noise, kick drum, or $ffff if none.

Channel Data Format

Notes and rests are encoded as single-byte events of the format kL. For notes, k is 0-$b, corresponding to C-B within the current octave, and L is the length the note should play before continuing.

Key number: 0   1   2   3   4   5   6   7   8   9  $a  $b
Key:        C  C#   D  D#   E   F  F#   G  G#   A  A#   B

For the noise channel the keys are mapped to noise values according to the following table. For noise values, like period values but unlike the keys that map to them, lower values mean higher pitch.

Key number: 0   1   2   3   4   5   6   7   8   9  $a  $b
Octave 0:   0   1   2   3   4   5   6   7   8   9  $a  $b
Octave 1:  $c  $e  $f  $f  $f  $f  $f  $f  $f  $f  $f  $f
Octave 2: $80 $81 $82 $83 $84 $85 $86 $87 $88 $89 $8a $8b
Octave 3: $8c $8e $8f $8f $8f $8f $8f $8f $8f $8f $8f $8f

Octaves 2 and 3 are periodic noise, a buzzing/ringing sound that approximates certain chromatic tones (although consistently about 50 cents sharp) as shown in the following table:

Key number:  0    1    2    3    4    5    6    7    8    9   $a   $b
Octave 2:   D8   D7   D6   D5   D4   G3   D3  A#2  F#2   D2   G1   D1
Octave 3:   G0  D-1  D-2  D-2  D-2  D-2  D-2  D-2  D-2  D-2  D-2  D-2

Octaves 4 and 5 are not useful in the general case, but are used in combination with volume and volume envelopes by the presets for closed hihat and snare drum:
Key number: 0   1   2   3   4   5   6   7   8   9  $a  $b
Octave 4:   4   4   4   4   4   4   4   4   4   4   4   4 (closed hihat)
Octave 5:  $b  $b  $b  $b  $b  $b  $b  $b  $b  $b  $b  $b (snare drum)

Key is irrelevant for the kick drum channel.

Note events may be immediately followed (i.e. no other events may come between them) by 1 or more tied lengths of the form dL that serve to lengthen the initial note by L time. 

Finally, rests have the form cL. Unlike in FF1, rests in FF3 behave as expected and properly silence the preceding note.

In all cases L is a length code from the following table:

                      whole  half  4th  8th  16th  32nd  64th
Normal note lengths:      0     2    5    8    $b    $d
Dotted note lengths:            1    3    6     9
Triplet note lengths:           4    7   $a    $c    $e    $f

However, the specified length is the length until the next event is played, and is not necessarily the length the note will actually play before being silenced, due to auto-release. When starting notes FF3 sets the sustain length of notes to a hard-coded 3/4 the total length of the note including tied length. What exactly this means depends on the volume envelope used. If a volume envelope is used the sustain length is the maximum time the note may be in the sustain phase of its envelope before being automatically transitioned to release phase. However, this only means anything if that envelope has a sustain phase and its release phase fades out. Some (e.g. percussion) envelopes effectively do not have a sustain phase and will fade out even without auto-release; other (e.g. tremolo) envelopes do not have release envelopes that fade out, and the note will continue to play until a new note is started or a rest is encountered. Rests immediately silence the preceding note even if its envelope has not yet brought the volume to 0.

Once again auto-release has no effect on the kick drum channel.

In addition to notes, rests, and tied lengths, the following commands are defined:
e0 tt: Set global tempo to t BPM. Default of 150.
e1-ee: Set channel volume to 2 ($e1)-15 ($ee) (default of 15). Note that channel volume is ONLY applied if there is also a volume envelope.
ef-f4: Set octave 0 ($ef)-5($f4). Octave 0 begins at C2, resulting in a total key span of C2-B7 for square wave channels; triangle is 1 octave lower.
f5-f7 vv pp: Set timbre and envelopes. By default no envelopes are used:
	Square: Set duty cycle to 12.5% ($f5), 25% ($f6), or 50% ($f7), volume envelope number to v ($ff if none), and pitch envelope number to p ($ff if none). Defaults to 12.5% duty cycle.
	Triangle: Set pitch envelope number to p ($ff if none).
	Noise: Set volume envelope number to v ($ff if none) and pitch envelope number to p ($ff if none).
	Kick drum: No effect.
f8 eppp nsss: Set pitch slide register for square wave channels ($4001, $4005, etc.). Has no effect on other channels. Defaults to pitch slide disabled.
	e: Enable pitch slide
	p: Pitch slide period. Pitch is modified every p+1 half-frames.
	n: Negative flag. If set, the square wave period is reduced (rising pitch), else the period is increased (falling pitch).
	s: Pitch slide amount. The amount of change to the period is relative to the current period, resulting in linear pitch slides according to the following table (note that it will be slightly detuned because of how the period registers works):
		0: 100% change: if n silences channel after 1 period, else decreases pitch by 1 octave/period
		1: 50% change: if n +1 octave/period, else -7.02 semitones/period
		2: 25% change: if n +4.98 semitones/period, else -3.86 semitones/period
		3: 12.5% change: if n +2.31 semitones/period, else -2.04 semitones/period
		4: 6.25% change: if n +1.12 semitones/period, else -1.05 semitones/period
		5: 3.12% change: if n +54.96 cents/period, else -53.27 cents/period
		6: 1.56% change: if n +27.26 cents/period, else -26.84 cents/period
		7: 0.78% change: if n +13.58 cents/period, else -13.47 cents/period
		
	Note: The absolute range of the square wave channels is 54.6 Hz (~A1) to 12.4 KHz (~G9), and any channel that is taken outside that range by pitch slide will be silenced. The pitch slide unit ALWAYS computes the next period value and checks it for valid range, but the period value is only updated if pitch slide is enabled; n should be set whenever e is not set to avoid this effect.
	
f9: Closed hihat preset for noise channel. Set octave to 4, volume envelope number to 0, and channel volume to 8
fa: Snare drum preset for noise channel. Set octave to 5, volume envelope number to 1, and channel volume to 15
fb nn: Begin loop and set to play n > 0 times. May have 2 levels of loops.
fc xx yy: End loop. Decrement inner loop counter and if not 0 go to y:x, else end inner loop and continue.
fd xx yy: Odd loop break. If loop counter is odd (1, 3, etc.) end inner loop and go to y:x, else continue.
fe xx yy: Go to y:x
ff: End of channel. Stop and silence the channel but other channels will continue. When all channels have ended playback is stopped.

Examples

Square Wave Channel:
E0 91: Set global tempo to $91 (145) BPM
F6 09 FF: Set duty cycle to 25% and set envelopes
	v = 9: Volume envelope number 9
	p = $ff: No pitch envelope
EB: Set channel volume to $c (12)
EF: Set octave 0 (starting at C2)
CC: Rest
	L = $c: Triplet 16th note
58 D0: Play note with tied length
	k = 5: Key F
	L = 8, 0: 8th note + whole note
F8 8D: Set pitch slide
	e = 1: Enable pitch slide
	p = 0: Period length of 0+1=1 half-frames
	n = 1: Falling period (rising pitch)
	s = 5: 3.12% change: +54.96 cents/period
FB 02: Begin loop
	n = 2: Play loop sequence 2 times (set loop counter to 2)
FD CB A9: Odd loop break
	y:x = $a9cb: If loop counter is odd (second playthrough of the loop sequence) end loop and go to $a9cb
FC B1 A9: End loop
	y:x = $a9b1: Decrement loop counter; if not 0 go to $a9b1, else end loop and continue
	
Noise Channel:
F9: Set closed hihat preset
0B: Play note
	k = 0: Noise value 4 (all keys are the same with this preset)
	L = $b: 16th note
FA: Set snare drum preset
08: Play note
	k = 0: Noise value $b (with this preset)
	L = 8: 8th note
FE 63 AA: Goto
	y:x = $aa63: Address $aa63

Kick Drum Channel:
02: Play note
	k = 0: Irrelevant
	L = 2: Half note
	
ENVELOPES

The FF3 engine has a relatively complex envelope system capable of ASR and AD envelopes (or any subset thereof) and tremolo for volume envelopes, as well as pitch envelopes and vibrato.

Pitch Envelopes

Pitch envelopes consist of a single phase and are formed by a table of period offset:length pairs that add an offset to the current period and wait for the specified number of frames before moving onto the next pair, optionally concluding with a loop back to a previous pair.  

It is important to note that pitch envelopes directly modify the period for the channel, and these modifications accumulate; i.e. envelope values are relative. But the FF3 engine does not allow pitch envelopes to cause the period to cross a $100-value boundary. While this is done to prevent audible glitches caused by writes to the period high register, the direct and cumulative modification of the period combine to create the unwanted side effect that the base pitch can be shifted due to clamping at the high/low points of the envelope. E.g. if a vibrato envelope has the repeating sequence +2, -2, -2, +2 (+/- 2) but the current period is $1ff and +2 would cause a boundary crossing, the result will be $1ff + 2 = $1ff, and then $1ff - 4 + 2 = $1fd, NOT $1ff; the center frequency has shifted.

Pitch Envelope Format:
00: End of envelope. No further modification will be made to pitch.
0LLL LLLL pp: Add offset p (signed, two's complement) to current period and wait L frames
1ooo oooo: Loop. Add 1:o (< 0) to current envelope position in bytes.

Pitch envelope 1 serves as an example:
 
32 00 06 FF 06 01 FC
32 00: Offset:length pair
	L = $32: $32 frames
	p = 0: +0 period units
06 FF: Offset:length pair
	L = 6: 6 frames
	p = $ff: -1 period units
06 01: Offset:length pair
	L = 6: 6 frames
	p = 1: +1 period units
FC: Loop. $fc = -4 bytes, so go back 2 offset:length pairs
 
This is a delayed vibrato envelope that waits 50 frames before beginning a vibrato of depth 1 period value and period of 12 frames (5 Hz). This small of a depth will produce a very slight but perceivable vibrato, e.g. for A440 +/- about 3.3 cents.

04 FF FE
04 FF: Offset:length pair
	L = 4: 4 frames
	p = $ff: -1 period units
FE: Loop. $fe = -2 bytes, so go back 1 offset:length pair
 
Envelope 8 demonstrates a couple things. It is a pitch slide envelope, decreasing the period by 1 every 4 frames (rising pitch). This may well not work as intended, however, because of the inability for pitch slide to cause period values to cross $100 boundaries. As such the pitch slide will abruptly end at the next (lowest) $100 boundary.

Pitch Envelope Table:
36:9eab word[$10]: Addresses of pitch envelopes

Pitch Envelopes:

Pairs show period offset on the left side and length on the right. Loops are indicated with structures like -2->4 which show the relative byte offset on the left side and the new absolute offset on the right (2x the number of offset:length pairs). Terminal 00 bytes are not shown for non-looping envelopes.

 0 (0) @9ecb (6dedb): -1:4  +1:4  -4->0
 1 (1) @9ed0 (6dee0): +0:50 -1:6  +1:6  -4->2
 2 (2) @9ed7 (6dee7): -1:50 +1:6  -1:6  -4->2
 3 (3) @9ede (6deee): -1:6  +1:6  -4->0
 4 (4) @9ee3 (6def3): -1:1
 5 (5) @9ee6 (6def6): +0:16 -1:6  +1:6  -4->2
 6 (6) @9eed (6defd): +0:6  -1:6  +1:6  -4->2
 7 (7) @9ef4 (6df04): +0:24 -1:6  +1:6  -4->2
 8 (8) @9efb (6df0b): -1:4  -2->0
 9 (9) @9efe (6df0e): -1:24 -1:6  +1:6  -4->2
10 (a) @9f05 (6df15): -1:1  -2:1  -2:1  -2:1  +2:1  +2:1  +2:1  +2:1  +2:1  +2:1  +2:1  -2:1  -2:1  -2:1  -2:1  -28->2
11 (b) @9f24 (6df34): +0:1  -1:1  +1:1  +1:1  -1:1  -8->2
12 (c) @9f2f (6df3f): +7:1  -2:1  -2:1  -2:1  -2:1  -2:1  -2:1  -2:1  -2:1  +1:1  +1:1  +1:1  -1:1  -1:1  -1:1  +1:1  +1:1  +1:1  -1:1  -1:1  -1:1  +1:1  +1:1  +1:1  -1:1  -1:1  -1:1  +2:1  +2:1  +2:1  +2:1  +2:1  +2:1  +2:1  -2:1  -2:1  -2:1
13 (d) @9f7a (6df8a): +1:1  +2:1  +2:1  +2:1  +2:2  -2:1  -2:1  -2:1  -1:1  -18->0
14 (e) @9f8d (6df9d): +7:1  -3:1  -3:1  -3:1  -3:1  -2:2  +1:2  +1:2  -1:2  -1:2  -8->12
15 (f) @9fa2 (6dfb2): -7:1  +7:1  +7:2  -2:1  -3:1  -3:1  -3:1  -3:1  +2:1  +2:1  +2:1  -2:1  -2:1  -2:1  +2:1  +2:1  +2:1  -2:1  -2:1  -2:1  +2:1  +2:1  +2:1  -2:1  -2:1  -2:1  +2:1  +2:1  +2:1  +2:1  +2:1  +2:1  +2:1

Code to load the address of a pitch envelope:
86DE    LDA $9EAB,Y
86E1    STA $D8
86E3    LDA $9EAC,Y
86E6    STA $D9

Volume Envelopes

Volume envelopes are significantly more complex and offer greater flexibility, consisting of 3 phases: attack, sustain, and release. However, any of these phases may be 0-length, and they need not be used as named; e.g. the attack or sustain envelopes can be used as decay instead, for non-sustaining instruments. Unlike pitch envelopes, channels have an envelope volume value separate from the channel volume specified by the corresponding channel command; these 2 values are multiplied to get the final volume which is actually written to the hardware.

Note auto-release is directly related to the volume envelope. When a note begins, the specified length of the note and any tied lengths are added up, and 3/4 of this value (subject to some rounding errors) is assigned as the note's sustain length. The sustain length determines the maximum time the note may stay in the sustain phase before it is forced into the release phase, if the envelope does not result in the phase ending sooner. This sustain length is exclusive to the sustain phase, and does not include the time spent in the attack phase; this makes it strongly recommended that harmonies between channels should share an envelope if there is an attack phase.

The attack phase is the simplest. It consists of a simple table of 1 or more volume values, 1 per frame; 1 value is always necessary to set the initial volume of the sustain and release phases. Each frame the corresponding value is assigned to the channel's envelope volume, and the attack phase ends when the table ends. While the intent of the attack phase is to go from pre-note silence to max volume, many FF3 envelopes use it as a decay envelope, fading out from max volume either to silence or to some lower sustained volume, and do not use sustain or release envelopes at all.

Sustain and release phases function almost identically and in fact share almost all of their code. They are notably more complex than the attack phase, for several reasons. The basic structure of sustain/release envelope tables is identical to that of the pitch envelope: a series of offset:length pairs with an optional repeat point, which tells the engine to set the volume and then wait for a number of frames before modifying it again.

However, there is a key difference in interpretation due to the fact that the purpose of a volume envelope is typically to fade out; in fact the primary mechanism of the sustain and release phases is a per-phase parameter that specifies fade-out speed between 0 (no fade out) and 100 (decrement the envelope volume each frame). This is how the envelope volume value is used, and when it reaches 0 the note is stopped, whether in sustain or release phase. The envelope table in fact serves as an adjustment value to this process; rather than actually modifying the envelope volume value, each frame the channel volume is multiplied by the envelope volume + the current adjustment value to get the value written to the hardware. As such the current table values do NOT accumulate, nor do they affect the end of note condition caused by the envelope volume value reaching 0. Conversely, the phase does not end when the table ends; rather, the fade out continues with no further modification from the table (i.e. the modification value is 0).

To summarize:

Attack Phase:
- Simple, per-frame table-based
- Table must contain at least 1 entry to serve as initial envelope volume
- Phase ends when the table ends
Sustain Phase:
- Initial volume specified by the final volume of the attack phase
- Advances to the release phase when auto-release occurs (when the note's sustain length expires)
Both Sustain and Release Phases:
- Persistent fade out + table-based modification value
- Table can loop
- The end of the table removes the volume modification step from the process but does not end the phase
- The note ends when the fade out reaches 0 volume regardless of the modification value
Release Phase:
- Only reachable via auto-release
- Initial volume specified by the final (unmodified) fade-out value of the sustain phase

Attack Envelope Format:
0v: Envelope volume v
ff (1--- ----): End of phase
Anything else: INVALID

Sustain/Release Envelope Header:
+0 byte: Volume fade-out/frame * 100, from 0 to 100. If 0, volume is never decremented.

Sustain/Release Envelope Format:
00: End of modification table. Fade-out continues as long as note is in phase.
0LLL LLLL vv: Use volume offset v (signed, two's complement) for the next L frames
1ooo oooo: Loop. Add 1:o (< 0) to current envelope position in bytes.

This offers considerable flexibility and potential for space-savings, though some examples may be needed to fully understand.

Volume Envelope 0 (0):
A @9ad4 (6dae4): 15  9  3  0

Envelope 0 has no sustain or release phases, and consists only of an attack envelope that serves as a rapid decay, and is used for the closed hihat preset among others. This is necessary because sustain/release phases cannot fade out faster than 1 volume per frame.

Volume Envelope 16 (10):
A @9c46 (6dc56): 15
S @9c48 (6dc58): 100
R @9c48 (6dc58): 100

Envelope 16 features a more gradual fade out. The attack phase simply sets the initial volume for the fade out, and the sustain and release phases have no modification tables but specify a fade out of 100: 1 volume per frame.

Volume Envelope 23 (17):
A @9cab (6dcbb):  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15

Envelope 23 is a pure attack envelope that ramps up to 15 and maintains max volume until the next note or rest.

Volume Envelope 37 (25):
A @9e75 (6de85): 15
S @9e77 (6de87):  0 -15:1  +0:1 -4->1
R @9e77 (6de87):  0 -15:1  +0:1 -4->1

Envelope 37 is an extreme tremolo (perhaps even frequency modulation) envelope. The alternating volume modifications each frame create a tremolo with a depth of 15 and period of 2 frames (30 Hz) that continues indefinitely (remember that the modification value causing the volume to be 0 does not cause the phase to end).

Volume Envelope Table:
36:9a7c struct[$29]
+0 word: Address of attack envelope
+2 word: Address of sustain envelope
+4 word: Address of release envelope

Volume Envelopes

For sustain/release envelopes pairs show volume offset on the left side and length on the right. Loops are indicated with structures like -2->4 which show the relative byte offset on the left side and the new absolute offset on the right (2x the number of offset:length pairs). Terminal bytes are not shown for non-looping envelope tables.

Volume Envelope 0 (0):
A @9ad4 (6dae4): 15  9  3  0
Volume Envelope 1 (1):
A @9ae1 (6daf1): 15 12  9  7  5  3  2  1  0
Volume Envelope 2 (2):
A @9af3 (6db03): 15 15 14 14 13 13 12 12 11 11 10 10  9  9  8  8  8  7  7  7  7  6
S @9b0a (6db1a): 20
R @9b0a (6db1a): 20
Volume Envelope 3 (3):
A @9af3 (6db03): 15 15 14 14 13 13 12 12 11 11 10 10  9  9  8  8  8  7  7  7  7  6
S @9b14 (6db24): 10
R @9b14 (6db24): 10
Volume Envelope 4 (4):
A @9b5b (6db6b):  5  6  7  8  9  9 10 10 11 11 12 12 13 13 15
S @9b6b (6db7b):  5  +0:2  -1:2 -4->1
R @9b6b (6db7b):  5  +0:2  -1:2 -4->1
Volume Envelope 5 (5):
A @9b89 (6db99): 11 12 13 14 15 14 13 12 11 10  9  8  7  7  6  6  6  5
S @9b9c (6dbac): 10
R @9b9c (6dbac): 10
Volume Envelope 6 (6):
A @9b89 (6db99): 11 12 13 14 15 14 13 12 11 10  9  8  7  7  6  6  6  5
S @9ba6 (6dbb6):  5
R @9ba6 (6dbb6):  5
Volume Envelope 7 (7):
A @9bb0 (6dbc0): 15  6  8  9 10 11 12 13 14 15
S @9bbb (6dbcb):  5  +0:1  -1:2  -2:2  -1:2  +0:1 -10->1
R @9bbb (6dbcb):  5  +0:1  -1:2  -2:2  -1:2  +0:1 -10->1
Volume Envelope 8 (8):
A @9bcf (6dbdf):  5  6  7  8  9  9 10 10 11 11 13 13 15 15
S @9bde (6dbee):  5  +0:1  -1:2  +0:1 -6->1
R @9bde (6dbee):  5  +0:1  -1:2  +0:1 -6->1
Volume Envelope 9 (9):
A @9bee (6dbfe): 15 14 13 12 11 10  9  8  8  7  7  7  6
S @9bfc (6dc0c): 25
R @9bfc (6dc0c): 25
Volume Envelope 10 (a):
A @9c10 (6dc20):  7  9 11 13 15
S @9c16 (6dc26):  5  +0:2  -1:2 -4->1
R @9c16 (6dc26):  5  +0:2  -1:2 -4->1
Volume Envelope 11 (b):
A @9af3 (6db03): 15 15 14 14 13 13 12 12 11 11 10 10  9  9  8  8  8  7  7  7  7  6
S @9b1e (6db2e):  5
R @9b1e (6db2e):  5
Volume Envelope 12 (c):
A @9b5b (6db6b):  5  6  7  8  9  9 10 10 11 11 12 12 13 13 15
S @9b79 (6db89):  5
R @9b79 (6db89):  5
Volume Envelope 13 (d):
A @9af3 (6db03): 15 15 14 14 13 13 12 12 11 11 10 10  9  9  8  8  8  7  7  7  7  6
S @9b14 (6db24): 10
R @9b14 (6db24): 10
Volume Envelope 14 (e):
A @9b5b (6db6b):  5  6  7  8  9  9 10 10 11 11 12 12 13 13 15
S @9b79 (6db89):  5
R @9b79 (6db89):  5
Volume Envelope 15 (f):
A @9c2a (6dc3a):  3  3  5  5  7  7  9  9 11 11 13 13 15
S @9c38 (6dc48):  5  +0:2  -1:2 -4->1
R @9c38 (6dc48):  5  +0:2  -1:2 -4->1
Volume Envelope 16 (10):
A @9c46 (6dc56): 15
S @9c48 (6dc58): 100
R @9c48 (6dc58): 100
Volume Envelope 17 (11):
A @9bee (6dbfe): 15 14 13 12 11 10  9  8  8  7  7  7  6
S @9c06 (6dc16):  5
R @9c06 (6dc16):  5
Volume Envelope 18 (12):
A @9c5c (6dc6c): 15 15 14 14 13 13 12
S @9c64 (6dc74):  0  +0:1  -1:2  -2:2  -1:2  +0:1 -10->1
R @9c64 (6dc74):  0  +0:1  -1:2  -2:2  -1:2  +0:1 -10->1
Volume Envelope 19 (13):
A @9c78 (6dc88): 15 13 11  9  7  5  4
Volume Envelope 20 (14):
A @9c88 (6dc98): 15 12  9  6  3  0
Volume Envelope 21 (15):
A @9c97 (6dca7): 15
S @9c99 (6dca9): 33
R @9c99 (6dca9): 33
Volume Envelope 22 (16):
A @9ca1 (6dcb1): 15
Volume Envelope 23 (17):
A @9cab (6dcbb):  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
Volume Envelope 24 (18):
A @9d40 (6dd50):  1  1  1  1  2  2  2  2  3  3  3  3  4  4  4  4  5  5  5  5  6  6  6  6  7  7  7  7  8  8  8  8  9  9  9  9 10 10 10 10 11 11 11 11 12 12 12 12 13 13 13 13 14 14 14 14 15 15 15 15  0
Volume Envelope 25 (19):
A @9dcb (6dddb):  1  3  5  7  7  7  7  7  7  7  7  9 11 13 15 15 15 15 15 15 15 15 15 13 11  9  7  7  7  7  7  7  7  7  5  3  1  0
Volume Envelope 26 (1a):
A @9e29 (6de39):  3  6  9 12 15
Volume Envelope 27 (1b):
A @9e46 (6de56): 15 15  3  3  6  9 12 15
S @9e4f (6de5f): 33
R @9e4f (6de5f): 33
Volume Envelope 28 (1c):
A @9cab (6dcbb):  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
S @9cdd (6dced):  0  -3:1  -6:1  -9:1  -6:1  -3:1  +0:1 -12->1
R @9cdd (6dced):  0  -3:1  -6:1  -9:1  -6:1  -3:1  +0:1 -12->1
Volume Envelope 29 (1d):
A @9c46 (6dc56): 15
S @9c50 (6dc60): 100  -6:1  +0:1 -4->1
R @9c50 (6dc60): 100  -6:1  +0:1 -4->1
Volume Envelope 30 (1e):
A @9e57 (6de67):  3  6  9 12 15
S @9e5d (6de6d):  0  -2:1  -4:1  -6:1  -4:1  -2:1  +0:1 -12->1
R @9e5d (6de6d):  0  -2:1  -4:1  -6:1  -4:1  -2:1  +0:1 -12->1
Volume Envelope 31 (1f):
A @9d86 (6dd96):  1  0  1  0  2  0  2  0  3  0  3  0  4  0  4  0  5  0  5  0  6  0  6  0  7  0  7  0  8  0  8  0  9  0  9  0 10  0 10  0 11  0 11  0 12  0 12  0 13  0 13  0 14  0 14  0 15  0 15  0
Volume Envelope 32 (20):
A @9cf9 (6dd09):  0  2  0  4  0  6  0  8  0 10  0 12  0 14  0 15
S @9d0a (6dd1a):  0 -15:1  +0:1 -4->1
R @9d0a (6dd1a):  0 -15:1  +0:1 -4->1
Volume Envelope 33 (21):
A @9d1c (6dd2c):  1  0  3  0  5  0  7  0  9  0 11  0 13  0 15
S @9d2c (6dd3c):  0 -15:1 -15:1  +0:1 -4->3
R @9d2c (6dd3c):  0 -15:1 -15:1  +0:1 -4->3
Volume Envelope 34 (22):
A @9cc5 (6dcd5):  8  0  9  0 10  0 11  0 12  0 13  0 14  0 15
S @9cd5 (6dce5): 100
R @9cd5 (6dce5): 100
Volume Envelope 35 (23):
A @9cab (6dcbb):  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
S @9cf1 (6dd01): 100
R @9cf1 (6dd01): 100
Volume Envelope 36 (24):
A @9dfa (6de0a):  1  0  5  0  7  0  7  0  7  0  7  0 11  0 15  0 15  0 15  0 15  0 15  0 11  0  7  0  7  0  7  0  7  0  5  0  1  0
Volume Envelope 37 (25):
A @9e75 (6de85): 15
S @9e77 (6de87):  0 -15:1  +0:1 -4->1
R @9e77 (6de87):  0 -15:1  +0:1 -4->1
Volume Envelope 38 (26):
A @9e37 (6de47):  3  6  9 12 15  0
Volume Envelope 39 (27):
A @9b2e (6db3e): 15 15 14 14 13 13 12 12 11 11 10 10  9  9  8  8  8  7  7  7  6  6  6  6  5  5  5  5  5  4  4  4  4  4  4  3
S @9b53 (6db63):  5
R @9b53 (6db63):  5
Volume Envelope 40 (28):
A @9e83 (6de93):  7  7  9 11 13 15 15 15 15 10  5 10 15 10  5  0  5 10 15 10  5  0  0  5 10 15 10  5  0  0  0  5 10 15 10  5  0

Code to load a volume envelope table address:
85BB    LDA $9A7C,Y
85BE    STA $D6
85C0    LDA $9A7D,Y
85C3    STA $D7

SOUND EFFECT FORMAT

The sound effect format is nearly identical to the music format, and is played mostly by the same code. The only 2 noteworthy differences are that sound effects are limited to the square 2 and noise channels and have a fixed tempo of 150 BPM in which 1 tick = 1 frame (see the note/rest length table); in fact sound effects MUST NOT set the tempo, as that will set the tempo for music playback instead.

Sound Effect Header Structure:
+0 word[2]: Channel data addresses in order of square 2, noise

ADDITIONAL TABLES

Note/Rest Length Table in Ticks:
0: Whole (96)
1: Dotted half (72)
2: Half (48)
3: Dotted 4th (36)
4: Triplet half (32)
5: 4th (24)
6: Dotted 8th (18)
7: Triplet 4th (16)
8: 8th (12)
9: Dotted 16th (9)
a: Triplet 8th (8)
b: 16th (6)
c: Triplet 16th (4)
d: 32nd (3)
e: Triplet 32nd (2)
f: Triplet 64th (1)

Track Tables

FF3 distributes both its tracks and its track tables across multiple $2000-byte banks. The bank at address $8000 is $36 for all sound code, while the bank at $a000 and header address are shown below. Note that sometimes the track header or channel data is in the common bank at $8000-$9fff.

Track Header Address Tables (array of words):
37:a000: Tracks 0 (0) to 24 (18)
38:a000: Tracks 25 (19) to 42 (2a)
39:8c77: Tracks 43 (2b) to 54 (36)
39:b3ae: Tracks 55 (37) to 58 (3a)
 9:b400: Tracks 59 (3b) to 64 (40)

Combined Track and Channel Addresses:
 # Name                        Bk HdrA   Sq1A  Sq2A  TriA  NoiA  KckA
 0 Resting at the Inn          37:a032:  a03c  a05f  a067
 1 The Prelude                 37:a07c:  a086  a1ca
 2 Crystal Cave                37:a1d2:  a1dc  a324  a401
 3 Elia, the Maiden of Water   37:a444:  a44e  a4a6  a4ae
 4 Lute of Noah                37:a56a:  a574  a641
 5 Return of the Warrior       37:a685:  a68f  a700  a774
 6 Town of Water               37:a7f6:  a800  a861  a8bf
 7 Fanfare                     37:a97c:  a986  a9d6  aa1f  aa5f  aa6e
 8 Chocobos!                   37:aa81:  aa8b  ab3d  ab81
 9 Good Ol' Fellows            37:abef:  abf9  ac7e  acd8
 a Go Above the Clouds!        37:ad36:  ad40  ada4  ae40
 b Cute Little Tozas           37:aeb9:  aec3  af5a  afd6
 c Jinn, the Fire              37:b042:  b04c  b0ba  b114
 d Living Forest               37:b16c:  b176  b1fa  b25b
 e Hazardous Short Music 3     37:b2b8:  b2c2  b2e9  b30e
 f Beneath the Horizon         37:b323:  b32d  b370  b403
10 Time Remains                37:b452:  b45c  b4b2  b502
11 Vegies of Geasal            37:b58b:  b595  b608  b66a
12 In the Covert Town          37:b6a8:  b6b2  b77d  b879
13 The Requiem                 37:b92a:  b934  b9b2  ba35
14 Opening Theme               37:ba6d:  ba77  bb0c  bbad
15 Deep Under the Water        37:bc54:  bc5e  bcb5  bd60
16 Shrine of Nept              37:be23:  be2d  be9f  becd
17 Item Get                    37:bf3d:  bf47  bf63  bf74
18 Garuda Defeat               37:bf81:  bf8b  bfb8  bfdc
19 Big Chocobo!                38:a024:  a02e  a090  a0e5
1a Swift Twist                 38:a125:  a12f  a175  a1ab
1b Good Morning!               38:a1d2:  a1dc  a23a  a268
1c Dancer's Dance              38:a2a7:  a2b1  a2ed  a31e
1d The Dungeon                 38:a332:  a33c  a37c  a3e3
1e Eternal Wind                38:a46f:  a479  a4f9  a63d
1f My Home Town                38:a748:  a752  a7cd  a827
20 Battle                      38:a92b:  a935  a9bf  aae1  aba6  ac38
21 The Way to the Top          38:ac7f:  ac89  acde  ad5b
22 Sailing Enterprise          38:ad97:  ada1  ae05  ae5d
23 The Invincible              38:af00:  af0a  af8b  b02e
24 Tower of Owen               38:b0a5:  b0af  b163  b201
25 The Crystal Tower           38:b236:  b240  b2b4  b364
26 Let Me Know the Truth       38:b40b:  b415  b4c9  b542
27 Forbidden Land              38:b585:  b58f  b5e6  b675
28 This is the Last Battle 3   38:b717:  b721  b851  b927  b9ba  ba66
29 The Dark Crystals           38:ba9a:  baa4  bb02  bc22
2a Boss Battle                 38:bcc0:  bcca  bd8b  be98  bf61  bfb7
2b Parting with a Companion    39:8c8f:  8c99  8cb5  8cc9
2c Added Companion             39:8cd2:  8cdc  8cf6  8d13
2d Hazardous Short Music 2     39:8d1a:  8d24  8d57  8d84
2e Salonia                     39:8da2:  8dac  8e21  8ed4
2f The Boundless Ocean         39:8f76:  8f80  8fe6  9043
30 Fall SFX                    39:9128:  9132  913b        9140
31 Danger SFX                  39:9148:  9152  916b  9182  918c
32 Shattering SFX              39:919c:  91a6  91b4        91b9
33 Applause SFX                39:91c3:  91cd  91da  91e5  91f0
34 Boo SFX                     39:9201:  920b  9215
35 Bahamut Flies SFX           39:9220:  922a  922c        923d
36 Crystal Room                39:924a:  9254  92bd
37 The Everlasting World 2     39:b3b6:  b3c0  b4c8  b6f9
38 Castle of Hain              39:b876:  b880  b913  b9d8
39 Chocobo Forest              39:ba82:        ba8c  baa4
3a Let's Play the Piano Again! 39:babf:  bac9  bae9
3b The Everlasting World 3      9:b40c:  b416  b57d  b991  bb7a
3c The Everlasting World 1      9:bcc7:  bcd1  bd58
3d Hazardous Short Music 1      9:be7f:  be89  beb4  bf00
3e This is the Last Battle 1    9:bf14:  bf1e  bf69  bf71
3f This is the Last Battle 2    9:bfa5:  bfaf  bf69  bf71
40 Let's Play the Piano!        9:bfb4:  bfbe

Moving Track Tables and Data

This multi-bank system is implemented in a rather complex way across multiple functions and data structures, and changes to relocate the tables or track data will also be a bit complex. 

First, an array of 4 bytes gives the bank numbers to be loaded at $a000:

36:89bf ($6c9cf): $37, $38, $39, 9

The bank is switched to based on this table and the track number by the function at 36:899f ($6c9af):

899F    LDA #$07
89A1    STA $8000
89A4    LDX #$00
89A6    LDA $7F43
89A9    CMP #$19
89AB    BCC $89B8
89AD    INX
89AE    CMP #$2B
89B0    BCC $89B8
89B2    INX
89B3    CMP #$3B
89B5    BCC $89B8
89B7    INX
89B8    LDA $89BF,X
89BB    STA $8001
89BE    RTS

Finally, the locations of the track tables are specified by the following code at 36:8a00 ($6CA10):

8A00    LDA $7F43
8A03    CMP #$19
8A05    BCC $8A0E
8A07    CMP #$2B
8A09    BCS $8A1D
8A0B    SEC
8A0C    SBC #$19
8A0E    ASL A
8A0F    TAX
8A10    LDA $A000,X
8A13    STA $D8
8A15    LDA $A001,X
8A18    STA $D9
8A1A    JMP $8A57
8A1D    CMP #$37
8A1F    BCS $8A33
8A21    SEC
8A22    SBC #$2B
8A24    ASL A
8A25    TAX
8A26    LDA $8C77,X
8A29    STA $D8
8A2B    LDA $8C78,X
8A2E    STA $D9
8A30    JMP $8A57
8A33    CMP #$3B
8A35    BCS $8A49
8A37    SEC
8A38    SBC #$37
8A3A    ASL A
8A3B    TAX
8A3C    LDA $B3AE,X
8A3F    STA $D8
8A41    LDA $B3AF,X
8A44    STA $D9
8A46    JMP $8A57
8A49    SBC #$3B
8A4B    ASL A
8A4C    TAX
8A4D    LDA $B400,X
8A50    STA $D8
8A52    LDA $B401,X
8A55    STA $D9

Sound Effect Table

Sound Effect Table Address: 36:92c5

Unlike music, all sound effect data is stored in bank $36.

Track   Addr  Sq2A  Sq2FO  NoiA  NoiFO
 0 (0)  9387: 938b (6d39b) 9393 (6d3a3)
 1 (1)  939a: 939e (6d3ae) ffff
 2 (2)  93a8: 93ac (6d3bc) 93b8 (6d3c8)
 3 (3)  93c2: ffff         93c6 (6d3d6)
 4 (4)  93cc: ffff         93d0 (6d3e0)
 5 (5)  93df: 93e3 (6d3f3) ffff
 6 (6)  93ec: 93f0 (6d400) ffff
 7 (7)  93ff: 9403 (6d413) 940b (6d41b)
 8 (8)  9411: 9415 (6d425) ffff
 9 (9)  9420: 9424 (6d434) ffff
10 (a)  942c: ffff         9430 (6d440)
11 (b)  9440: 9444 (6d454) ffff
12 (c)  944f: 9453 (6d463) 945b (6d46b)
13 (d)  9463: 9467 (6d477) 9476 (6d486)
14 (e)  947f: 9483 (6d493) 949a (6d4aa)
15 (f)  94b3: 94b7 (6d4c7) 94be (6d4ce)
16 (10) 94c6: 94ca (6d4da) 94d3 (6d4e3)
17 (11) 94dd: ffff         94e1 (6d4f1)
18 (12) 94e7: ffff         94eb (6d4fb)
19 (13) 94f2: 94f6 (6d506) ffff
20 (14) 94fe: 9502 (6d512) ffff
21 (15) 950a: 950e (6d51e) 9517 (6d527)
22 (16) 9520: ffff         9524 (6d534)
23 (17) 952c: 9530 (6d540) ffff
24 (18) 953a: 953e (6d54e) ffff
25 (19) 9546: 954a (6d55a) ffff
26 (1a) 9550: 9554 (6d564) 955a (6d56a)
27 (1b) 9560: ffff         9564 (6d574)
28 (1c) 956b: 956f (6d57f) 9579 (6d589)
29 (1d) 957f: 9583 (6d593) ffff
30 (1e) 958e: 9592 (6d5a2) ffff
31 (1f) 9599: 959d (6d5ad) 95a8 (6d5b8)
32 (20) 95b4: 95b8 (6d5c8) ffff
33 (21) 95c3: 95c7 (6d5d7) 95cd (6d5dd)
34 (22) 95d7: ffff         95db (6d5eb)
35 (23) 95e6: ffff         95ea (6d5fa)
36 (24) 95f8: 95fc (6d60c) ffff
37 (25) 9604: ffff         9608 (6d618)
38 (26) 9612: ffff         9616 (6d626)
39 (27) 9620: ffff         9624 (6d634)
40 (28) 962f: ffff         9633 (6d643)
41 (29) 963e: 9642 (6d652) 964b (6d65b)
42 (2a) 9653: 9657 (6d667) 9662 (6d672)
43 (2b) 966c: ffff         9670 (6d680)
44 (2c) 967d: 9681 (6d691) 968e (6d69e)
45 (2d) 969c: 96a0 (6d6b0) ffff
46 (2e) 9387: 938b (6d39b) 9393 (6d3a3)
47 (2f) 96a8: 96ac (6d6bc) 96b4 (6d6c4)
48 (30) 96c5: ffff         96c9 (6d6d9)
49 (31) 96d4: 96d8 (6d6e8) 96eb (6d6fb)
50 (32) 96fc: ffff         9700 (6d710)
51 (33) 970e: ffff         9712 (6d722)
52 (34) 971e: 9722 (6d732) ffff
53 (35) 972e: 9732 (6d742) 973c (6d74c)
54 (36) 974a: 974e (6d75e) 9757 (6d767)
55 (37) 975e: 9762 (6d772) 976a (6d77a)
56 (38) 9779: 977d (6d78d) 978a (6d79a)
57 (39) 9795: ffff         9799 (6d7a9)
58 (3a) 9387: 938b (6d39b) 9393 (6d3a3)
59 (3b) 97a1: ffff         97a5 (6d7b5)
60 (3c) 97bf: 97c3 (6d7d3) 97d1 (6d7e1)
61 (3d) 97de: 97f8 (6d808) 97e2 (6d7f2)
62 (3e) 9806: 980a (6d81a) 9816 (6d826)
63 (3f) 981d: 9821 (6d831) ffff
64 (40) 9829: ffff         982d (6d83d)
65 (41) 9836: ffff         983a (6d84a)
66 (42) 9845: ffff         9849 (6d859)
67 (43) 985d: ffff         9861 (6d871)
68 (44) 986e: 9872 (6d882) 987b (6d88b)
69 (45) 9881: ffff         9885 (6d895)
70 (46) 988f: ffff         9893 (6d8a3)
71 (47) 989a: 989e (6d8ae) 98a5 (6d8b5)
72 (48) 98ab: 98af (6d8bf) 98b6 (6d8c6)
73 (49) 98bd: 98c1 (6d8d1) 98c7 (6d8d7)
74 (4a) 98d1: 98d5 (6d8e5) 98e0 (6d8f0)
75 (4b) 98e9: 98ed (6d8fd) ffff
76 (4c) 98f6: ffff         98fa (6d90a)
77 (4d) 9903: ffff         9907 (6d917)
78 (4e) 990f: ffff         9913 (6d923)
79 (4f) 9922: 9926 (6d936) 9930 (6d940)
80 (50) 9938: 993c (6d94c) 9947 (6d957)
81 (51) 9951: 9955 (6d965) 996b (6d97b)
82 (52) 9975: 9979 (6d989) 9982 (6d992)
83 (53) 9989: 998d (6d99d) 9999 (6d9a9)
84 (54) 99a3: 99a7 (6d9b7) ffff
85 (55) 99b2: ffff         99b6 (6d9c6)
86 (56) 99c3: ffff         99c7 (6d9d7)
87 (57) 99cd: 99d1 (6d9e1) 99d9 (6d9e9)
88 (58) 99e4: ffff         99e8 (6d9f8)
89 (59) 99f2: ffff         99f6 (6da06)
90 (5a) 96ba: ffff         96be (6d6ce)
91 (5b) 97ad: 97b1 (6d7c1) 97b9 (6d7c9)
92 (5c) 99ff: 9a03 (6da13) 9a1d (6da2d)
93 (5d) 9a3b: 9a3f (6da4f) ffff
94 (5e) 9a4e: 9a52 (6da62) ffff
95 (5f) 9a5b: 9a5f (6da6f) ffff
96 (60) 9a66: 9a6a (6da7a) ffff

Download [880]Final Fantasy III (NES) Sound Format.txt ↓

FROM THE COMMUNITY

Player reviews

0 reviews
No ratings yet

Played this project? Tell other players how it holds up.

Your take on Final Fantasy III (NES) Sound Format

Spam has been overwhelming. To help us approve your review, sign up and introduce yourself in the Introductions forum so we know you’re not a bot.

Sign in with your Retro Replay account to rate this project and share your experience.

Sign in to review