-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFinal Fantasy III (NES) Sound Format.txt
764 lines (668 loc) · 38.8 KB
/
Final Fantasy III (NES) Sound Format.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
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