Kingdom Hearts DS Games - SDAT File Format
This document covers the SDAT file format. SDAT files contain music and sound effect data, either in the form of sequenced sound or as full audio samples. All information was referenced from this document
The Nitro Composer packs various types of sound files in a single file (*.sdat) for use in DS games.
Inside the SDAT you will find: SSEQ (Sequence), SSAR (Sequence Archive), SBNK (Sound Bank), SWAR (Wave Archive), STRM (Stream).
SSAR is a collection of SSEQ, while SWAR is a collection of SWAV.
The file has the following structure:
- Header
- Symbol Block
- Info Block
- File Allocation Table (FAT)
- File Block
Header
The Header appears at offset 0 in the SDAT file.
Position | Type | Name | Description |
---|---|---|---|
0x0 | int8[4] | type | ‘SDAT’ |
0x4 | uint32 | magic | 0x0100feff |
0x8 | uint32 | nFileSize | |
0xC | uint16 | nSize | |
0xE | uint16 | nBlock | usually 4, but some have 3 only ( Symbol Block omitted ) |
0x10 | uint32 | nSymbOffset | offset of Symbol Block = 0x40 |
0x14 | unit32 | nSymbSize | size of Symbol Block |
0x18 | uint32 | nInfoOffset | offset of Info Block |
0x1C | uint32 | nInfoSize | size of Info Block |
0x20 | uint32 | nFatOffset | offset of FAT |
0x24 | uint32 | nFatSize | size of FAT |
0x28 | uint32 | nFileOffset | offset of File Block |
0x2C | uint32 | nFileSize | size of File Block |
0x30 | uint8[16] | reserved | unused, 0s |
Symbol Block
It appears at offset 0x40, right after the Header. It may be omitted. It contains the symbols (or “filenames”) of each sound file in the SDAT file. All offsets are relative to this block’s starting address (i.e. 0x40). NB. Some files doesn’t have Symbol Block. NB. The value of nSize of Symbol Block may not be 32-bit aligned. However, the value of nSymbSize in Header is.
Position | Type | Name | Description |
---|---|---|---|
0x0 | char[4] | type | ‘SYMB’ |
0x4 | uint32 | nSize | size of this Symbol Block |
0x8 | uint32[8] | nRecOffset | offset of Records (note below) |
0x28 | u8[24] | reserved | unused, 0s |
Symbol Block - Record
There are a total of 8 records in the Symbol Block. They are: | Record No. | Record Name | Description |————|————-|———— | 0 | SEQ | Sequence (for music) | 1 | SEQARC | Sequence Archive (for sound effect) | 2 | BANK | Sound Bank | 3 | WAVEARC | Wave Archive | 4 | PLAYER* | Player (Group-related) | 5 | GROUP | Group of SEQ/SEQARC/BANK/WAVEARC | 6 | PLAYER2* | Player2 (Stream-related) | 7 | STRM | Stream
- Records 4 and 5 do not appear in SMAP file. A SMAP File is generated by the Nitro Composer listing all sound files in the SDAT file. An example can be found from «Zoids Saga DS - Legend of Arcadia»
All offsets are relative to Symbol block’s starting address (i.e. 0x40). Each record (except Record 1 “SEQARC”) has the following structure:
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint32 | nCount | No of entries in this record |
0x4 | uint32 | nEntryOffset | Array of offsets of each entry |
For Record 1 (SEQARC), it is a group which contains sub-records. The sub-record is of the same structure as SDATSYMBREC (above). Record 1 has the following structure:
Position | Type | Name | Description |
---|---|---|---|
0x0 | unit32 | nCount | No of entries in this record |
0x4 | uint32 | nEntryOffset | Offset of this Group’s symbol |
0x8 | uint32 | nSubRecOffset | Offset of the sub-record |
Below is an example to access these records:
```SDATSYMB *symb; int i, j; char *szSymbol; … // access record 0 ‘SSEQ’ SDATSYMBREC *symb_rec = (SDATSYMBREC *) ( (u8 *)symb + symb->RecOffset[0] );
for ( i = 0; i < symb_rec->nCount; i++ ) { // print out the symbol szSymbol = (char *) ( (u8 *)symb + symb_rec->nEntryOffset[i] ); printf( “%s\n”, szSymbol ); } …
// access record 1 ‘SSAR’ SDATSYMBREC2 symb_rec2 = (SDATSYMBREC *)( (u8 *)symb + symb->RecOffset[1] );
for ( i = 0; i < symb_rec2->nCount; i++ ) { szSymbol = (char *) ( (u8 *)symb + symb_rec2->Group[ i ].nEntryOffset ); printf( “%s\n”, szSymbol );
SDATSYMBREC *symb_subrec = (SDATSYMBREC *) ( (u8 *)symb + symb_rec2->Group[i].nSubRecOffset );
for ( j = 0; j < symb_subrec->nCount; j++ )
{
// print out sub record's symbols
szSymbol = (char *) ( (u8 *)symb + symb_subrec->nEntryOffset[i] );
printf( "%s\n", szSymbol );
} } ```
Symbol Block - Entry
EXCEPT for Record 1 “SEQARC”, an Entry in the record is a null terminated string. This corresponds to the “filename” of a sound file in the SDAT file.
For Record 1 “SEQARC”, since a SEQARC file is a collection of Sequence files, therefore this record contains a sub-record. And this sub-record contains the symbols (“filenames”) of each of the archived SEQ files.
Info Block
The Info Block appears just after the Symbol Block. It contains some information of each sound file in the SDAT file. All offsets are relative to this block’s starting address.
Position | Type | Name | Description |
---|---|---|---|
0x0 | char[4] | type | ‘INFO’ |
0x4 | uint32 | nSize | size of this Info Block |
0x8 | uint32[8] | nRecOffset | offset of a Record |
0x48 | uint8[24] | reserved | unused, 0s |
Info Block - Record
There are a total of 8 records in the Info Block. The Record Names in 1.2.1 above applies here as well. All offsets are relative to Info block’s starting address. With modifications, the code example above could be used to access the Info records and entries.
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint32 | nCount | No of entries in this record |
0x4 | uint32 | nEntryOffset | array of offsets of each entry |
Info Block - Entry
Record 0 “SEQ” - The Info Entry for SEQ contains playback information.
Position | Type | Name | Description |
---|---|---|---|
0x0 | u16 | fileID | for accessing this file |
0x2 | u16 | unknown | |
0x4 | u16 | bnk | Associated BANK |
0x6 | u8 | vol | Volume |
0x7 | u8 | cpr | |
0x8 | u8 | ppr | |
0x9 | u8 | ply | |
0xA | u8[2] | unknown |
Record 1 “SEQARC”
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint16 | fileID | |
0x2 | uint16 | unknown |
Remarks: no info is available for SEQARC files. The info of each archived SEQ is stored in that SEQARC file.
Record 2 “BANK”
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint16 | fileID | |
0x2 | uint16 | unknown | |
0x4 | uint16[4] | wa | Associated WAVEARC. 0xffff if not in use |
Remarks: Each bank can links to up to 4 WAVEARC files. The wa[4] stores the WAVEARC entry number.
Record 3 “WAVEARC”
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint16 | fileID | |
0x2 | uint16 | unknown |
Remarks: This is not a new structure. It is the same as SDATINFOSSAR above for Record 1.
Record 4 “PLAYER”
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint8 | unknown | |
0x1 | uint8[3] | padding | |
0x4 | uint32 | unknown2 |
Remarks: None
Record 5 “GROUP”
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint32 | nCount | number of sub-records |
0x4 | uint32 | type | |
0x8 | uint32 | nEntry |
Remarks: SDATINFOPlayer::Group::type can be one of the following values. nEntry is the entry number in the relevant Record (SEQ/SEQARC/BANK/WAVEARC).
Value | Type |
---|---|
0x0700 | SEQ |
0x0803 | SEQARC |
0x0601 | BANK |
0x0402 | WAVEARC |
Record 6 “PLAYER2”
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint8 | nCount | |
0x1 | uint8[16] | v | 0xff if not in use |
0x11 | uint8[7] | reserved | padding, 0s |
Remarks: The use is unknown. The first byte states how many of the v[16] is used (non 0xff).
Record 7 “STRM”
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint16 | fileID | for accessing the file |
0x2 | uint16 | unknown | |
0x4 | uint8 | vol | volume |
0x5 | uint8 | pri | |
0x6 | uint8 | ply | |
0x7 | uint8[5] | reserved |
Remarks: ‘ply’ means play?, ‘pri’ means priority?
FAT
The FAT appears just after the Info Block. It contains the records of offset and size of each sound file in the SDAT file.
Position | Type | Name | Description |
---|---|---|---|
0x0 | char[4] | type | ‘FAT ‘ |
0x4 | uint32 | nSize | size of the FAT |
0x8 | uint32 | nCount | Number of FAT records |
0xC | SDATFATREC[1] | Rec | Arrays of FAT records |
FAT - Record (SDATFATREC)
It contains the offset and size of the sound file. All the offsets are relative to the SDAT Header structure’s beginning address.
Position | Type | Name | Description |
---|---|---|---|
0x0 | uint32 | nOffset | offset of the sound file |
0x4 | uint32 | nSize | size of the Sound file |
0x8 | uint32[2] | reserved | always 0s, for storing data in runtime. |
File Block
The File Block is the last block and appears just after the FAT. It has a small header (the structure below) which contains the total size and number of sound of files. All the sound files are stored after this structure.
Position | Type | Name | Description |
---|---|---|---|
0x0 | char[4] | type[4] | ‘FILE’ |
0x4 | uint32 | nSize | size of this block |
0x8 | uint32 | nCount | Mumber of sound files |
0xC | uint32 | reserved | always 0 |