SABS & SABL Files
SAB(Stream) and SAB(Load). The B is most likely "bank" as the game code refers to a "sound bank" when loading SABL/SABS files.
- SABS = Snd Alias Bank Stream
- SABL = Snd Alias Bank Load
Structure
Thanks to Jakes625, Red-EyeX32, master131, and kokole.
struct hash_entry_t
{
u8 md5[0x10]; // md5 of the audio file
}; // 0x10
SampleRateTable = { 8000, 12000, 16000, 24000, 32000, 44100, 48000, 96000, 192000 };
struct audio_entry_t
{
u32 name; // this is a hash of the name. Name Found in snd_alias_t asset in ff
u32 size;
u32 offset;
u32 sampleCount;
u8 sampleRateIndex; // see SampleRateTable
u8 channelCount; // enum 0x1 = mono 0x2 = dual
u8 looped;
u8 format; // enum 0x0 = pcm, 0x4 = xma, 0x5 = mp3, 0x8 = flac
}; // 0x14
struct header_t
{
u32 magic; // "2UX#"
u32 version; // 0x0E
u32 sizeOfAudioEntry; // 0x14
u32 sizeOfHashEntry; // 0x10
u32 sizeOfStringEntry; // 0x40
u32 entryCount; // number of sound entries NOT NAME ENTRIES
u64 unk1; // always 0x8 for some reason, might be the size of the next 3 fields
u64 fileLength; // Size of the whole file
u64 entries; // &audio_entry_t[0]
u64 hashes; // &hash_entry_t[0]
}; // 0x38
struct sabs_file
{
header_t header;
u8 asset_link_id[0x10]; // 16 bytes which are associated between sabs + 0x38 and soundasset + 0x830 (can be > 0x830)
u8 nameEntries[30][64];
u8 padding[0x38];
}; // 0x800To calculate the duration of an audio entry:
durationInMilliseconds = 1000 * sampleCount / sampleRate;
Note that "sampleRate" is the actual sample rate value from the table and not the index/flag value from the structure.