DSP (File Format)

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.

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):

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) { return nibble_to_s8[byte & 0xF]; }

s8 get_high_nibble(u8 byte) { return nibble_to_s8[(byte >> 4) & 0xF]; }

s16 clamp(s32 val) { if (val < -32768) val = -32768; if (val > 32767) val = 32767; return s16(val); }

void DecodeADPCM(char *src, s16* dst, const DSPHeader& d) { s16 hist1 = d.initial_hist1; s16 hist2 = d.initial_hist2; s16 *dst_end = dst + d.num_samples;

while (dst < dst_end) {   // Each frame, we need to read the header byte and use it to set the scale and coefficient values: u8 header = *src++;

u16 scale = 1 << (header & 0xF); u8 coef_index = (header >> 4); s16 coef1 = d.coefs[coef_index * 2]; s16 coef2 = d.coefs[coef_index * 2 + 1];

// 7 bytes per frame for (u32 b = 0; b < 7; b++) {     u8 byte = *src++;

// 2 samples per byte for (u32 s = 0; s < 2; s++) {       s8 adpcm_nibble = (s == 0) ? get_high_nibble(byte) : get_low_nibble(byte); s16 sample = clamp(((adpcm_nibble * scale) << 11) + 1024 + ((coef1 * hist1) + (coef2 * hist2)) >> 11);

hist2 = hist1; hist1 = sample; *dst++ = sample;

if (dst >= dst_end) break; }     if (dst >= dst_end) break; } } }