Anonymous

Changes

From Final Fantasy Inside

FF9/Sound/AKAO sequence

1,862 bytes added, 12:38, 30 July 2020
Fix AkaoChannelInfo mask bits
AkaoSeqHeader *header;
int num_channels = 0;
while (int bit = 0; header->bit < 32; bit++) if (info.mask & (1 << bit)) != 0; bit++) num_channels++;
There is <channels count> offsets to channel opcode data counting from current offset. Each offsets is a relative offset based on the address the offset itself.
=== Channel Commands [AKAO Opcodes] ===
For every channels in an AKAO sequence, there is a set of commands to perform. This is similar to Field opcodes. Here I will call this sound commands "opcodes". Every opcode has its own number of arguments . === Custom Instrument Map Table === When a song uses custom instruments with [[FF9/Sound/Opcodes/0xfe14|opcode 0xFE 0x14]], a custom instrument map table will be placed after the end of AKAO opcode sequence. This table consists of a collection of zones representing performance settings for a particular key range. A zone is an 8-byte item, and an instrument can have one or more regions.  struct AkaoInstrumentZoneAttr { uint8_t instrument; // corresponding to opcode 0xA1 uint8_t low_key; // lowest key (in note number) uint8_t high_key; // highest key (in note number) uint8_t ar; // ADSR: attack rate (0-127) uint8_t sr; // ADSR: sustain rate (0-127) uint8_t s_mode; // ADSR: sustain mode (1: linear increase, 3: linear decrease, 5: exponential increase, 7: exponential decrease) uint8_t rr; // ADSR: release rate (0-31) uint8_t volume; // adjust the note volume to n/128 of the original volume (0 will keep the original volume) } - Zones must be ordered from nolow key to high key-argumentsThe final zone of the instrument must be a terminator filled with 0s (more precisely, to 3 argumentsa zone with ADSR sustain mode of 0 is considered a terminator).
=== Drum Instrument Map Table ===
uint8_t sr; // ADSR: sustain rate (0-127)
uint8_t s_mode; // ADSR: sustain mode (1: linear increase, 3: linear decrease, 5: exponential increase, 7: exponential decrease)
uint8_t rr; // ADSR: release rate (0-12731)
uint8_t volume; // adjust the percussion volume to n/128 of the original volume (0 will keep the original volume)
uint8_t pan : 7; // corresponding to opcode 0xAA
|1
|
|The opcode indicates the note key and length. The note will be keyed off 2 ticks before the next note.
|-
|0x9A-0x9F
|-
|[[FF9/Sound/Opcodes/0xb4b5|0xB4]]
|Vibrato (Channel Pitch LFO (Vibrato)
|4
|delay: byte, rate: byte, type: byte (0-15)
|-
|[[FF9/Sound/Opcodes/0xb4b5|0xB5]]
|Channel Pitch LFO Vibrato Depth
|2
|depth: byte
|-
|[[FF9/Sound/Opcodes/0xb4b5|0xB6]]
|Turn Off Channel Pitch LFOVibrato
|1
|
|-
|[[FF9/Sound/Opcodes/0xb8b9|0xB8]]
|Tremolo (Channel Volume LFO (Tremolo)
|4
|delay: byte, rate: byte, type: byte (0-15)
|-
|[[FF9/Sound/Opcodes/0xb8b9|0xB9]]
|Channel Volume LFO Tremolo Depth
|2
|depth: byte
|-
|[[FF9/Sound/Opcodes/0xb8b9|0xBA]]
|Turn Off Channel Volume LFOTremolo
|1
|
|-
|[[FF9/Sound/Opcodes/0xdd|0xDD]]
|Channel Pitch LFO Vibrato Depth Slide
|3
|length: byte, depth: byte
|-
|[[FF9/Sound/Opcodes/0xde|0xDE]]
|Channel Volume LFO Tremolo Depth Slide
|3
|length: byte, depth: byte
|-
|[[FF9/Sound/Opcodes/0xe4|0xE4]]
|Channel Pitch LFO Vibrato Rate Slide
|3
|length: byte, rate: byte
|-
|[[FF9/Sound/Opcodes/0xe5|0xE5]]
|Channel Volume LFO Tremolo Rate Slide
|3
|length: byte, rate: byte
|bpm = tempo / 218.453333 (approximate)
More strictly, <code>bpm = 60.0 / (48 * (65536.0 / tempo) * (0x43D1 / (33868800.0 / 8)))</code>
 
Note that this coefficient is different from other games with PlayStation AKAO.
|-
|[[FF9/Sound/Opcodes/0xfe00|0xFE 0x01]]
When <code>times</code> is 0, it will be translated to 256 times.
|-
|[[FF9FF7/PSX/Sound/Opcodes/0xa1|0xFE 0x0A]]|Load Instrument (With Some Unknown EffectNo Attack Sample)
|3
|instrument: byte
|Unlike 0xA1, the sample before the loop point is replaced by a short, silence sample.
|-
|[[FF9/Sound/Opcodes/0xfe0b|0xFE 0x0B]]
|-
|[[FF9/Sound/Opcodes/0xfe0e|0xFE 0x0E]]
|Subroutine JumpPattern
|4
|destination_offset: signed int16
|The subroutine Remember the return address and jump to the specified location. It cannot be nested. It will overwrite the return address.
|-
|[[FF9/Sound/Opcodes/0xfe0f|0xFE 0x0F]]
|Return from SubroutineEnd Pattern
|2
|
|Return from opcode 0xFE 0x0E.
|-
|[[FF9/Sound/Opcodes/0xfe10|0xFE 0x10]]
|UnknownAllocate Reserved Voices
|3
|valuecount: byte|Reserve the specified <code>count</code> of hardware voices. Reserved voices will not be used unless explicitly specified in opcode 0xFE 0x1D.
|-
|[[FF9/Sound/Opcodes/0xfe10|0xFE 0x11]]
|UnknownFree Reserved Voices
|2
|
|Clears Set the effect count of opcode 0xFE 0x10reserved voices to 0.
|-
|[[FF9/Sound/Opcodes/0xa3|0xFE 0x12]]
|Code-referenced to 0xA0. Should not be used.
|-
|[[FF9/Sound/Opcodes/0xfe190xa9|0xFE 0x19]]|UnknownChannel Volume Slide Per Note On|?4|?length: byte, volume: byte (0-127)|Applies volume slide (opcode 0xA9) for each notes. When <code>length</code> is 0, it will be translated to 256 ticks.
|-
|[[FF9/Sound/Opcodes/0xfe1a|0xFE 0x1A]]
|Unknown
|?|?2
|
|Turn something on.
|-
|[[FF9/Sound/Opcodes/0xfe1b|0xFE 0x1B]]
|Unknown
|?|?2
|
|Clears the effect of opcode 0xFE 0x1A.
|-
|[[FF9/Sound/Opcodes/0xfe1c|0xFE 0x1C]]
|Unknown
|?3|?value: byte|Obsoleted opcode? As far as I learned from the assembly code, it probably does nothing.
|-
|[[FF9/Sound/Opcodes/0xfe1d|0xFE 0x1D]]
|UnknownUse Reserved Voices|?|?2
|
|Allow using the reserved voices to play the sound of the current track. If they are all used, the remaining voices will instead be used normally.
 
Use opcode [[FF9/Sound/Opcodes/0xfe10|0xFE 0x10]] to allocate reserved voices.
|-
|[[FF9/Sound/Opcodes/0xfe1e|0xFE 0x1E]]
|UnknownUse No Reserved Voices|?|?2
|
|Disable the effect of opcode 0xFE 0x1D.
|-
|[[FF9/Sound/Opcodes/0xa0|0xFE 0x1F]]
112
edits