BCSAR: Difference between revisions
m BCSAR View added to the Tools |
|||
(13 intermediate revisions by 7 users not shown) | |||
Line 1: | Line 1: | ||
The BCSAR (Binary CTR Sound ARchive) format is the 3DS's equivalent of the Wii's BRSAR format. They're not the same structures, though, but they do have the same purpose. | |||
The BCSAR (CTR Sound ARchive) format is the 3DS's equivalent of the Wii's BRSAR format. They're not the same structures, though, but they do have the same purpose. | |||
BCSAR are located in the RomFS, this is usually stored under "romfs:/sound/<name>.bcsar". This contains various audio formats, such as CSTM, CWSD, and CWAV. | BCSAR are located in the RomFS, this is usually stored under "romfs:/sound/<name>.bcsar". This contains various audio formats, such as CSTM, CWSD, CSEQ, and CWAV. | ||
== BCSAR Header == | == BCSAR Header == | ||
Line 40: | Line 37: | ||
| 0x14 | | 0x14 | ||
| 0x4 | | 0x4 | ||
| | | STRG partition reference ID? (Always 0x2000) | ||
|- | |- | ||
| 0x18 | | 0x18 | ||
Line 52: | Line 49: | ||
| 0x20 | | 0x20 | ||
| 0x4 | | 0x4 | ||
| | | INFO partition reference ID? (Always 0x2001) | ||
|- | |- | ||
| 0x24 | | 0x24 | ||
Line 61: | Line 58: | ||
| 0x4 | | 0x4 | ||
| Length of INFO partition | | Length of INFO partition | ||
|- | |||
| 0x2C | |||
| 0x4 | |||
| Main FILE partition reference ID? (Always 0x2002) | |||
|- | |- | ||
| 0x30 | | 0x30 | ||
Line 86: | Line 87: | ||
STRG contains the names of the audio files in the BCSAR. | STRG contains the names of the audio files in the BCSAR. | ||
Header | ==== Header ==== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 101: | Line 101: | ||
| 0x4 | | 0x4 | ||
| Length of STRG partition (also in CSAR header) | | Length of STRG partition (also in CSAR header) | ||
|- | |||
| 0x8 | |||
| 0x4 | |||
| String table type magic (always 0x2400) | |||
|- | |||
| 0xC | |||
| 0x4 | |||
| This + 8 points to the string table (always 0x10) | |||
|- | |||
| 0x10 | |||
| 0x4 | |||
| String table lookup type magic (always 0x2401) | |||
|- | |||
| 0x14 | |||
| 0x4 | |||
| This + 8 points to the string lookup table | |||
|- | |- | ||
| 0x18 | | 0x18 | ||
| 0x4 | | 0x4 | ||
| | | Filename count | ||
|- | |||
| 0x1C | |||
| 0xC * count | |||
| String offset table | |||
|- | |- | ||
|} | |} | ||
==== String offset table entry ==== | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 118: | Line 138: | ||
| 0x0 | | 0x0 | ||
| 0x4 | | 0x4 | ||
| Type of the | | Type of the node (should be 0x1F01) | ||
|- | |- | ||
| 0x4 | | 0x4 | ||
| 0x4 | | 0x4 | ||
| Offset of the | | Offset to data from the end of the STRG header (sizeof 0x18) | ||
|- | |- | ||
| 0x8 | | 0x8 | ||
| 0x4 | | 0x4 | ||
| | | Length of the data buffer (includes NUL terminator) | ||
|- | |- | ||
|} | |} | ||
Then every filename is rawly setted. You can set up a dictionary that contains, using a simple counter, the size of every filename in order. Then, using the same type of counter, get the values of the size of the filename in a correct order. | Then every filename is rawly setted. You can set up a dictionary that contains, using a simple counter, the size of every filename in order. Then, using the same type of counter, get the values of the size of the filename in a correct order. | ||
==== String lookup table ==== | |||
===== Header ===== | |||
{| class="wikitable" border="1" | |||
|- | |||
! OFFSET | |||
! SIZE | |||
! DESCRIPTION | |||
|- | |||
| 0x0 | |||
| 0x4 | |||
| Index of the root entry | |||
|- | |||
| 0x4 | |||
| 0x4 | |||
| Entry count | |||
|- | |||
| 0x8 | |||
| 0x14 * count | |||
| Lookup entry | |||
|- | |||
|} | |||
===== Entry ===== | |||
{| class="wikitable" border="1" | |||
|- | |||
! OFFSET | |||
! SIZE | |||
! DESCRIPTION | |||
|- | |||
| 0x0 | |||
| 0x2 | |||
| Nonzero if contains data | |||
|- | |||
| 0x2 | |||
| 0x2 | |||
| Bit test condition (index = (this >> 3), bit = (~this & 7)), -1 if unused | |||
|- | |||
| 0x4 | |||
| 0x4 | |||
| Fail condition leaf index (-1 if unused) | |||
|- | |||
| 0x8 | |||
| 0x4 | |||
| Success condition leaf index (-1 if unused) | |||
|- | |||
| 0xC | |||
| 0x4 | |||
| String lookup table index (-1 if unused) | |||
|- | |||
| 0x10 | |||
| 0x3 | |||
| 3-byte Resource ID, Little Endian (-1 if unused) | |||
|- | |||
| 0x13 | |||
| 0x1 | |||
| Resource type (01=sound, 02=sound list, 03=sound bank, 04=sound player name?, 06=sound group, FF=unused) | |||
|- | |||
|} | |||
=== INFO === | === INFO === | ||
Line 135: | Line 219: | ||
For now I only know some information in the header for this partition, but I'm working on figuring the rest out. | For now I only know some information in the header for this partition, but I'm working on figuring the rest out. | ||
==== Header ==== | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 149: | Line 235: | ||
| 0x4 | | 0x4 | ||
| Length of INFO partition (also in CSAR header) | | Length of INFO partition (also in CSAR header) | ||
|- | |||
| 0x8 | |||
| 0x4 | |||
| Audio Table Reference ID (0x2100) | |||
|- | |||
| 0xC | |||
| 0x4 | |||
| This + 8 points to the Audio Table | |||
|- | |||
| 0x10 | |||
| 0x4 | |||
| Set Table Reference ID (0x2104) | |||
|- | |||
| 0x14 | |||
| 0x4 | |||
| This + 8 points to the Set Table | |||
|- | |||
| 0x18 | |||
| 0x4 | |||
| Bank Table Reference ID (0x2101) | |||
|- | |||
| 0x1C | |||
| 0x4 | |||
| This + 8 points to the Bank Table | |||
|- | |||
| 0x20 | |||
| 0x4 | |||
| WAV Archive Table Reference ID (0x2103) | |||
|- | |||
| 0x24 | |||
| 0x4 | |||
| This + 8 points to the WAV Archive Table | |||
|- | |||
| 0x28 | |||
| 0x4 | |||
| Group Table Reference ID (0x2105) | |||
|- | |||
| 0x2C | |||
| 0x4 | |||
| This + 8 points to the Group Table | |||
|- | |||
| 0x30 | |||
| 0x4 | |||
| Player Table Reference ID (0x2102) | |||
|- | |||
| 0x34 | |||
| 0x4 | |||
| This + 8 points to Player Table | |||
|- | |||
| 0x38 | |||
| 0x4 | |||
| FILE Table Reference ID (0x2106) | |||
|- | |||
| 0x3C | |||
| 0x4 | |||
| This + 8 points to the FILE Table | |||
|- | |||
| 0x40 | |||
| 0x4 | |||
| Unknown Table Reference ID (0x220B) | |||
|- | |||
| 0x44 | |||
| 0x4 | |||
| This + 8 points to unknown | |||
|- | |||
|} | |||
==== Blocks ==== | |||
Every offset in the header points to data similar to this: | |||
* 4byte length | |||
* length array of the below struct | |||
** u32 type | |||
** u32 offset relative to the address of the length field (beginning of the block) | |||
The data the offset points to is dependent on the type of the above struct: | |||
===== 0x2200 ===== | |||
{| class="wikitable" border="1" | |||
|- | |||
! OFFSET | |||
! SIZE | |||
! DESCRIPTION | |||
|- | |||
| 0x0 | |||
| 0x4 | |||
| Unknown | |||
|- | |||
| 0x4 | |||
| 0x4 | |||
| Sound player ID | |||
|- | |||
| 0x8 | |||
| 0x4 | |||
| Unknown | |||
|- | |||
| 0xC | |||
| 0x4 | |||
| Type of the extended info | |||
|- | |||
| 0x10 | |||
| 0x4 | |||
| Offset to extended info *relative to the beginning of this struct* | |||
|- | |||
| 0x14 | |||
| ??? | |||
| Unknown... | |||
|- | |||
|} | |||
===== 0x2204 ===== | |||
{| class="wikitable" border="1" | |||
|- | |||
! OFFSET | |||
! SIZE | |||
! DESCRIPTION | |||
|- | |||
| 0x0 | |||
| 0x4 | |||
| First Sound ID in this sequence set | |||
|- | |||
| 0x4 | |||
| 0x4 | |||
| Last Sound ID in this sequence set | |||
|- | |||
| 0x8 | |||
| 0x4 | |||
| Type of the extended info | |||
|- | |||
| 0xC | |||
| 0x4 | |||
| Offset to extended info *relative to the beginning of this struct* | |||
|- | |||
| 0x10 | |||
| 0x4 | |||
| Type of the extended info | |||
|- | |||
| 0x14 | |||
| 0x4 | |||
| Offset to extended info *relative to the beginning of this struct* | |||
|- | |||
| 0x18 | |||
| 0x4 | |||
| Unknown | |||
|- | |||
| 0x1C | |||
| 0x4 | |||
| Unknown | |||
|- | |||
|} | |||
===== 0x2206 ===== | |||
{| class="wikitable" border="1" | |||
|- | |||
! OFFSET | |||
! SIZE | |||
! DESCRIPTION | |||
|- | |||
| 0x0 | |||
| 0x4 | |||
| Unknown | |||
|- | |||
| 0x4 | |||
| 0x4 | |||
| Type of the extended info | |||
|- | |||
| 0x8 | |||
| 0x4 | |||
| Offset to extended info *relative to the beginning of this struct* | |||
|- | |||
| 0xC | |||
| 0x4 | |||
| Unknown | |||
|- | |||
| 0x10 | |||
| 0x4 | |||
| Unknown | |||
|- | |||
|} | |||
===== Table IDs ===== | |||
{| class="wikitable" border="1" | |||
|- | |||
! ID | |||
! NAME | |||
|- | |||
| 0x2200 | |||
| Audio Table | |||
|- | |||
| 0x2204 | |||
| Set Table | |||
|- | |||
| 0x2206 | |||
| Bank Table | |||
|- | |||
| 0x2207 | |||
| WAV Archive Table | |||
|- | |||
| 0x2208 | |||
| Group Table | |||
|- | |||
| 0x2208 | |||
| Player Table | |||
|- | |||
| 0x220A | |||
| FILE Table | |||
|- | |- | ||
|} | |} | ||
Line 170: | Line 466: | ||
| Length of FILE partition (also in CSAR header) | | Length of FILE partition (also in CSAR header) | ||
|- | |- | ||
| 0x8 | |||
| 0x24 | |||
| Padding | |||
|} | |} | ||
Line 177: | Line 476: | ||
After some more research, there are multiple FILE partitions, but only 1 of them is the 'main' FILE partition (it's the one you get from the BCSAR header). The 'main' FILE partition contains all of the other sub FILE partitions. | After some more research, there are multiple FILE partitions, but only 1 of them is the 'main' FILE partition (it's the one you get from the BCSAR header). The 'main' FILE partition contains all of the other sub FILE partitions. | ||
== Tools == | |||
* vgmtoolbox's Advanced Cutter/Offset Finder tool can extract BCWAVs without filenames | |||
* [https://github.com/soneek/3DSUSoundArchiveTool 3DSUSoundArchiveTool] reference implementation of CSAR extraction | |||
* [https://github.com/thane98/BCSAR-View BCSAR View] | |||
* [https://github.com/Gota7/Citric-Composer Citric Composer] | |||
[[Category:File formats]] |