Line 1: |
Line 1: |
| [[Category:File formats]] | | [[Category:File formats]] |
| This document is about the format of CTR Streams (CSTM). | | This document is about the format of CTR Streams (CSTM). |
− |
| |
− | The structure is almost exact to the CTR Wave Format (CWAV).
| |
| | | |
| === Overview === | | === Overview === |
| | | |
− | The structure of the CSTM is almost exactly the CWAV, except a few differences. The formats can be easily converted between eachother. | + | The structure is similar to that of a [[BCWAV]], with a few differences, such as its different INFO block format, the addition of a SEEK block, and the organization of the DATA block samples into blocks. |
| | | |
| These files are either found in rom:\sound\stream\ or they can be inside of a CSAR. | | These files are either found in rom:\sound\stream\ or they can be inside of a CSAR. |
| | | |
− | === Format === | + | === Header === |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | 0x000 || 4 || Magic (CSTM) |
| + | |- |
| + | | 0x004 || 2 || Endianness (0xFEFF = little, 0xFFFE = big) |
| + | |- |
| + | | 0x006 || 2 || Header Size (0x40 due to [[#Info Block|Info Block]] alignment) |
| + | |- |
| + | | 0x008 || 4 || Version (0x02000000) |
| + | |- |
| + | | 0x00C || 4 || File Size |
| + | |- |
| + | | 0x010 || 2 || Number of Blocks (3) |
| + | |- |
| + | | 0x012 || 2 || Reserved |
| + | |- |
| + | | 0x014 || 12 || [[#Info Block|Info Block]] [[#Sized Reference|Sized Reference]] (Offset relative to start of file) |
| + | |- |
| + | | 0x020 || 12 || [[#Seek Block|Seek Block]] [[#Sized Reference|Sized Reference]] (Offset relative to start of file) |
| + | |- |
| + | | 0x02C || 12 || [[#Data Block|Data Block]] [[#Sized Reference|Sized Reference]] (Offset relative to start of file) |
| + | |} |
| + | |
| + | === Block Header === |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | 0x000 || 4 || Magic |
| + | |- |
| + | | 0x004 || 4 || Size |
| + | |} |
| + | |
| + | ==== Block Types ==== |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! MAGIC !! TYPE |
| + | |- |
| + | | INFO || [[#Info Block|Info Block]] |
| + | |- |
| + | | SEEK || [[#Seek Block|Seek Block]] |
| + | |- |
| + | | DATA || [[#Data Block|Data Block]] |
| + | |} |
| + | |
| + | === Info Block === |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | 0x000 || 8 || [[#Block Header|Block Header]] |
| + | |- |
| + | | 0x008 || 8 || [[#Stream Info|Stream Info]] [[#Reference|Reference]] (Offset relative to this field) |
| + | |- |
| + | | 0x010 || 8 || [[#Track Info|Track Info]] [[#Reference Table|Reference Table]] [[#Reference|Reference]] (Offset relative to [[#Stream Info|Stream Info]] [[#Reference|Reference]] field) |
| + | |- |
| + | | 0x018 || 8 || [[#Channel Info|Channel Info]] [[#Reference Table|Reference Table]] [[#Reference|Reference]] (Offset relative to [[#Stream Info|Stream Info]] [[#Reference|Reference]] field) |
| + | |- |
| + | | 0x020 || 56 || [[#Stream Info|Stream Info]] |
| + | |- |
| + | | 0x058 || X || [[#Track Info|Track Info]] [[#Reference Table|Reference Table]] |
| + | |- |
| + | | X || X || [[#Channel Info|Channel Info]] [[#Reference Table|Reference Table]] |
| + | |- |
| + | | X || X || [[#Track Info|Track Info]] Entries |
| + | |- |
| + | | X || X || [[#Channel Info|Channel Info]] Entries |
| + | |} |
| + | |
| + | If encoding is DSP ADPCM: |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | X || X || [[#DSP ADPCM Info|DSP ADPCM Info]] Entries |
| + | |} |
| + | |
| + | If encoding is IMA ADPCM: |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | X || X || [[#IMA ADPCM Info|IMA ADPCM Info]] Entries |
| + | |} |
| + | |
| + | The info block is aligned to 0x20 bytes. |
| + | |
| + | ==== Encoding ==== |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! VALUE !! DESCRIPTION |
| + | |- |
| + | | 0 || PCM8 |
| + | |- |
| + | | 1 || PCM16 |
| + | |- |
| + | | 2 || DSP ADPCM |
| + | |- |
| + | | 3 || IMA ADPCM |
| + | |} |
| + | |
| + | ==== Stream Info ==== |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | 0x000 || 1 || [[#Encoding|Encoding]] |
| + | |- |
| + | | 0x001 || 1 || Loop (0 = don't loop, 1 = loop) |
| + | |- |
| + | | 0x002 || 1 || Channel Count |
| + | |- |
| + | | 0x003 || 1 || Padding |
| + | |- |
| + | | 0x004 || 4 || Sample Rate |
| + | |- |
| + | | 0x008 || 4 || Loop Start Frame |
| + | |- |
| + | | 0x00C || 4 || Loop End Frame |
| + | |- |
| + | | 0x010 || 4 || Sample Block Count |
| + | |- |
| + | | 0x014 || 4 || Sample Block Size |
| + | |- |
| + | | 0x018 || 4 || Sample Block Sample Count |
| + | |- |
| + | | 0x01C || 4 || Last Sample Block Size |
| + | |- |
| + | | 0x020 || 4 || Last Sample Block Sample Count |
| + | |- |
| + | | 0x024 || 4 || Last Sample Block Padded Size |
| + | |- |
| + | | 0x028 || 4 || Seek Data Size |
| + | |- |
| + | | 0x02C || 4 || Seek Interval Sample Count |
| + | |- |
| + | | 0x030 || 8 || Sample Data [[#Reference|Reference]] (Offset relative to [[#Data Block|Data Block]] Data field) |
| + | |} |
| + | |
| + | ==== Track Info ==== |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | 0x000 || 1 || Volume |
| + | |- |
| + | | 0x001 || 1 || Pan |
| + | |- |
| + | | 0x002 || 2 || Padding |
| + | |- |
| + | | 0x004 || 8 || Channel Index [[#Byte Table|Byte Table]] [[#Reference|Reference]] (Offset relative to Volume field) |
| + | |- |
| + | | 0x00C || X || Channel Index [[#Byte Table|Byte Table]] (Padded to 4 bytes) |
| + | |} |
| + | |
| + | ===== Byte Table ===== |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | 0x000 || 4 || Count |
| + | |- |
| + | | 0x004 || Count || Elements |
| + | |} |
| + | |
| + | ==== Channel Info ==== |
| | | |
− | === CSTM Header === | + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | 0x000 || 8 || ADPCM Info [[#Reference|Reference]] (Offset relative to this field) |
| + | |} |
| + | |
| + | ===== DSP ADPCM Info ===== |
| | | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
Line 18: |
Line 201: |
| ! OFFSET !! SIZE !! DESCRIPTION | | ! OFFSET !! SIZE !! DESCRIPTION |
| |- | | |- |
− | | 0x000 || 4 || MAGIC "CSTM" | + | | 0x000 || 32 || [[#DSP ADPCM Param|Param]] |
| + | |- |
| + | | 0x020 || 6 || [[#DSP ADPCM Context|Context]] |
| + | |- |
| + | | 0x026 || 6 || Loop [[#DSP ADPCM Context|Context]] |
| + | |- |
| + | | 0x02C || 2 || Padding |
| + | |} |
| + | |
| + | ====== DSP ADPCM Param ====== |
| + | |
| + | {| class="wikitable" border="1" |
| |- | | |- |
− | | 0x004 || 2 || Endianess (0xFEFF=LE / 0xFFFE=BE)
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| |- | | |- |
− | | 0x00C || 4 || Filesize | + | | 0x000 || 32 || 16-bit Coefficients |
| |} | | |} |
| | | |
− | === INFO Header === | + | ====== DSP ADPCM Context ====== |
| | | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
Line 31: |
Line 225: |
| ! OFFSET !! SIZE !! DESCRIPTION | | ! OFFSET !! SIZE !! DESCRIPTION |
| |- | | |- |
− | | 0x000 || 4 || Magic "INFO" | + | | 0x000 || 1 || 4-bit Predictor + 4-bit Scale |
| |- | | |- |
− | | 0x004 || 4 || Length | + | | 0x001 || 1 || Reserved |
| |- | | |- |
− | | 0x020 || 1 || Type (00 = PCM8, 01 = PCM16, 02 = DSPADPCM) | + | | 0x002 || 2 || Previous Sample |
| + | |- |
| + | | 0x004 || 2 || Second Previous Sample |
| + | |} |
| + | |
| + | ===== IMA ADPCM Info ===== |
| + | |
| + | {| class="wikitable" border="1" |
| |- | | |- |
− | | 0x021 || 1 || Loop Flag
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| |- | | |- |
− | | 0x022 || 2 || Total Channels | + | | 0x000 || 4 || [[#IMA ADPCM Context|Context]] |
| |- | | |- |
− | | 0x024 || 4 || Sample Rate | + | | 0x004 || 4 || Loop [[#IMA ADPCM Context|Context]] |
| + | |} |
| + | |
| + | ====== IMA ADPCM Context ====== |
| + | |
| + | {| class="wikitable" border="1" |
| |- | | |- |
− | | 0x028 || 4 || Unknown
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| |- | | |- |
− | | 0x02C || 4 || Total samples | + | | 0x000 || 2 || Data |
| |- | | |- |
− | | 0x030 || X || The Channels' Data Pointers | + | | 0x002 || 1 || Table Index |
| |- | | |- |
− | | X || X || The Channels' Data | + | | 0x003 || 1 || Padding |
| |} | | |} |
| | | |
− | === DATA Header === | + | === Seek Block === |
| | | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
Line 58: |
Line 264: |
| ! OFFSET !! SIZE !! DESCRIPTION | | ! OFFSET !! SIZE !! DESCRIPTION |
| |- | | |- |
− | | 0x000 || 4 || Magic "DATA" | + | | 0x000 || 8 || [[#Block Header|Block Header]] |
| + | |- |
| + | | 0x008 || [[#Block Header|Block Header]] Size Value - 8 || Data |
| + | |} |
| + | |
| + | The seek block is aligned to 0x20 bytes. |
| + | |
| + | === Data Block === |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| |- | | |- |
− | | 0x004 || 4 || Length | + | | 0x000 || 8 || [[#Block Header|Block Header]] |
| |- | | |- |
− | | 0x020 || X || Start of Channels' Data | + | | 0x008 || [[#Block Header|Block Header]] Size Value - 8 || Data |
| |} | | |} |
| | | |
− | Unlike CWAV, if there are 2 channels in a CSTM they alternate every 0x2000 bytes of the DATA partition starting at 0x20.
| + | The data block is aligned to 0x20 bytes, as well as the data field's actual sample data. |
− | The last section of each channel is usually less than 0x2000, the lengths of these channels is stored in the INFO Header. | |
| | | |
− | === SEEK Header === | + | === Reference Table === |
| | | |
− | Additionally it introduces a new partition called SEEK which comes right before DATA, so a CSTM would be ordered like this:
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | 0x000 || 4 || Count |
| + | |- |
| + | | 0x004 || Count * 8 || [[#Reference|References]] (Offsets relative to Count field) |
| + | |} |
| | | |
− | * CSTM Header
| + | === Sized Reference === |
− | * INFO Partition
| + | |
− | * SEEK Partition
| + | {| class="wikitable" border="1" |
− | * DATA Partition
| + | |- |
| + | ! OFFSET !! SIZE !! DESCRIPTION |
| + | |- |
| + | | 0x000 || 8 || [[#Reference|Reference]] |
| + | |- |
| + | | 0x008 || 4 || Size |
| + | |} |
| | | |
− | By default this means that 0x24-0x2B in the CSTM Partition is the SEEK position and length respectively, and DATA position and length follows it (in a CWAV 0x24-0x2B is usually the DATA position and length).
| + | === Reference === |
| | | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
Line 83: |
Line 312: |
| ! OFFSET !! SIZE !! DESCRIPTION | | ! OFFSET !! SIZE !! DESCRIPTION |
| |- | | |- |
− | | 0x000 || 4 || Magic (SEEK) | + | | 0x000 || 2 || Type ID |
| + | |- |
| + | | 0x002 || 2 || Padding |
| + | |- |
| + | | 0x004 || 4 || Offset ("null" = 0xFFFFFFFF) |
| + | |} |
| + | |
| + | ==== Reference Types ==== |
| + | |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! ID !! TYPE |
| + | |- |
| + | | 0x0100 || [[#Byte Table|Byte Table]] |
| + | |- |
| + | | 0x0101 || [[#Reference Table|Reference Table]] |
| + | |- |
| + | | 0x0300 || [[#DSP ADPCM Info|DSP ADPCM Info]] |
| + | |- |
| + | | 0x0301 || [[#IMA ADPCM Info|IMA ADPCM Info]] |
| + | |- |
| + | | 0x1F00 || [[#Data_Block|Sample Data]] |
| + | |- |
| + | | 0x4000 || [[#Info Block|Info Block]] |
| + | |- |
| + | | 0x4001 || [[#Seek Block|Seek Block]] |
| + | |- |
| + | | 0x4002 || [[#Data Block|Data Block]] |
| + | |- |
| + | | 0x4100 || [[#Stream Info|Stream Info]] |
| + | |- |
| + | | 0x4101 || [[#Track Info|Track Info]] |
| |- | | |- |
− | | 0x004 || 4 || Length | + | | 0x4102 || [[#Channel Info|Channel Info]] |
| |} | | |} |