DSP (File Format): Difference between revisions

Jump to navigation Jump to search
m
>Aruki
No edit summary
>Aruki
(12 intermediate revisions by 2 users not shown)
Line 1: Line 1:
The '''.dsp format''' is a common GameCube/Wii format for audio that comes with the SDK. It encodes sound using Nintendo's ADPCM codec. The same ADPCM codec is also embedded into several Retro Studios format, like [[AGSC (File Format)|AGSC]]; the [[CSMP (File Format)|CSMP]] format actually embeds the entire DSP format within it.
The '''.dsp format''' is a common GameCube/Wii format for audio that comes with the SDK. It encodes sound using Nintendo's ADPCM codec. The same ADPCM codec is also embedded into several Retro Studios format, like [[AGSC (File Format)|AGSC]]; the [[CSMP (File Format)|CSMP]] format actually embeds the entire DSP format within it.
{{todo|An explanation of how ADPCM works would be nice to have somewhere on this page. Also, a better text explanation for the decoding process to go along with the example code.}}


__TOC__
__TOC__
Line 7: Line 9:
{| class="wikitable"
{| class="wikitable"
! Offset
! Offset
! Type
! Size
! Size
! Description
! Description
|-
|-
| 0x0
| 0x0
| u32
| 4
| 4
| '''Sample count'''
| '''Sample count'''
|-
|-
| 0x4
| 0x4
| u32
| 4
| 4
| '''ADPCM nibble count'''
| '''ADPCM nibble count'''; includes frame headers
|-
|-
| 0x8
| 0x8
| u32
| 4
| 4
| '''Sample rate'''
| '''Sample rate'''
|-
|-
| 0xC
| 0xC
| u16
| 2
| 2
| '''Loop flag'''; 1 means looped, 0 means not looped
| '''Loop flag'''; 1 means looped, 0 means not looped
|-
|-
| 0xE
| 0xE
| u16
| 2
| 2
| '''Format'''; always 0
| '''Format'''; always 0
|-
|-
| 0x10
| 0x10
| u32
| 4
| 4
| '''Loop start offset'''
| '''Loop start offset'''
|-
|-
| 0x14
| 0x14
| u32
| 4
| 4
| '''Loop end offset'''
| '''Loop end offset'''
|-
|-
| 0x18
| 0x18
| u32
| 4
| 4
| Always 0
| '''Current address'''; always 0
|-
|-
| 0x1C
| 0x1C
| s16[16]
| 2 × 16
| 2 × 16
| '''Decode coefficients'''; this is 8 pairs of signed 16-bit values
| '''Decode coefficients'''; this is 8 pairs of signed 16-bit values
|-
|-
| 0x3C
| 0x3C
| u16
| 2
| 2
| '''Gain'''; always 0
| '''Gain'''; always 0
|-
|-
| 0x3E
| 0x3E
| u16
| 2
| 2
| '''Initial predictor/scale'''; always matches first frame header
| '''Initial predictor/scale'''; always matches first frame header
|-
|-
| 0x40
| 0x40
| s16
| 2
| 2
| '''Initial sample history 1'''
| '''Initial sample history 1'''
|-
|-
| 0x42
| 0x42
| s16
| 2
| 2
| '''Initial sample history 2'''
| '''Initial sample history 2'''
|-
|-
| 0x44
| 0x44
| u16
| 2
| 2
| '''Loop context predictor/scale'''
| '''Loop context predictor/scale'''
|-
|-
| 0x46
| 0x46
| s16
| 2
| 2
| '''Loop context sample history 1'''
| '''Loop context sample history 1'''
|-
|-
| 0x48
| 0x48
| s16
| 2
| 2
| '''Loop context sample history 2'''
| '''Loop context sample history 2'''
|-
|-
| 0x4A
| 0x4A
| u16[11]
| 2 × 11
| 2 × 11
| '''Padding'''
| '''Reserved'''
|-
|-
| 0x60
| 0x60
| colspan=2 | End of DSP header
| colspan=3 {{unknown|End of DSP header}}
|}
|}


== Audio Data ==
== ADPCM Data ==
 
The ADPCM audio data is split up into multiple ''frames''. Each frame is 8 bytes; it starts with a one-byte header, then has 7 bytes (or 14 samples) of audio data. For each frame header, the bottom 4 bits are the scale value, and the top 4 bits are the coefficient index to use for the current frame.


The ADPCM audio data is split up into multiple ''frames''. Each frame is 8 bytes; it starts with a one-byte header, then has 7 bytes (or 14 samples) of audio data. For each frame, the bottom 4 bits are the scale value, and the top 4 bits are the coefficient index to use for the current frame.
=== Example C Decoding Function ===


Sample decoding code ([https://github.com/kode54/vgmstream/blob/master/src/coding/ngc_dsp_decoder.c vgmstream] used as reference):
[https://github.com/kode54/vgmstream/blob/master/src/coding/ngc_dsp_decoder.c vgmstream] used as reference:


<pre>static const s8 nibble_to_s8[16] = {0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1};
<syntaxhighlight lang="c">static const s8 nibble_to_s8[16] = {0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1};


s8 get_low_nibble(u8 byte) {
s8 get_low_nibble(u8 byte) {
Line 104: Line 126:
}
}


void DecodeADPCM(char *src, s16* dst, const DSPHeader& d)
void DecodeADPCM(u8 *src, s16 *dst, const DSPHeader& d)
{
{
   s16 hist1 = d.initial_hist1;
   s16 hist1 = d.initial_hist1;
Line 117: Line 139:
     u16 scale = 1 << (header & 0xF);
     u16 scale = 1 << (header & 0xF);
     u8 coef_index = (header >> 4);
     u8 coef_index = (header >> 4);
     s16 coef1 = d.coefs[coef_index * 2];
     s16 coef1 = d.coefs[coef_index][0];
     s16 coef2 = d.coefs[coef_index * 2 + 1];
     s16 coef2 = d.coefs[coef_index][1];


     // 7 bytes per frame
     // 7 bytes per frame
Line 140: Line 162:
     }
     }
   }
   }
}</pre>
}</syntaxhighlight>


[[Category:Audio]]
[[Category:Audio]]
[[Category:Metroid Prime]]
[[Category:Metroid Prime]]
[[Category:Metroid Prime 2: Echoes]]
[[Category:Metroid Prime 2: Echoes]]
Anonymous user

Navigation menu