diff options
author | melanson <melanson@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-02-25 02:48:37 +0000 |
---|---|---|
committer | melanson <melanson@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-02-25 02:48:37 +0000 |
commit | ba4694f4bb6e456868a22d927d8f34f93625a2af (patch) | |
tree | f005da803d8573493e4b4f92e9c213eb8aaa4e0e /adpcm.c | |
parent | 3605aa4ec8d0130984aeb402d8f5e9df5d747bfe (diff) | |
download | mpv-ba4694f4bb6e456868a22d927d8f34f93625a2af.tar.bz2 mpv-ba4694f4bb6e456868a22d927d8f34f93625a2af.tar.xz |
fixed, strengthened, rewrote, and renamed a variety of the ADPCM decoders
(including MS, DK4 and DK3 ADPCM)
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@4855 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'adpcm.c')
-rw-r--r-- | adpcm.c | 249 |
1 files changed, 118 insertions, 131 deletions
@@ -12,6 +12,7 @@ #include "config.h" #include "bswap.h" #include "adpcm.h" +#include "mp_msg.h" #define BE_16(x) (be2me_16(*(unsigned short *)(x))) #define BE_32(x) (be2me_32(*(unsigned int *)(x))) @@ -196,11 +197,19 @@ int ms_adpcm_decode_block(unsigned short *output, unsigned char *input, int predictor; // fetch the header information, in stereo if both channels are present + if (input[stream_ptr] > 6) + mp_msg(MSGT_DECAUDIO, MSGL_WARN, + "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n", + input[stream_ptr]); coeff1[0] = ms_adapt_coeff1[input[stream_ptr]]; coeff2[0] = ms_adapt_coeff2[input[stream_ptr]]; stream_ptr++; if (channels == 2) { + if (input[stream_ptr] > 6) + mp_msg(MSGT_DECAUDIO, MSGL_WARN, + "MS ADPCM: coefficient (%d) out of range (should be [0..6])\n", + input[stream_ptr]); coeff1[1] = ms_adapt_coeff1[input[stream_ptr]]; coeff2[1] = ms_adapt_coeff2[input[stream_ptr]]; stream_ptr++; @@ -267,49 +276,71 @@ int ms_adpcm_decode_block(unsigned short *output, unsigned char *input, return (block_size - (MS_ADPCM_PREAMBLE_SIZE * channels)) * 2; } -// note: This decoder assumes the format 0x61 data always comes in -// mono flavor -int fox61_adpcm_decode_block(unsigned short *output, unsigned char *input) +int dk4_adpcm_decode_block(unsigned short *output, unsigned char *input, + int channels, int block_size) { int i; - int predictor; - int index; + int output_ptr; + int predictor_l = 0; + int predictor_r = 0; + int index_l = 0; + int index_r = 0; // the first predictor value goes straight to the output - predictor = output[0] = LE_16(&input[0]); - SE_16BIT(predictor); - index = input[2]; - - // unpack the nibbles - for (i = 4; i < FOX61_ADPCM_BLOCK_SIZE; i++) + predictor_l = output[0] = LE_16(&input[0]); + SE_16BIT(predictor_l); + index_l = input[2]; + if (channels == 2) { - output[1 + (i - 4) * 2 + 0] = (input[i] >> 4) & 0x0F; - output[1 + (i - 4) * 2 + 1] = input[i] & 0x0F; + predictor_r = output[1] = LE_16(&input[4]); + SE_16BIT(predictor_r); + index_r = input[6]; } - decode_nibbles(&output[1], FOX61_ADPCM_SAMPLES_PER_BLOCK - 1, 1, - predictor, index, - 0, 0); + output_ptr = channels; + for (i = DK4_ADPCM_PREAMBLE_SIZE * channels; i < block_size; i++) + { + output[output_ptr++] = input[i] >> 4; + output[output_ptr++] = input[i] & 0x0F; + } + + decode_nibbles(&output[channels], + (block_size - DK4_ADPCM_PREAMBLE_SIZE * channels) * 2 - channels, + channels, + predictor_l, index_l, + predictor_r, index_r); - return FOX61_ADPCM_SAMPLES_PER_BLOCK; + return (block_size - DK4_ADPCM_PREAMBLE_SIZE * channels) * 2 - channels; } +#define DK3_GET_NEXT_NIBBLE() \ + if (decode_top_nibble_next) \ + { \ + nibble = (last_byte >> 4) & 0x0F; \ + decode_top_nibble_next = 0; \ + } \ + else \ + { \ + last_byte = input[in_ptr++]; \ + nibble = last_byte & 0x0F; \ + decode_top_nibble_next = 1; \ + } + // note: This decoder assumes the format 0x62 data always comes in // stereo flavor -int fox62_adpcm_decode_block(unsigned short *output, unsigned char *input) +int dk3_adpcm_decode_block(unsigned short *output, unsigned char *input) { - int pred1; - int pred2; - int index1; - int index2; + int sum_pred; + int diff_pred; + int sum_index; + int diff_index; + int diff_channel; int in_ptr = 0x10; int out_ptr = 0; - int flag1 = 0; - int flag2 = 1; - int sum; unsigned char last_byte = 0; unsigned char nibble; + int decode_top_nibble_next = 0; // ADPCM work variables int sign; @@ -317,137 +348,93 @@ int fox62_adpcm_decode_block(unsigned short *output, unsigned char *input) int step; int diff; - pred1 = LE_16(&input[10]); - pred2 = LE_16(&input[12]); - SE_16BIT(pred1); - SE_16BIT(pred2); - sum = pred2; - index1 = input[14]; - index2 = input[15]; + sum_pred = LE_16(&input[10]); + diff_pred = LE_16(&input[12]); + SE_16BIT(sum_pred); + SE_16BIT(diff_pred); + diff_channel = diff_pred; + sum_index = input[14]; + diff_index = input[15]; while (in_ptr < 2048) { - if (flag2) - { - last_byte = input[in_ptr++]; - nibble = last_byte & 0x0F; - - step = adpcm_step[index1]; - - sign = nibble & 8; - delta = nibble & 7; - - diff = step >> 3; - if (delta & 4) diff += step; - if (delta & 2) diff += step >> 1; - if (delta & 1) diff += step >> 2; - - if (sign) - pred1 -= diff; - else - pred1 += diff; - - CLAMP_S16(pred1); + // process the first predictor of the sum channel + DK3_GET_NEXT_NIBBLE(); - index1 += adpcm_index[nibble]; - CLAMP_0_TO_88(index1); + step = adpcm_step[sum_index]; - if (flag1) - flag2 = 0; - else - { - nibble = (last_byte >> 4) & 0x0F; + sign = nibble & 8; + delta = nibble & 7; - step = adpcm_step[index2]; + diff = step >> 3; + if (delta & 4) diff += step; + if (delta & 2) diff += step >> 1; + if (delta & 1) diff += step >> 2; - sign = nibble & 8; - delta = nibble & 7; + if (sign) + sum_pred -= diff; + else + sum_pred += diff; - diff = step >> 3; - if (delta & 4) diff += step; - if (delta & 2) diff += step >> 1; - if (delta & 1) diff += step >> 2; + CLAMP_S16(sum_pred); - if (sign) - pred2 -= diff; - else - pred2 += diff; + sum_index += adpcm_index[nibble]; + CLAMP_0_TO_88(sum_index); + + // process the diff channel predictor + DK3_GET_NEXT_NIBBLE(); - CLAMP_S16(pred2); + step = adpcm_step[diff_index]; - index2 += adpcm_index[nibble]; - CLAMP_0_TO_88(index2); + sign = nibble & 8; + delta = nibble & 7; - sum = (sum + pred2) / 2; - } - output[out_ptr++] = pred1 + sum; - output[out_ptr++] = pred1 - sum; + diff = step >> 3; + if (delta & 4) diff += step; + if (delta & 2) diff += step >> 1; + if (delta & 1) diff += step >> 2; - flag1 ^= 1; - if (in_ptr >= 2048) - break; - } + if (sign) + diff_pred -= diff; else - { - nibble = (last_byte >> 4) & 0x0F; - - step = adpcm_step[index1]; - - sign = nibble & 8; - delta = nibble & 7; + diff_pred += diff; - diff = step >> 3; - if (delta & 4) diff += step; - if (delta & 2) diff += step >> 1; - if (delta & 1) diff += step >> 2; + CLAMP_S16(diff_pred); - if (sign) - pred1 -= diff; - else - pred1 += diff; + diff_index += adpcm_index[nibble]; + CLAMP_0_TO_88(diff_index); - CLAMP_S16(pred1); + // output the first pair of stereo PCM samples + diff_channel = (diff_channel + diff_pred) / 2; + output[out_ptr++] = sum_pred + diff_channel; + output[out_ptr++] = sum_pred - diff_channel; - index1 += adpcm_index[nibble]; - CLAMP_0_TO_88(index1); + // process the second predictor of the sum channel + DK3_GET_NEXT_NIBBLE(); - if (flag1) - flag2 = 1; - else - { - last_byte = input[in_ptr++]; - nibble = last_byte & 0x0F; + step = adpcm_step[sum_index]; - step = adpcm_step[index2]; + sign = nibble & 8; + delta = nibble & 7; - sign = nibble & 8; - delta = nibble & 7; + diff = step >> 3; + if (delta & 4) diff += step; + if (delta & 2) diff += step >> 1; + if (delta & 1) diff += step >> 2; - diff = step >> 3; - if (delta & 4) diff += step; - if (delta & 2) diff += step >> 1; - if (delta & 1) diff += step >> 2; - - if (sign) - pred2 -= diff; - else - pred2 += diff; - - CLAMP_S16(pred2); - - index2 += adpcm_index[nibble]; - CLAMP_0_TO_88(index2); + if (sign) + sum_pred -= diff; + else + sum_pred += diff; - sum = (sum + pred2) / 2; - } + CLAMP_S16(sum_pred); - output[out_ptr++] = pred1 + sum; - output[out_ptr++] = pred1 - sum; + sum_index += adpcm_index[nibble]; + CLAMP_0_TO_88(sum_index); - flag1 ^= 1; - if (in_ptr >= 2048) - break; - } + // output the second pair of stereo PCM samples + output[out_ptr++] = sum_pred + diff_channel; + output[out_ptr++] = sum_pred - diff_channel; } return out_ptr; |