Duck DK3 IMA ADPCM
- Audio ID: 0x0062
- Company: Duck/On2
- Samples: http://samples.mplayerhq.hu/A-codecs/DK3/
Some Sega Saturn game CDs contain AVI files which store audio using the Duck DK3 IMA ADPCM algorithm. DK3 ADPCM data can be decoded using the same tables as are used to decode IMA ADPCM data while using a slightly modified variant of the IMA ADPCM algorithm. The name DK3 apparently comes from the fact that 3 ADPCM nibbles decode to 4 16-bit PCM samples, in contrast to Duck's DK4 IMA ADPCM algorithm, in which 4 ADPCM nibbles decode to 4 16-bit PCM samples.
All multi-byte values are encoded in little-endian format. The length of a single block of DK3 data is encoded in the nBlockAlign field of an AVI file's WAVEFORMATEX header.
The DK3 algorithm encodes a sum channel and a difference channel, rather than left and right channels, using the standard IMA ADPCM algorithm and tables. Note that the encoding implies that the format only supports stereo data. A block of DK3 has a 16-byte preamble with the following information:
bytes 0-1 unknown bytes 2-3 sample rate bytes 4-9 unknown bytes 10-11 initial sum channel predictor bytes 12-13 initial diff channel predictor byte 14 initial sum channel index byte 15 initial diff channel index
After processing the block preamble, a stream of DK3 data is decoded nibble by nibble, just like many ADPCM algorithms. The low nibble is decoded first (bits 3-0), then the high nibble. When decoding the stream, it is useful to conceptualize it as a stream of nibbles:
n0 n1 n2 n3 n4 n5 n6 n7 ...
where the nibbles were arranged in the original bytestream as:
byte0 byte1 byte2 byte3 n1n0 n3n2 n5n4 n7n6 ...
Each set of 3 nibbles decodes to 4 16-bit PCM samples using this process (note that the diff value is initialized to the same value as the diff predictor):
- get next ADPCM nibble in stream
- update sum channel predictor and index using nibble
- get next ADPCM nibble in stream
- update diff channel predictor and index using nibble
- diff value = (diff value + diff predictor) / 2
- next left channel PCM sample = sum channel + diff value
- next right channel PCM sample = sum channel - diff value
- get next ADPCM nibble in stream
- update sum channel predictor and index using nibble
- next left channel PCM sample = sum channel + diff value
- next right channel PCM sample = sum channel - diff value