Difference between revisions of "SFX (SA)"
m (Added loop info and broke up package section) |
m (Changed 200 sound limit to 400. See Talk section for more info.) |
||
Line 1: | Line 1: | ||
{{Research}} | {{Research}} | ||
− | San Andreas uses a hierarchical system for managing sound effects, as opposed to the flat arrays of effects used in [[SFX|previous titles]]. Instead of individual sounds, SA has ''packages'' which group sounds based on where they are used in the game, and these sounds are further separated into ''banks'' based on what they are used for, with each bank containing up to | + | San Andreas uses a hierarchical system for managing sound effects, as opposed to the flat arrays of effects used in [[SFX|previous titles]]. Instead of individual sounds, SA has ''packages'' which group sounds based on where they are used in the game, and these sounds are further separated into ''banks'' based on what they are used for, with each bank containing up to 400 sounds. |
The bank/package system allows the game to only load the sound(s) needed at the moment – in some instances, the game only loads a single sound from a bank (though it is more common for entire banks to be loaded at a time). | The bank/package system allows the game to only load the sound(s) needed at the moment – in some instances, the game only loads a single sound from a bank (though it is more common for entire banks to be loaded at a time). | ||
Line 82: | Line 82: | ||
// 4084 bytes (including SoundMeta array) | // 4084 bytes (including SoundMeta array) | ||
type BankHeader struct { | type BankHeader struct { | ||
− | // The number of sounds in the bank. Must be <= | + | // The number of sounds in the bank. Must be <= 400. |
NumSounds uint16 | NumSounds uint16 | ||
Padding uint16 | Padding uint16 | ||
Line 90: | Line 90: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | The <code>BankHeader</code> structure's location is specified by the <code>BankHeaderOffset</code> value of the bank's <code>BankMeta</code> structure. | + | The <code>BankHeader</code> structure's location is specified by the <code>BankHeaderOffset</code> value of the bank's <code>BankMeta</code> structure. The maximum number of sounds in each bank is 400. |
− | |||
The audio sample buffers are all in ''signed 16-bit mono PCM'' format. The offset of a sound's PCM buffer can be calculated with the following function: | The audio sample buffers are all in ''signed 16-bit mono PCM'' format. The offset of a sound's PCM buffer can be calculated with the following function: |
Revision as of 13:05, 29 August 2020
San Andreas uses a hierarchical system for managing sound effects, as opposed to the flat arrays of effects used in previous titles. Instead of individual sounds, SA has packages which group sounds based on where they are used in the game, and these sounds are further separated into banks based on what they are used for, with each bank containing up to 400 sounds.
The bank/package system allows the game to only load the sound(s) needed at the moment – in some instances, the game only loads a single sound from a bank (though it is more common for entire banks to be loaded at a time).
Contents
File Formats
The SFX config formats are pure dumps of game structures, so contain a lot of irrelevant data. They are stored in the audio/CONFIG
directory and have the extension .dat
.
PakFiles.dat
PakFiles.dat
is a list of package names. Each name takes up 52 bytes.
// package count = file size / 52
type PackageList struct {
Packages []string
}
The package names are the same as their file names inside the audio/SFX
directory. In other files and also in the game, each package is referred to by its 0-based index in the package list (0, 1, 2, etc.).
BankLkup.dat
BankLkup.dat
contains an array of metadata structures for all banks in all packages.
// 12 bytes
type BankMeta struct {
// Index of package in PakFiles.dat
PackageIndex uint8
Padding [3]uint8
// Bank header location in package file.
BankHeaderOffset uint32
// Total size of sounds in bank.
BankSize uint32
}
Note that the game uses hardcoded indices to reference specific banks, so changes in order can lead to problems.
Packages
Package files contain banks, which contain sound data (including the raw PCM data). Packages are in the audio/SFX
directory and have no file extension.
An unmodified game has the following packages:
FEET
GENRL
PAIN_A
SCRIPT
SPC_EA
SPC_FA
SPC_GA
SPC_NA
SPC_PA
Each bank stored in a package file has two parts: the header and the PCM buffers. The PCM buffers follow the header.
Sound structure
Most of the bank header is made up of sound metadata, which has the following structure:
type SoundMeta struct {
// Offset of the PCM buffer from the end of the bank header.
BufferOffset uint32
// Where the start of the loop is (in samples).
LoopOffset int32
// Sample rate (measured in Hz).
SampleRate uint16
// Audio headroom. Defines how much louder than average
// this sound effect is expected to go.
Headroom int16
}
The Headroom
value tells the game how loud the sound will be. This allows the game to adjust what volume to play the sound at in order to prevent the audio clipping. A value of 0 tells the game that the sound is about average volume, with negative values meaning the sound is quieter and positive values meaning it's louder.
LoopOffset
is the position of the start of the looped part of the sound, measured in samples. This value is used to give looped sounds an "introduction" – for example, the sound of a car's engine starting up should have an unlooped ignition sound, but the sound of the engine running after starting should be looped. If LoopOffset
is -1
, the sound does not loop.
Bank structure
The actual bank header structure is as follows:
// 4084 bytes (including SoundMeta array)
type BankHeader struct {
// The number of sounds in the bank. Must be <= 400.
NumSounds uint16
Padding uint16
// Sound metadata.
Sounds [400]SoundMeta
}
The BankHeader
structure's location is specified by the BankHeaderOffset
value of the bank's BankMeta
structure. The maximum number of sounds in each bank is 400.
The audio sample buffers are all in signed 16-bit mono PCM format. The offset of a sound's PCM buffer can be calculated with the following function:
func (sound *SoundMeta) getPCMOffset(bankInfo *BankMeta) uint32 {
// BankHeaderOffset is the offset of the start of the header,
// so the end of the header is 4804 bytes after.
return bankInfo.BankHeaderOffset + 4804 + sound.BufferOffset
}
Since the SoundMeta
structure does not specify the size of the buffer, it must be calculated.
In the following code, bankAudioSize
is BankMeta.BankSize
for the current bank.
func calculateBufferSize(bankHeader *BankHeader, bankAudioSize uint32, soundIndex int) uint32 {
sound := bankHeader.Sounds[soundIndex]
var length uint32
if soundIndex >= int(bankHeader.NumSounds-1) {
// This is the final sound in the bank, so we need to use the size of the bank
// to calculate the length of the sound's buffer.
length = bankAudioSize - sound.BufferOffset
} else {
// length = this sound offset - next sound offset
// This works because the buffers are stored contiguously in the file.
length = bankHeader.Sounds[soundIndex+1].BufferOffset - sound.BufferOffset
}
return length
}
BankSlot.dat
A bank slot is capable of storing some SFX data, this data can be either one entire bank or one single sound from a bank. There is a total of 45 bank slots.
Each bank slot is used by a specific audio class of the game, for example 10 slots are used for vehicle banks, one slot for the bank of explosions, 4 slots for script speeches (which stores single sounds), and so on.
The BankSlot.dat
file's structure is
type SlotFile struct {
// Always 45
NumSlots uint16
Slots [45]Slot
}
where Slot
is
type Slot struct {
// Sum of all buffer sizes before this slot (i.e. the offset).
BufferOffset uint32
// Buffer size for this slot.
BufferSize uint32
// {-1, -1} on disk. Related to feet sounds?
Unknown [2]int32
Ignored [4804]byte
}
Each slot owns a buffer capable of storing some amount of sound data. If this size is lower than the size of the data stored in the slot, sound artifacts will occur in-game.
By default, those buffer sizes are arbitrary values, but it can safely be the size of the highest bank stored in the slot or the size of the highest sound stored in the slot, depending if the slot is used to store a sound or a bank.
Scripting
Sounds can be used in SCM with the following opcodes:
- 018C – Plays a sound on a specific location
- 018E – Stops the played sound
- 03CF – Loads a sound
- 03D0 – Checks if sound has been loaded
- 03D1 – Plays the loaded sound
- 03D2 – Checks if the loaded sound has finished
- 097A – Plays an audio event
- 097B – Plays an audio event in an object
- 09F1 – Plays an audio event in a character
- 09F7 – Plays an audio event in a vehicle
- 09D6 – Makes a character say a scripted speech
Tools
- San Andreas Audio Toolkit – Allows you to modify SFX Packages – It contains a bug related to bank slots causing sound artifacts
- GTAForums: Mod Loader – Allows you to easily change SFX data and fixes the sound artifacts on big sounds.
- GTAForums: Dynamic SFX – Fixes sound artifacts caused by sounds bigger than the original.
See also
- Audio Streams – Used for streaming audio tracks
External links
- GTA:SA SFX Directory
- Default contents of PakFiles.dat
- Default contents of BankLkup.dat
- Default contents of BankSlot.dat