EvilEngine/Sound Format: Difference between revisions

no edit summary
mNo edit summary
No edit summary
 
(3 intermediate revisions by 3 users not shown)
Line 1:
This page contains information on how sounds and music are stored in the[[EvilEngine]] games.
 
SoundsIn [[Scooby-Doo! Night of 100 Frights]] and [[SpongeBob SquarePants: Battle for Bikini Bottom]] sounds are usually contained in '''SND''' and '''SNDS''' [[assetEvilEngine/Assets|assets]]s, with the '''SNDI''' asset containing information about them. Each [[EvilEngine/HIP_(File_Format)|HOP]] file (sometimes the [[EvilEngine/HIP_(File_Format)|HIP]]) contains multiple SND and SNDS assets and one single SNDI asset. There doesn't seem to be an internal difference between SND and SNDS other than being stored as different assets; sound effects are usually in SND and voice lines and music (stored in mnu5.HIP in BFBB) are usually in SNDS.
 
In [[The SpongeBob SquarePants Movie]], [[The Incredibles]] and [[The Incredibles: Rise of the Underminer]], '''SND''' and '''SNDS''' assets are empty, and instead, all of the sounds are contained entirely in the '''SNDI''' asset.
 
Xbox and the [[FMOD]] GameCube games are the only platform which support '''Stereo'''. PS2 and GameCube (Scooby/BFBB) only support '''Mono''' due to its sound format (VAG and DSP).
 
==SND/SNDS Format==
Line 9 ⟶ 13:
|subtitle=Sound/Streaming Sound
|type=[[Binary]]
|games=Scooby BFBB TSSM Incredibles ROTU RatProto}}
|games=Night of 100 Frights<br>Battle for Bikini Bottom<br>The SpongeBob SquarePants Movie<br>The Incredibles<br>Rise of the Underminer}}
 
===GameCube (Night of 100 Frights/Battle for Bikini Bottom)===
InThe Scooby-Doo:audio Nightformat ofon 100the FrightsGameCube andversion Spongebobof Squarepants: Battle For Bikini Bottom, SNDScooby-Doo and SNDSBFBB areis a GameCubeNintendo DSP-ADPCM audio file stripped of its 0x60 bytebytes *.dsp header: all of a level's sound headers are kept separate in the single SNDI asset.
 
===GameCube (The SpongeBob SquarePants Movie - Ratatouille Prototype)===
In The Spongebob Squarepants Movie Game, The Incredibles and Rise of the Underminer, the SND and SNDS assets are empty, and instead, all of the sounds are contained entirely in the SNDI asset.
Those games on GameCube are the only EvilEngine games which utilize the [[FMOD]] audio engine. This allows stereo support although it still uses the same Nintendo non-stereo codec like Scooby-Doo and BFBB by interleaving two mono tracks. SND/SNDS assets are empty; all sounds are contained entirely in SNDI assets within "FSB3" (FMOD Sample Bank) files.
 
===Xbox===
The audio format on the Xbox version of all 5 games is either raw IMAXbox ADPCM, or raw 16-bit Linear PCM stripped of its *.wav header: all of a level's sound headers are kept separate in the single SNDI asset.
 
===PlaystationPlayStation 2===
The audio format on the PS2 version of all 5 games is a PS2 VAG sound file stripped of its 0x30 bytebytes header (except in Scooby-Doo): all of a level's sound headers are kept separate in the single SNDI asset. The first 0x10 bytes are usually null to initialize the SPU.
 
==SNDICSSS Format==
{{AssetInfobox
|title=CSSS
|subtitle=Cutscene Streaming Sound
|type=[[Binary]]
|games=TSSM Incredibles ROTU}}
 
Same as SND/SNDS in Movie and The Incredibles: CSSS assets are empty and only used to "link" the sound header in SNDI with the sound data stored in [[EvilEngine/CSN|cutscenes]].
 
 
 
 
==SNDI Format==
{{AssetInfobox
|title=SNDI
|subtitle=Sound Info
|type=[[Binary]]
|games=Scooby BFBB TSSM Incredibles ROTU RatProto}}
|games=Night of 100 Frights<br>Battle for Bikini Bottom<br>The SpongeBob SquarePants Movie<br>The Incredibles<br>Rise of the Underminer}}
 
===GameCube (Night of 100 Frights/Battle Forfor Bikini Bottom)===
The SNDI has a 0xC or 0x10 bytebytes big-endian header:
 
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || intu32 || amount of SND'''num_effects''' || Amount of headers for SND assets.
|-
| 0x04 || byte[4]u32 || null- || Padding "0xCDCDCDCD"
|-
| 0x08 || intu32 || amount of SNDS'''num_streams''' || Amount of headers for SNDS assets.
|-
| 0x0C || intu32 || amount of cutscene SNDSnum_cutscenes || Amount of headers for SNDS assets used in cutscenescutscene assets. '''(BFBB only.)'''
|}
 
After that, there are three consecutive arrays of SNDI entries: one for the SND, one for the SNDS and one for the cutscene SNDSheaders. Each SNDI entry is 0x64 bytes long, big-endian and follows this structure:
 
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || byte[0x60]u32 || Sound Header'''num_samples''' || HeaderAmount of GameCube DSP soundraw file.samples
|-
| 0x04 || u32 || '''num_adpcm_nibbles''' || Amount of ADPCM nibbles (including frame headers)
| 0x60 || [[AssetID]] || Sound Asset ID || Asset ID of corresponding SND or SNDS asset.
|}
 
===GameCube (Movie Game/Incredibles/Rise of the Underminer)===
In those games, the SNDI contains not only the sound headers but also the entirety of the sound files themselves.
 
====SNDI Header====
The SNDI itself has a 0x20 byte header:
 
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x000x08 || [[AssetID]]u32 || this'''sample_rate''' || AssetSample IDrate ofin this assetHz
|-
| 0x0C || u16 || '''loop_flag''' || 0 = Not Looped, 1 = Looped
| 0x04 || int || footerOffset || Offset relative to end of this header to the Footer section. Subtract 0x20 from this to get the absolute offset of the Footer.
|-
| 0x080x0E || byte[0x10]u16 || ?'''format''' || UsuallyAlways all 0s0
|-
| 0x180x10 || shortu32 || soundCount'''sa''' || TotalLoop amountstart of soundsoffset, in SNDInibbles
|-
| 0x1A0x14 || shortu32 || firstFSB3soundCount'''ea''' || AmountLoop ofend soundsoffset, in the first FSB3 of the SNDInibbles
|-
| 0x18 || u32 || '''ca''' || Initial offset value, always 2
| 0x1C || short || otherFSB3soundCount || Amount of sounds combining all FSB3s which are not the first of the SNDI
|-
| 0x1E0x1C || bytes16[16] || FSB3count'''coef''' || AmountDecoder of FSB3 filescoefficients
|-
| 0x3C || u16 || '''gain''' || Gain factor. Always 0
| 0x1F || byte || cutsceneSoundCount || Amount of cutscene sounds in file. '''The values related to cutscene files are not addressed in the description below yet.'''
|}
 
All sounds are contained inside FSB3 files. Each FSB3 can contain one or multiple sounds; in all files analyzed so far, most of the sounds are contained in the first FSB3 file, with each subsequent file containing only one. This is the structure of a FSB3 file:
 
====FSB3 Header====
This is the header of a FSB3 file. There is one per FSB3 in the SNDI.
 
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x3E || u16 || '''pred_scale''' || Predictor and scale. This will be initialized to the predictor and scale value of the sample’s first frame.
| 0x00 || char[4] || magic || "FSB3" in ASCII
|-
| 0x40 || u16 || '''yn1''' || rowspan="2" | History data; used to maintain decoder state during sample playback
| 0x04 || int || numSamples || Amount of samples in the FSB3. Each sample is a sound. However, unlike most FSB3 files in other games, here only one sample header is used for all sounds, which might be confusing, and a different, custom header is used for individual sounds.
|-
| 0x42 || u16 || '''yn2'''
| 0x08 || int || totalHeadersSize || Total size of the single sample header + each individual sound header. This is always equal to (72 + 0x36 * numSamples).
|-
| 0x44 || u16 || '''loop_pred_scale''' || Predictor/scale for the loop point frame. If the sample does not loop, this value is zero
| 0x0C || int || totalDataSize || Total size of all sound data combining all sound entries.
|-
| 0x46 || u16 || '''loop_yn1''' || rowspan="2" | History data for the loop point. If the sample does not loop, this value is zero.
| 0x10 || int || version || Always 196609.
|-
| 0x140x48 || intu16 || mode || Always 2.'''loop_yn2'''
|}-
| 0x4A || u8[22] || '''pad''' || Unknown values
|-
! colspan="4" |
|-
| 0x60 || [[AssetID]] || '''uAssetID''' || Asset ID of corresponding SND/SNDS asset
|}
 
===GameCube (The SpongeBob SquarePants Movie - Ratatouille Prototype)===
After the FSB3 header, there is one sample header.
In those games, the SNDI contains not only the sound headers but also the entirety of the sound data themselves.
 
====SampleSNDI Header====
The SNDI itself has a 0x20 byte big-endian header:
This is the header of a FSB3 sample. There is one per FSB3 in the SNDI, immediately after the FSB3 header above.
 
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || short[[AssetID]] || size'''uSoundInfoID''' || AlwaysAsset 126ID of this asset
|-
| 0x04 || u32 || '''uSumFSBSize / nOffsetFinalFSBEnd''' || Total size of all FSB3 files, also offset to the Footer section (relative to end of this header, add 0x20 to get the absolute offset).
| 0x02 || char[30] || soundName || Sample name in ASCII. Since each sample actually refers to multiple sounds and this is usually different from the actual sound names, this is likely leftover data and unused.
|-
| 0x08 || s32 || '''pFMusicMod''' || ''null''
| 0x20 || int || lengthSamples || Misleading name; this is actually the amount of samples on the uncompressed data for the first sound only. The first sound in the list will have 0 as its own lengthSamples.
|-
| 0x0C || s32 || '''pFSBFileArray''' || ''null''
| 0x24 || int || lengthCompressedBytes || Misleading name; this is actually the length of the compressed sound data in bytes for the first sound only. The first sound in the list will have 0 as its own lengthCompressedBytes.
|-
| 0x10 || s32 || '''pWavInfoArray''' || ''null''
| 0x28 || int || loopStart || Start of loop in sample. Only refers to first sound in list. This is probably unused as each sound would require its own loopStart.
|-
| 0x14 || s32 || '''pCutsceneAudioHeaders''' || ''null''
| 0x2C || int || loopEnd || End of loop in sample. Only refers to first sound in list. This is probably unused as each sound would require its own loopEnd.
|-
| 0x300x18 || intu16 || sampleHeaderMode'''nWavFiles''' || AlwaysTotal 33558561amount of sounds
|-
| 0x1A || u16 || '''nSounds''' || Amount of sounds in the first FSB3 of the SNDI
| 0x34 || int || deffreq || Always 32000
|-
| 0x1C || u16 || '''nStreams''' || Amount of sounds combining all FSB3's which are not the first of the SNDI
| 0x38 || short || defvol || Always 255
|-
| 0x3A0x1E || shortu8 || defpan'''nFSBFiles''' || AlwaysAmount 128of FSB3 files
|-
| 0x1F || u8 || '''nCutsceneAudioHeaders''' || Amount of cutscene headers
| 0x3C || short || defpri || Always 255
|-
| 0x3E || short || numchannels || Always 1
|-
| 0x40 || float || minDistance || Always 1.0
|-
| 0x44 || float || maxDistance || Always 1000000.0
|}
 
====SoundFSB3 HeaderFormat====
All sounds are contained inside FSB3 files. The first FSB3 is loaded into RAM, thus it has a ~8MB size limit, but can contain multiple sounds. Every subsequent FSB3 is streamed, thus it has no size limit but can only contain 1 sound. Read [[FMOD]] for more information about FMOD and the FSB3 format. <u>'''Note:'''</u> SNDI header and the Footer section are stored in big-endian while FSB's are little-endian.
After the sample header, there are sound headers. This header repeats '''numSamples''' times (one for each sound). This header is 0x36 bytes long, an unusual length since it's not aligned to 4 bytes.
 
====Footer Section====
This is a section which occurs at the end of the SNDI. The offset to this is set in the SNDI header. This is its structure:
 
=====FSB3 Offsets=====
{| class="wikitable"
! Offset !! Size !! Description
|-
| 0x00 || 4[[#SNDI Header|'''[nFSBFiles]''']] || '''Array''' of ints. The amount of ints is the same amount of FSB3 files, as set in the SNDI header. Each int is an offset to the start of each FSB3 file, relative to the end of the SNDI header. Add 0x20 to each value to get the absolute offset.
|}
 
After this, we have [[#SNDI Header|'''nWavFiles''']] times the following structure, which refers to each sound in the SNDI:
=====gcWavInfo=====
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || [[AssetID]] || '''uAssetID''' || Asset ID of sound.
| 0x00 || int || lengthSamples || Length of uncompressed samples in sound. This is 0 for the first sound in the list, as the value is set in the sample header above, but for each subsequent sound it's the actual value.
|-
| 0x04 || u8 || '''uFlags''' || Loop and format flag.
* 0 = RAM sound (first FSB)
* 1 = Looped
* 2 = Streaming sound (subsequent FSB)
|-
| 0x05 || u8 || '''uAudioSampleIndex''' || Zero-based index of sound inside its FSB3 file
| 0x04 || int || lengthCompressedBytes || Length of bytes in compressed data. This is 0 for the first sound in the list, as the value is set in the sample header above, but for each subsequent sound it's the actual value.
|-
| 0x06 || u8 || '''uFSBIndex''' || Zero-based index of the FSB3 file containing this sound (index to the FSB3 offsets array)
| 0x08 || uint[8] || unknown || 8 ints with unknown function.
|-
| 0x07 || u8 || '''uSoundInfoIndex''' ||
| 0x28 || byte[14] || unknown || 14 bytes with unknown function.
|}
 
=====Cutscene Header=====
Adding the lengthCompressedBytes in each Sound Header entry will result in the totalDataSize value of the FSB3 header.
At the end of the SNDI are the cutscene header. They are a 0x60 bytes dsp header + asset id of corresponding CSSS asset (same format as header in Scooby/BFBB).
 
====Sound Data====
After '''numSamples''' occurrences of the Sound Header, we have the compressed sound data. The total length of this is set in the FSB3 Header (totalDataSize), with each sound in order.
 
After the sound data for the entire FSB3 file ends, we usually have the next FSB3 file, or if it's the last one, then we've reached the Footer section.
 
====Footer Section====
This is a section which occurs at the end of the file. The offset to this is set in the SNDI header. This is its structure:
 
===Xbox===
Stored in little-endian. The SNDI has a 0xC byte header:
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || u32 || '''num_effects''' || Amount of headers for SND assets
| 0x00 || int[FSB3count] || FSB3offsets || An array of ints. The amount of ints is the same amount of FSB3 files, as set in the SNDI header. Each int is an offset to the start of each FSB3 file, relative to the end of the header. Subtract 0x20 from each value to get the absolute offset of the file.
|-
| 0x04 || u32 || '''num_streams''' || Amount of headers for SNDS assets
|-
| 0x08 || u32 || num_cutscenes || Amount of headers used in cutscenes assets
|}
 
After that, there are three consecutive arrays of entries: one for the SND, one for the SNDS and one for cutscene headers. Each entry is 0x2C bytes long and follows this structure:
After this, we have '''soundCount''' times the following structure, which refers to each sound in the SNDI:
 
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || [[Asset ID]]u16 || [[SND]]/[[SNDS]]'''wFormatTag''' || Asset1 if PCM, 0x69 (105) IDif ofXbox sound.ADPCM
|-
| 0x02 || u16 || '''nChannels''' || Number of audio Channels. Always 1 (Mono), but support for 2 (Stereo)
| 0x04 || byte || unknown ||
|-
| 0x04 || u32 || '''nSamplesPerSec''' || Sampling rate in Hz
| 0x05 || byte || index || Zero-based index of sound inside its FSB3 file.
|-
| 0x08 || u32 || '''nAvgBytesPerSec''' || Used as an estimate for bytes per second. Can be ignored
| 0x06 || byte || fileIndex || Zero-based index of the FSB3 file containing this sound (index to the FSB3offsets array).
|-
| 0x0C || u16 || '''nBlockAlign''' || Block size in bytes. 2 if PCM, 36 (0x24) if Xbox ADPCM
| 0x07 || byte || unknown ||
|-
| 0x0E || u16 || '''wBitsPerSample''' || Number of bits used per sample. 16 (0x10) if PCM, 4 if Xbox ADPCM
|-
| 0x10 || u16 || '''cbSize''' || Amount of extra bytes. Always 0 if PCM, 2 if Xbox ADPCM (NibblesPerBlock)
|-
| 0x12 || u16 || NibblesPerBlock || ADPCM nibbles per block. 64 (0x40) if Xbox ADPCM, 0 if PCM
|-
| 0x14 || u32 || Datasize || Size of corresponding sound data.
|-
| 0x18 || [[AssetID]] || Sound Asset ID || Asset ID of corresponding SND or SNDS asset
|-
| 0x1C || u32 || flag/loop || 0 = Not Looped, 1 = Looped, 2 = Unknown
|-
| 0x20 || u8[12] || Padding || ''null''
|}
More information about [https://xboxdevwiki.net/Xbox_ADPCM Xbox ADPCM].
 
===XboxPlayStation 2===
The SNDI has a 0x8 or 0xC bytebytes little-endian header:
 
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || int[[AssetID]] || amount of SNDassetID || AmountAssetID of headersSNDI '''(Only present in forIncredibles SNDand assets.ROTU)'''
|-
| 0x04/0x00 || intuint || amount of SNDS'''num_effects''' || Amount of headers for SNDSSND assets.
|-
| 0x08/0x04 || uint || '''num_streams''' || Amount of headers for SNDS assets
|-
| 0x08 || int || amount of cutscene SNDS || Amount of headers for SNDS assets used in cutscenes.
|}
 
After that, there are threetwo consecutive arrays of SNDI entries: one for the SND, one for the SNDS and one for the cutscene SNDS. Each SNDI entry is 0x2C0x30 bytes long and followsis thisa structure:Sony VAG header.
====Scooby-Doo: Night of 100 Frights====
 
Stored in big-endian, except '''reserved''' and probably also '''reserved2''' which are in little-endian.
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || shortchar[4] || fmtId'''id''' || 0x0069 if Xbox ADPCM, 0x0001 if Linear PCM."VAGp"
|-
| 0x020x04 || shortu32 || fmtChannels'''version''' || NumberAlways of3, audio4 Channels.or 32
|-
| 0x08 || u32 || '''reserved''' || Asset ID of corresponding SND/SNDS
| 0x04 || int || fmtSampleRate || Sampling rate. Xbox ADPCM data plays at this rate multipled by 65/64.
|-
| 0x0C || u32 || '''data_size''' || Size of corresponding SND/SNDS asset
| 0x08 || int || fmtBytesPerSecond || Used as an estimate for bytes per second. Can be ignored.
|-
| 0x0C0x10 || shortu32 || fmtBlockAlignment'''frequency''' || BlockSampling Size.rate 0x0024in for Xbox ADPCM data.Hz
|-
| 0x14 || u32[3] || '''reserved2''' ||
| 0x0E || short || fmtBitsPerSample || Number of bits used per sample. 0x0004 if Xbox ADPCM, 0x0000 if Linear PCM.
* u32[1]: ''null''
* u32[2]: ''null'' or 0xE4AC0000
* u32[3]: ''null''
|-
| 0x20 || char[16] || '''name''' || Old filename, can be ignored
| 0x10 || short || fmtExtBytes || Will always be 0x0002 if Xbox ADPCM. 0x0000 if Linear PCM.
|-
| 0x12 || short || fmtExtData || ADPCM nibbles per block. Normally 0x0040 if Xbox APCM. 0x0000 if Linear PCM.
|-
| 0x14 || int || dataSize || Size of the corresponding SND or SNDS asset.
|-
| 0x18 || [[AssetID]] || Sound Asset ID || Asset ID of corresponding SND or SNDS asset.
|-
| 0x1C || byte[16] || Padding ||
|}
There are two 0x30 bytes "RIFF" header with a different format, one in I001.HIP and in S005.HIP. However, they don't seem to work ingame.
 
====Battle for Bikini Bottom - Rise of the Underminer====
 
Stored in little-endian.
===Playstation 2===
The SNDI has a 0x8 byte header:
 
{| class="wikitable"
! Offset !! Type !! Variable !! Description
|-
| 0x00 || intchar[4] || amount of SND'''id''' || Amount of headers for SND assets."VAGp"
|-
| 0x080x04 || intu32 || amount of SNDS'''version''' || Amount4 or 32 in BFBB, always of32 headersin forevery SNDSother assets.game
|-
| 0x08 || u32 || '''assetID''' || Asset ID of corresponding SND/SNDS
|-
| 0x0C || u32 || '''data_size''' || Size of corresponding SND/SNDS asset
|-
| 0x10 || u32 || '''frequency''' || Sampling rate in Hz
|-
| 0x14 || u32 || '''streamInterleaveSize''' ||
|-
| 0x18 || u32 || '''streamInterleaveCount''' ||
|-
| 0x1C || u32 || '''reserved2''' ||
|-
| 0x20 || char[16] || '''name''' || Old filename, can be ignored
|}
 
After that, there are two consecutive arrays of SNDI entries: one for the SND and one for the SNDS. Each SNDI entry is 0x30 bytes long and is a [http://www.psdevwiki.com/ps3/Multimedia_Formats_and_Tools#VAG VAG header]. The reserved space at 0x8 in the header contains the sound's [[Asset ID]].
 
{{Assets}}
 
[[Category:Asset]] [[Category:File Format]] [[Category:StubEvilEngine]]
2,079

edits