Difference between revisions of "DSP (File Format)"

From Retro Modding Wiki
Jump to: navigation, search
(Audio Data)
Line 104: Line 104:
 
}
 
}
  
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;

Revision as of 12:02, 24 January 2015

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; the CSMP format actually embeds the entire DSP format within it.

Header

Offset Size Description
0x0 4 Sample count
0x4 4 ADPCM nibble count
0x8 4 Sample rate
0xC 2 Loop flag; 1 means looped, 0 means not looped
0xE 2 Format; always 0
0x10 4 Loop start offset
0x14 4 Loop end offset
0x18 4 Always 0
0x1C 2 × 16 Decode coefficients; this is 8 pairs of signed 16-bit values
0x3C 2 Gain; always 0
0x3E 2 Initial predictor/scale; always matches first frame header
0x40 2 Initial sample history 1
0x42 2 Initial sample history 2
0x44 2 Loop context predictor/scale
0x46 2 Loop context sample history 1
0x48 2 Loop context sample history 2
0x4A 2 × 11 Padding
0x60 End of DSP header

Audio 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, the bottom 4 bits are the scale value, and the top 4 bits are the coefficient index to use for the current frame.

Sample decoding code (vgmstream used as reference):

  1. static const s8 nibble_to_s8[16] = {0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1};
  2.  
  3. s8 get_low_nibble(u8 byte) {
  4.     return nibble_to_s8[byte & 0xF];
  5. }
  6.  
  7. s8 get_high_nibble(u8 byte) {
  8.     return nibble_to_s8[(byte >> 4) & 0xF];
  9. }
  10.  
  11. s16 clamp(s32 val) {
  12.     if (val < -32768) val = -32768;
  13.     if (val > 32767) val = 32767;
  14.     return s16(val);
  15. }
  16.  
  17. void DecodeADPCM(u8 *src, s16 *dst, const DSPHeader& d)
  18. {
  19.   s16 hist1 = d.initial_hist1;
  20.   s16 hist2 = d.initial_hist2;
  21.   s16 *dst_end = dst + d.num_samples;
  22.  
  23.   while (dst < dst_end)
  24.   {
  25.     // Each frame, we need to read the header byte and use it to set the scale and coefficient values:
  26.     u8 header = *src++;
  27.  
  28.     u16 scale = 1 << (header & 0xF);
  29.     u8 coef_index = (header >> 4);
  30.     s16 coef1 = d.coefs[coef_index * 2];
  31.     s16 coef2 = d.coefs[coef_index * 2 + 1];
  32.  
  33.     // 7 bytes per frame
  34.     for (u32 b = 0; b < 7; b++)
  35.     {
  36.       u8 byte = *src++;
  37.  
  38.       // 2 samples per byte
  39.       for (u32 s = 0; s < 2; s++)
  40.       {
  41.         s8 adpcm_nibble = (s == 0) ? get_high_nibble(byte) : get_low_nibble(byte);
  42.         s16 sample = clamp(((adpcm_nibble * scale) << 11) + 1024 + ((coef1 * hist1) + (coef2 * hist2)) >> 11);
  43.  
  44.         hist2 = hist1;
  45.         hist1 = sample;
  46.         *dst++ = sample;
  47.  
  48.         if (dst >= dst_end) break;
  49.       }
  50.       if (dst >= dst_end) break;
  51.     }
  52.   }
  53. }