Difference between revisions of "SABS & SABL Files"

From COD Engine Research
Jump to: navigation, search
m
Line 8: Line 8:
 
Thanks to Jakes625, Red-EyeX32, master131, and kokole.
 
Thanks to Jakes625, Red-EyeX32, master131, and kokole.
 
<source lang="cpp">
 
<source lang="cpp">
struct hash_entry_t
+
enum snd_asset_channel_mode
 
{
 
{
u8 md5[0x10];                  // md5 of the audio file
+
SND_ASSET_CHANNEL_MODE_MONO = 0x1,
}; // 0x10
+
SND_ASSET_CHANNEL_MODE_DUAL = 0x2,
 +
// Could be more modes ex: ("Joint Stereo" and "Stereo")
 +
};
  
 
enum snd_asset_format
 
enum snd_asset_format
 
{
 
{
  SND_ASSET_FORMAT_PCMS16 = 0x0,
+
SND_ASSET_FORMAT_PCMS16 = 0x0,
  SND_ASSET_FORMAT_PCMS24 = 0x1,
+
SND_ASSET_FORMAT_PCMS24 = 0x1,
  SND_ASSET_FORMAT_PCMS32 = 0x2,
+
SND_ASSET_FORMAT_PCMS32 = 0x2,
  SND_ASSET_FORMAT_IEEE = 0x3,
+
SND_ASSET_FORMAT_IEEE = 0x3,
  SND_ASSET_FORMAT_XMA4 = 0x4,
+
SND_ASSET_FORMAT_XMA4 = 0x4,
  SND_ASSET_FORMAT_MP3 = 0x5,
+
SND_ASSET_FORMAT_MP3 = 0x5,
  SND_ASSET_FORMAT_MSADPCM = 0x6,
+
SND_ASSET_FORMAT_MSADPCM = 0x6,
  SND_ASSET_FORMAT_WMA = 0x7,
+
SND_ASSET_FORMAT_WMA = 0x7,
  SND_ASSET_FORMAT_FLAC = 0x8,
+
SND_ASSET_FORMAT_FLAC = 0x8,
  SND_ASSET_FORMAT_WIIUADPCM = 0x9,
+
SND_ASSET_FORMAT_WIIUADPCM = 0x9,
  SND_ASSET_FORMAT_MPC = 0xA,
+
SND_ASSET_FORMAT_MPC = 0xA,
  SND_ASSET_FORMAT_COUNT = 0xB,
+
SND_ASSET_FORMAT_COUNT = 0xB,
 
};
 
};
  
frameRateTable = { 8000, 12000, 16000, 24000, 32000, 44100, 48000, 96000, 192000 };
+
 
  
 
struct SndAssetBankEntry
 
struct SndAssetBankEntry
 
{
 
{
unsigned int id; // this is a hash of the name. Name Found in SndAlias asset in ff
+
unsigned int id;         // This is hash of the name. Name Found in SndAlias asset in ff
 
         unsigned int size;
 
         unsigned int size;
 
unsigned int offset;
 
unsigned int offset;
 
unsigned int frameCount;  
 
unsigned int frameCount;  
char frameRateIndex; // see frameRateTable
+
char frameRateIndex; // see frameRateTable
char channelCount; // enum 0x1 = mono 0x2 = dual
+
char channelCount; // enum 0x1 = mono 0x2 = dual
 
char looping;
 
char looping;
 
snd_asset_format format;
 
snd_asset_format format;
 
}; // 0x14
 
}; // 0x14
 +
 +
struct SndAssetBankEntryHash
 +
{
 +
        char hash[16]; // md5 of the audio file
 +
}; // 0x10
  
 
struct SndAssetBankHeader
 
struct SndAssetBankHeader
 
{
 
{
unsigned int magic;         // "2UX#"
+
unsigned int magic;           // "2UX#"
unsigned int version;         // 0x0E
+
unsigned int version;       // 0x0E
unsigned int entrySize;           // 0x14
+
unsigned int entrySize;       // 0x14
unsigned int checksumSize;           // 0x10
+
unsigned int checksumSize;   // 0x10
unsigned int dependencySize;         // 0x40
+
unsigned int dependencySize; // 0x40
unsigned int entryCount; // number of sound entries NOT NAME ENTRIES
+
unsigned int entryCount;     // number of sound entries NOT NAME ENTRIES
unsigned int dependencyCount; // always 0x8 for some reason, might be the size of the next 3 fields
+
unsigned int dependencyCount;
 
unsigned int pad32;
 
unsigned int pad32;
__int64 fileSize; // Size of the whole file
+
__int64 fileSize;       // Size of the whole file
__int64 entryOffset; // &SndAssetBankEntry[0]
+
__int64 entryOffset;       // &SndAssetBankEntry[0]
__int64 checksumOffset; // &hash_entry_t[0]
+
__int64 checksumOffset;       // &SndAssetBankEntryHash[0]
char checksumChecksum[16];         // 16 bytes which are associated between sabs + 0x38 and soundasset + 0x830 (can be > 0x830)
+
char checksumChecksum[16];
char dependencies[30][64];
+
char dependencies[512];
char padding[0x38];
+
char padding[1464];
 
}; // 0x800
 
}; // 0x800
 
</source>
 
</source>
  
 
To calculate the duration of an audio entry:
 
To calculate the duration of an audio entry:
durationInMilliseconds = 1000 * frameCount / frameRate;
+
<source lang="cpp">
Note that "frameRate" is the actual frame rate value from the table and not the index/flag value from the structure.
+
unsigned int SND_AssetBankGetFrameRate(SndAssetBankEntry *entry) {
 +
      int frameRate;
 +
      if (!entry)
 +
          break;
 +
     
 +
      switch (entry->frameRateIndex) {
 +
              case 0: frameRate = 8000; break;
 +
              case 1: frameRate = 12000; break;
 +
              case 2: frameRate = 16000; break;
 +
              case 3: frameRate = 24000; break;
 +
              case 4: frameRate = 32000; break;
 +
              case 5: frameRate = 44100; break;
 +
              case 6: frameRate = 48000; break;
 +
              case 7: frameRate = 96000; break;
 +
              case 8: frameRate = 192000; break;
 +
              default:
 +
                frameRate = 0;
 +
                break;
 +
      }
 +
      return frameRate;
 +
}
 +
 
 +
unsigned int SND_AssetBankGetLengthMs(SndAssetBankEntry *entry) {
 +
 
 +
      if (!entry)
 +
          break;
 +
     
 +
      return 1000 * entry->frameCount / SND_AssetBankGetFrameRate(entry);
 +
}
 +
</source>

Revision as of 18:52, 31 October 2018

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 Asset Bank Stream
  • SABL = Snd Asset Bank Load

Structure

Thanks to Jakes625, Red-EyeX32, master131, and kokole.

enum snd_asset_channel_mode 
{
	SND_ASSET_CHANNEL_MODE_MONO = 0x1,
	SND_ASSET_CHANNEL_MODE_DUAL = 0x2,
	// Could be more modes ex: ("Joint Stereo" and "Stereo")
};
 
enum snd_asset_format
{
	SND_ASSET_FORMAT_PCMS16 = 0x0,
	SND_ASSET_FORMAT_PCMS24 = 0x1,
	SND_ASSET_FORMAT_PCMS32 = 0x2,
	SND_ASSET_FORMAT_IEEE = 0x3,
	SND_ASSET_FORMAT_XMA4 = 0x4,
	SND_ASSET_FORMAT_MP3 = 0x5,
	SND_ASSET_FORMAT_MSADPCM = 0x6,
	SND_ASSET_FORMAT_WMA = 0x7,
	SND_ASSET_FORMAT_FLAC = 0x8,
	SND_ASSET_FORMAT_WIIUADPCM = 0x9,
	SND_ASSET_FORMAT_MPC = 0xA,
	SND_ASSET_FORMAT_COUNT = 0xB,
};
 
 
 
struct SndAssetBankEntry
{
	unsigned int id;         // This is hash of the name. Name Found in SndAlias asset in ff
        unsigned int size;
	unsigned int offset;
	unsigned int frameCount; 
	char frameRateIndex; 	 // see frameRateTable
	char channelCount; 	 // enum 0x1 = mono 0x2 = dual
	char looping;
	snd_asset_format format;
}; // 0x14
 
struct SndAssetBankEntryHash 
{ 
        char hash[16]; // md5 of the audio file 
}; // 0x10
 
struct SndAssetBankHeader
{
	unsigned int magic;           // "2UX#"
	unsigned int version; 	      // 0x0E
	unsigned int entrySize;       // 0x14
	unsigned int checksumSize;    // 0x10
	unsigned int dependencySize;  // 0x40
	unsigned int entryCount;      // number of sound entries NOT NAME ENTRIES
	unsigned int dependencyCount;
	unsigned int pad32;
	__int64 fileSize; 	      // Size of the whole file
	__int64 entryOffset; 	      // &SndAssetBankEntry[0]
	__int64 checksumOffset;       // &SndAssetBankEntryHash[0]
	char checksumChecksum[16];
	char dependencies[512];
	char padding[1464];
}; // 0x800

To calculate the duration of an audio entry:

unsigned int SND_AssetBankGetFrameRate(SndAssetBankEntry *entry) {
       int frameRate;
       if (!entry)
           break;
 
       switch (entry->frameRateIndex) {
               case 0: frameRate = 8000; break;
               case 1: frameRate = 12000; break;
               case 2: frameRate = 16000; break;
               case 3: frameRate = 24000; break;
               case 4: frameRate = 32000; break;
               case 5: frameRate = 44100; break;
               case 6: frameRate = 48000; break;
               case 7: frameRate = 96000; break;
               case 8: frameRate = 192000; break;
               default:
                 frameRate = 0;
                 break;
       }
       return frameRate;
}
 
unsigned int SND_AssetBankGetLengthMs(SndAssetBankEntry *entry) {
 
       if (!entry)
           break;
 
       return 1000 * entry->frameCount / SND_AssetBankGetFrameRate(entry);
}