Difference between revisions of "FF7/PSX/Sound/AKAO sequence"

From Final Fantasy Inside
< FF7
Jump to navigation Jump to search
Line 142: Line 142:
 
|Channel Master Volume
 
|Channel Master Volume
 
|2
 
|2
|volume: byte
+
|volume: byte (0-127)
 
|
 
|
 
|-
 
|-
Line 149: Line 149:
 
|3
 
|3
 
|length: byte, semitones: signed byte
 
|length: byte, semitones: signed byte
|
+
|When <code>length</code> is 0, it will be translated to 256 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xa5|0xA5]]
 
|[[FF7/PSX/Sound/Opcodes/0xa5|0xA5]]
 
|Set Octave
 
|Set Octave
 
|2
 
|2
|octave: byte
+
|octave: byte (0-15)
 
|
 
|
 
|-
 
|-
Line 172: Line 172:
 
|Channel Volume
 
|Channel Volume
 
|2
 
|2
|volume: byte
+
|volume: byte (0-127)
 
|
 
|
 
|-
 
|-
Line 178: Line 178:
 
|Channel Volume Slide
 
|Channel Volume Slide
 
|3
 
|3
|length: byte, volume: byte
+
|length: byte, volume: byte (0-127)
|
+
|When <code>length</code> is 0, it will be translated to 256 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xa8aa|0xAA]]
 
|[[FF7/PSX/Sound/Opcodes/0xa8aa|0xAA]]
 
|Channel Pan
 
|Channel Pan
 
|2
 
|2
|pan: byte
+
|pan: byte (0-127)
 
|64 is the center
 
|64 is the center
 
|-
 
|-
Line 190: Line 190:
 
|Channel Pan Slide
 
|Channel Pan Slide
 
|3
 
|3
|length: byte, pan: byte
+
|length: byte, pan: byte (0-127)
|
+
|When <code>length</code> is 0, it will be translated to 256 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xac|0xAC]]
 
|[[FF7/PSX/Sound/Opcodes/0xac|0xAC]]
 
|Noise Clock Frequency
 
|Noise Clock Frequency
 
|2
 
|2
|clock: byte
+
|clock: byte (0x00-0x3f)
 
|
 
|
 
|-
 
|-
Line 202: Line 202:
 
|ADSR: Attack Rate
 
|ADSR: Attack Rate
 
|2
 
|2
|attack_rate: byte
+
|attack_rate: byte (0x00-0x7f)
 
|
 
|
 
|-
 
|-
Line 208: Line 208:
 
|ADSR: Decay Rate
 
|ADSR: Decay Rate
 
|2
 
|2
|decay_rate: byte
+
|decay_rate: byte (0x00-0x0f)
 
|
 
|
 
|-
 
|-
Line 214: Line 214:
 
|ADSR: Sustain Level
 
|ADSR: Sustain Level
 
|2
 
|2
|sustain_level: byte
+
|sustain_level: byte (0x00-0x0f)
 
|
 
|
 
|-
 
|-
Line 220: Line 220:
 
|ADSR: Decay Rate & Sustain Level
 
|ADSR: Decay Rate & Sustain Level
 
|3
 
|3
|decay_rate: byte, sustain_level: byte
+
|decay_rate: byte (0x00-0x0f), sustain_level: byte (0x00-0x0f)
 
|
 
|
 
|-
 
|-
Line 226: Line 226:
 
|ADSR: Sustain Rate
 
|ADSR: Sustain Rate
 
|2
 
|2
|sustain_rate: byte
+
|sustain_rate: byte (0x00-0x7f)
 
|
 
|
 
|-
 
|-
Line 232: Line 232:
 
|ADSR: Release Rate
 
|ADSR: Release Rate
 
|2
 
|2
|release_rate: byte
+
|release_rate: byte (0x00-0x1f)
 
|
 
|
 
|-
 
|-
Line 244: Line 244:
 
|Channel Pitch LFO (Vibrato)
 
|Channel Pitch LFO (Vibrato)
 
|4
 
|4
|delay: byte, rate: byte, type: byte
+
|delay: byte, rate: byte, type: byte (0-15)
|
+
|When <code>rate</code> is 0, it will be translated to 256 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xb4b5|0xB5]]
 
|[[FF7/PSX/Sound/Opcodes/0xb4b5|0xB5]]
Line 262: Line 262:
 
|ADSR: Attack Mode
 
|ADSR: Attack Mode
 
|2
 
|2
|attack_mode: byte
+
|attack_mode: byte (1 or 5)
 
|
 
|
 
|-
 
|-
Line 268: Line 268:
 
|Channel Volume LFO (Tremolo)
 
|Channel Volume LFO (Tremolo)
 
|4
 
|4
|delay: byte, rate: byte, type: byte
+
|delay: byte, rate: byte, type: byte (0-15)
|
+
|When <code>rate</code> is 0, it will be translated to 256 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xb8b9|0xB9]]
 
|[[FF7/PSX/Sound/Opcodes/0xb8b9|0xB9]]
Line 286: Line 286:
 
|ADSR: Sustain Mode
 
|ADSR: Sustain Mode
 
|2
 
|2
|sustain_mode: byte
+
|sustain_mode: byte (1, 3, 5 or 7)
 
|
 
|
 
|-
 
|-
Line 292: Line 292:
 
|Channel Pan LFO
 
|Channel Pan LFO
 
|3
 
|3
|rate: byte, type: byte
+
|rate: byte, type: byte (0-15)
|
+
|When <code>rate</code> is 0, it will be translated to 256 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xbcbd|0xBD]]
 
|[[FF7/PSX/Sound/Opcodes/0xbcbd|0xBD]]
Line 310: Line 310:
 
|ADSR: Release Mode
 
|ADSR: Release Mode
 
|2
 
|2
|release_mode: byte
+
|release_mode: byte (3 or 7)
 
|
 
|
 
|-
 
|-
Line 365: Line 365:
 
|1
 
|1
 
|
 
|
|
+
|Remember the current offset as a loop point and increase the nesting level of the loop.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xc8c9|0xC9]]
 
|[[FF7/PSX/Sound/Opcodes/0xc8c9|0xC9]]
Line 371: Line 371:
 
|2
 
|2
 
|times: byte
 
|times: byte
|
+
|On the Nth repeat, this instruction will end the current loop by decrementing the nesting level of the loop. Otherwise, it will increment the loop counter and return to the loop point.
 +
When <code>times</code> is 0, it will be translated to 256 times.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xc8c9|0xCA]]
 
|[[FF7/PSX/Sound/Opcodes/0xc8c9|0xCA]]
Line 377: Line 378:
 
|1
 
|1
 
|
 
|
|
+
|This instruction will increment the loop counter.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xcb|0xCB]]
 
|[[FF7/PSX/Sound/Opcodes/0xcb|0xCB]]
Line 401: Line 402:
 
|2
 
|2
 
|delay: byte
 
|delay: byte
|
+
|When <code>delay</code> is 0, it will be translated to 257 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xcecf|0xCF]]
 
|[[FF7/PSX/Sound/Opcodes/0xcecf|0xCF]]
Line 407: Line 408:
 
|2
 
|2
 
|delay: byte
 
|delay: byte
|
+
|When <code>delay</code> is 0, it will be translated to 257 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xd0d1|0xD0]]
 
|[[FF7/PSX/Sound/Opcodes/0xd0d1|0xD0]]
Line 425: Line 426:
 
|2
 
|2
 
|delay: byte
 
|delay: byte
|
+
|When <code>delay</code> is 0, it will be translated to 257 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xd2d3|0xD3]]
 
|[[FF7/PSX/Sound/Opcodes/0xd2d3|0xD3]]
Line 431: Line 432:
 
|2
 
|2
 
|delay: byte
 
|delay: byte
|
+
|When <code>delay</code> is 0, it will be translated to 257 ticks.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xd4d5|0xD4]]
 
|[[FF7/PSX/Sound/Opcodes/0xd4d5|0xD4]]
Line 516: Line 517:
 
|tempo: uint16
 
|tempo: uint16
 
|bpm = tempo / 214.998204 (approximate)
 
|bpm = tempo / 214.998204 (approximate)
 +
Note that this coefficient is different from other games with PlayStation AKAO.
 
|-
 
|-
 
|[[FF7/PSX/Sound/Opcodes/0xe8e9|0xE9]]
 
|[[FF7/PSX/Sound/Opcodes/0xe8e9|0xE9]]

Revision as of 09:06, 31 May 2020

Introduction

AKAO frames are most complicated frames in FF7 sound system. ("AKAO" is frame magic, probably developed by Minoru Akao, Square Enix sound programmer :) )

Frame is similar to MIDI sequence - it's custom tracker format for playing sequence sound, well tuned specially for PSX.

This frames are in all FF7 game modules: Field, Battle, Worldmap and in minigames.

All files with exension *.SND are AKAO.

  • MINI/ASERI2.SND - Battle Arena theme
  • MINI/SENSUI.SND - used in Submarine minigame
  • ENEMY6/OVER2.SND - game over sequence
  • ENEMY6/FAN2.SND - battle win "fanfare" sequence
  • MOVIE/OVER2.SND - same game over sequence, don't know, why to duplicate data

Other AKAO frames are hard-wired in other files.


AKAO frame structure

Header (size: 16 bytes)

struct AkaoHeader
{
  static const uint8_t magic[4];  // "AKAO" C-string aka frame *MAGIC*
  uint16_t id;                    // frame ID, used for playing sequence
  uint16_t length;                // frame length - sizeof(header)
  uint16_t reverb_type;           // reverb type (range from 0 to 9)
  struct AkaoTimeStamp
  {
    uint8_t year_bcd;             // year (in binary coded decimal)
    uint8_t month_bcd;            // month (in binary coded decimal, between 0x01 - 0x12)
    uint8_t day_bcd;              // day (in binary coded decimal, between 0x01 - 0x31)
    uint8_t hours_bcd;            // hours (in binary coded decimal, between 0x00 - 0x23)
    uint8_t minutes_bcd;          // minutes (in binary coded decimal, between 0x00 - 0x59)
    uint8_t seconds_bcd;          // seconds (in binary coded decimal, between 0x00 - 0x59)
  } timestamp;
};

Channel info (size: 4 bytes + 2 bytes * <channels count>)

struct AkaoChannelInfo
{
  uint32_t mask;                         // represents bitmask of used channels in this frame
  uint32_t start_offsets[num_channels];  // offsets to channel opcode data
};
int num_channels = 0;
while (int bit = 0; ((info.mask & 0xFFFFFF) & (1 << bit)) != 0; bit++)
  num_channels++;

First there is 32-bit number (offset 0x10), which represents bitmask of used channels in this frame.

After this frame, there is <channels count> offsets to channel opcode data counting from current offset. Each offsets is a relative offset based on the address *next to* the offset itself. (This is a general rule for early versions of AKAO to interpret relative offsets.)


Channel Commands [AKAO Opcodes]

Most complicated part.

For every channel in AKAO frame there is set of commands to perform. This is similar to Field opcodes. Here I'll call this sound commands "opcodes". Every opcode has it's own number of arguments (from no-arguments, to 3 arguments).

Example (home-created AKAO frame):

Header

41 4b 41 4f - AKAO string

34 12 - frame ID: 0x1234

16 00 - frame length 0x16 in hex or 22 in decimal

04 00 - reverb type: 4 (large studio)

96 12 18 22 46 28 - unknown data


Channel info

01 00 00 00 - this indicates, that used only one channel

00 00 - offset to first channel opcodes: in our example 0x00 means that next to this offset is opcodes for first channel


Channel commands

e8 a8 66 - sets tempo, parameter 0x66a8

ea 00 50 - sets reverb depth

a8 55 - load sample 0x55 from INSTR.ALL to channel

aa 40 - sets channel volume

c2 - turns on reverb effect

a1 0c - sets volume pan

c8 - sets loop point

66 - 0x66 % 11 = 3 (3 means to take 3rd number from play length table), 0x66 / 11 = 9 (9 means to take pitch[9] from loaded instrument record index)

ca - returns to saved loop point with opcode c8


This example plays Chocobo "Whoo-Hoo" (instrument number 0x55) repeatedly.


Sound Opcode list

Opcode Summary Length Operands Note
0x00-0x99 Note, Tie, Rest 1 The opcode indicates the note key and length.
0x9A-0x9F Unimplemented n/a Should not be used. The opcode indicates the note key and length.
0xA0 Finish Channel 1
0xA1 Load Instrument 2 instrument: byte
0xA2 Overwrite Next Note Length 2 length: byte Ignores the regular length (delta-time) of the next note and overwrites it with the specified length.
0xA3 Channel Master Volume 2 volume: byte (0-127)
0xA4 Pitch Bend Slide 3 length: byte, semitones: signed byte When length is 0, it will be translated to 256 ticks.
0xA5 Set Octave 2 octave: byte (0-15)
0xA6 Increase Octave 1
0xA7 Decrease Octave 1
0xA8 Channel Volume 2 volume: byte (0-127)
0xA9 Channel Volume Slide 3 length: byte, volume: byte (0-127) When length is 0, it will be translated to 256 ticks.
0xAA Channel Pan 2 pan: byte (0-127) 64 is the center
0xAB Channel Pan Slide 3 length: byte, pan: byte (0-127) When length is 0, it will be translated to 256 ticks.
0xAC Noise Clock Frequency 2 clock: byte (0x00-0x3f)
0xAD ADSR: Attack Rate 2 attack_rate: byte (0x00-0x7f)
0xAE ADSR: Decay Rate 2 decay_rate: byte (0x00-0x0f)
0xAF ADSR: Sustain Level 2 sustain_level: byte (0x00-0x0f)
0xB0 ADSR: Decay Rate & Sustain Level 3 decay_rate: byte (0x00-0x0f), sustain_level: byte (0x00-0x0f)
0xB1 ADSR: Sustain Rate 2 sustain_rate: byte (0x00-0x7f)
0xB2 ADSR: Release Rate 2 release_rate: byte (0x00-0x1f)
0xB3 ADSR: Reset ADSR 1
0xB4 Channel Pitch LFO (Vibrato) 4 delay: byte, rate: byte, type: byte (0-15) When rate is 0, it will be translated to 256 ticks.
0xB5 Channel Pitch LFO Depth 2 depth: byte
0xB6 Turn Off Channel Pitch LFO 1
0xB7 ADSR: Attack Mode 2 attack_mode: byte (1 or 5)
0xB8 Channel Volume LFO (Tremolo) 4 delay: byte, rate: byte, type: byte (0-15) When rate is 0, it will be translated to 256 ticks.
0xB9 Channel Volume LFO Depth 2 depth: byte
0xBA Turn Off Channel Volume LFO 1
0xBB ADSR: Sustain Mode 2 sustain_mode: byte (1, 3, 5 or 7)
0xBC Channel Pan LFO 3 rate: byte, type: byte (0-15) When rate is 0, it will be translated to 256 ticks.
0xBD Channel Pan LFO Depth 2 depth: byte
0xBE Turn Off Channel Pan LFO 1
0xBF ADSR: Release Mode 2 release_mode: byte (3 or 7)
0xC0 Channel Transpose (Absolute) 2 semitones: signed byte
0xC1 Channel Transpose (Relative) 2 semitones: signed byte
0xC2 Turn On Reverb 1
0xC3 Turn Off Reverb 1
0xC4 Turn On Noise 1
0xC5 Turn Off Noise 1
0xC6 Turn On Frequency Modulation 1
0xC7 Turn Off Frequency Modulation 1
0xC8 Loop Point 1 Remember the current offset as a loop point and increase the nesting level of the loop.
0xC9 Return to Loop Point Up to N Times 2 times: byte On the Nth repeat, this instruction will end the current loop by decrementing the nesting level of the loop. Otherwise, it will increment the loop counter and return to the loop point.

When times is 0, it will be translated to 256 times.

0xCA Return to Loop Point 1 This instruction will increment the loop counter.
0xCB Reset Sound Effects 1 Reset sound effects such as noise, frequency modulation, reverb, overlay voice and alternate voice.
0xCC Turn On Legato 1 This instruction will stop the regular key on and key off performance of the subsequent notes and update the pitch only.
0xCD Turn Off Legato 1
0xCE Turn On Noise and Toggle Noise On/Off after a Period of Time 2 delay: byte When delay is 0, it will be translated to 257 ticks.
0xCF Toggle Noise On/Off after a Period of Time 2 delay: byte When delay is 0, it will be translated to 257 ticks.
0xD0 Turn On Full-Length Note Mode 1 This instruction will stop the regular key off performance of the subsequent notes.
0xD1 Turn Off Full-Length Note Mode 1
0xD2 Turn On Frequency Modulation and Toggle Frequency Modulation On/Off after a Period of Time 2 delay: byte When delay is 0, it will be translated to 257 ticks.
0xD3 Toggle Frequency Modulation On/Off after a Period of Time 2 delay: byte When delay is 0, it will be translated to 257 ticks.
0xD4 Turn On Playback Rate Side Chain 1 Duplicate and use the playback frequency of the previous voice channel.
0xD5 Turn Off Playback Rate Side Chain 1
0xD6 Turn On Pitch-Volume Side Chain 1 Multiply the playback frequency of the previous voice channel to the output volume. Lower pitch will make the volume smaller.
0xD7 Turn Off Pitch-Volume Side Chain 1
0xD8 Channel Fine Tuning (Absolute) 2 amount: signed byte
0xD9 Channel Fine Tuning (Relative) 2 amount: signed byte
0xDA Turn On Portamento 2 speed: byte
0xDB Turn Off Portamento 1
0xDC Fix Note Length 2 length_to_add: signed byte Ignore the regular length (delta-time) of subsequent notes and set to the fixed length. The length parameter is a value based on the current length. (default is 0)
0xDD Channel Pitch LFO Depth Slide 3 length: byte, depth: byte
0xDE Channel Volume LFO Depth Slide 3 length: byte, depth: byte
0xDF Channel Pan LFO Depth Slide 3 length: byte, depth: byte
0xE0-0xE7 Unimplemented 1 Code-referenced to 0xA0. Should not be used.
0xE8 Tempo 3 tempo: uint16 bpm = tempo / 214.998204 (approximate)

Note that this coefficient is different from other games with PlayStation AKAO.

0xE9 Tempo Slide 4 length: byte, tempo: uint16
0xEA Reverb Depth 3 depth: uint16
0xEB Reverb Depth Slide 4 length: byte, depth: uint16
0xEC Turn On Drum Mode 3 drum_map_offset: signed int16
0xED Turn Off Drum Mode 1
0xEE Unconditional Jump 3 destination_offset: signed int16 Can be used to make an infinite loop.
0xEF CPU-Conditional Jump 4 condition: byte, destination_offset: signed int16 Jump if the condition variable matches condition. The value of the condition variable can be set from the game program.
0xF0 Jump on the Nth Repeat 4 times: byte, destination_offset: signed int16
0xF1 Break the Loop on the Nth Repeat 4 times: byte, destination_offset: signed int16 Unlike 0xF0, this instruction will end the current loop by decrementing the nesting level of the loop.
0xF2 Load Instrument (No Attack Sample) 2 instrument: byte The sample before the loop point is replaced by a short, silence sample.
0xF3 Use No Delay for Channel Pitch/Volume LFO 1 Specific to FF7. This instruction changes the interpretation of the 0xB4 and 0xB8 parameters. There is no actual use in music.
0xF4 Turn On Overlay Voice 3 instrument: byte, instrument2: byte Play the same melody by different instruments on two voice channels. A free voice channel is required to work. Note that the two channels share the playback rate, and the pitch is not calculated for each instruments.

Used in the song "Anxious Heart".

0xF5 Turn Off Overlay Voice 1
0xF6 Volume Balance of Overlay Voice 2 balance: byte When the balance is 0, the volume of the primary voice will be 100% (127/128) of original and that of the secondary voice will be 0%. 127 is the opposite.
0xF7 Volume Balance Slide of Overlay Voice 3 length: byte, balance: byte
0xF8 Turn On Alternate Voice 2 release_rate: byte This instruction allows subsequent notes to be played on two alternating channels. At the same time, the ADSR release rate will be set to the specified value. A free voice channel is required to work.

Check "Opening - Bombing Mission", "Tifa's Theme" and "Fortress of the Condor" for actual usage.

0xF9 Turn Off Alternate Voice 1
0xFA-0xFC Unimplemented 1 Code-referenced to 0xA0. Should not be used.
0xFD Time Signature 3 ticks_per_beat: byte, beats_per_measure: byte Note that two parameters can be 0. This pattern is used for initialization.
0xFE Measure Number 2 measure: byte
0xFF Unimplemented 1 Code-referenced to 0xA0. Should not be used.