changeset 4854:4a6dde59834c

fixed, strengthened, rewrote, and renamed a variety of the ADPCM decoders (including MS, DK4 and DK3 ADPCM)
author melanson
date Mon, 25 Feb 2002 02:48:37 +0000
parents 2853640cea58
children f7f847e2d7c2
files adpcm.c adpcm.h codec-cfg.c codec-cfg.h dec_audio.c etc/codecs.conf
diffstat 6 files changed, 165 insertions(+), 174 deletions(-) [+]
line wrap: on
line diff
--- a/adpcm.c	Mon Feb 25 02:05:30 2002 +0000
+++ b/adpcm.c	Mon Feb 25 02:48:37 2002 +0000
@@ -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 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 @@
   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 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;
+    // process the first predictor of the sum channel
+    DK3_GET_NEXT_NIBBLE();
 
-      step = adpcm_step[index1];
+    step = adpcm_step[sum_index];
 
-      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)
-        pred1 -= diff;
-      else
-        pred1 += diff;
-
-      CLAMP_S16(pred1);
-
-      index1 += adpcm_index[nibble];
-      CLAMP_0_TO_88(index1);
+    if (sign)
+      sum_pred -= diff;
+    else
+      sum_pred += diff;
 
-      if (flag1)
-        flag2 = 0;
-      else
-      {
-        nibble = (last_byte >> 4) & 0x0F;
-
-        step = adpcm_step[index2];
+    CLAMP_S16(sum_pred);
 
-        sign = nibble & 8;
-        delta = nibble & 7;
+    sum_index += adpcm_index[nibble];
+    CLAMP_0_TO_88(sum_index);
+    
+    // process the diff channel predictor
+    DK3_GET_NEXT_NIBBLE();
 
-        diff = step >> 3;
-        if (delta & 4) diff += step;
-        if (delta & 2) diff += step >> 1;
-        if (delta & 1) diff += step >> 2;
+    step = adpcm_step[diff_index];
 
-        if (sign)
-          pred2 -= diff;
-        else
-          pred2 += diff;
-
-        CLAMP_S16(pred2);
-
-        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];
+      diff_pred += diff;
 
-      sign = nibble & 8;
-      delta = nibble & 7;
+    CLAMP_S16(diff_pred);
 
-      diff = step >> 3;
-      if (delta & 4) diff += step;
-      if (delta & 2) diff += step >> 1;
-      if (delta & 1) diff += step >> 2;
+    diff_index += adpcm_index[nibble];
+    CLAMP_0_TO_88(diff_index);
 
-      if (sign)
-        pred1 -= diff;
-      else
-        pred1 += diff;
-
-      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;
-
-        if (sign)
-          pred2 -= diff;
-        else
-          pred2 += diff;
+    diff = step >> 3;
+    if (delta & 4) diff += step;
+    if (delta & 2) diff += step >> 1;
+    if (delta & 1) diff += step >> 2;
 
-        CLAMP_S16(pred2);
+    if (sign)
+      sum_pred -= diff;
+    else
+      sum_pred += diff;
 
-        index2 += adpcm_index[nibble];
-        CLAMP_0_TO_88(index2);
-
-        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;
--- a/adpcm.h	Mon Feb 25 02:05:30 2002 +0000
+++ b/adpcm.h	Mon Feb 25 02:48:37 2002 +0000
@@ -10,21 +10,22 @@
 #define MS_ADPCM_SAMPLES_PER_BLOCK \
   ((sh_audio->wf->nBlockAlign - MS_ADPCM_PREAMBLE_SIZE) * 2)
 
-#define FOX61_ADPCM_PREAMBLE_SIZE 4
-#define FOX61_ADPCM_BLOCK_SIZE 0x200
-#define FOX61_ADPCM_SAMPLES_PER_BLOCK \
-  (((FOX61_ADPCM_BLOCK_SIZE - FOX61_ADPCM_PREAMBLE_SIZE) * 2) + 1)
+#define DK4_ADPCM_PREAMBLE_SIZE 4
+#define DK4_ADPCM_SAMPLES_PER_BLOCK \
+  (((sh_audio->wf->nBlockAlign - DK4_ADPCM_PREAMBLE_SIZE) * 2) + 1)
 
 // pretend there's such a thing as mono for this format
-#define FOX62_ADPCM_PREAMBLE_SIZE 8
-#define FOX62_ADPCM_BLOCK_SIZE 0x400
+#define DK3_ADPCM_PREAMBLE_SIZE 8
+#define DK3_ADPCM_BLOCK_SIZE 0x400
 // this isn't exact
-#define FOX62_ADPCM_SAMPLES_PER_BLOCK 6000
+#define DK3_ADPCM_SAMPLES_PER_BLOCK 6000
 
 int ima_adpcm_decode_block(unsigned short *output, unsigned char *input,
   int channels);
 int ms_adpcm_decode_block(unsigned short *output, unsigned char *input,
   int channels, int block_size);
-int fox61_adpcm_decode_block(unsigned short *output, unsigned char *input);
-int fox62_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 dk3_adpcm_decode_block(unsigned short *output, unsigned char *input);
+
 #endif
--- a/codec-cfg.c	Mon Feb 25 02:05:30 2002 +0000
+++ b/codec-cfg.c	Mon Feb 25 02:48:37 2002 +0000
@@ -224,8 +224,8 @@
 		"liba52",
 		"g72x",
 		"imaadpcm",
-		"fox61adpcm",
-		"fox62adpcm",
+		"dk4adpcm",
+		"dk3adpcm",
 		"roqaudio",
 		NULL
 	};
--- a/codec-cfg.h	Mon Feb 25 02:05:30 2002 +0000
+++ b/codec-cfg.h	Mon Feb 25 02:48:37 2002 +0000
@@ -35,8 +35,8 @@
 #define AFM_A52 14
 #define AFM_G72X 15
 #define AFM_IMAADPCM 16
-#define AFM_FOX61ADPCM 17
-#define AFM_FOX62ADPCM 18
+#define AFM_DK4ADPCM 17
+#define AFM_DK3ADPCM 18
 #define AFM_ROQAUDIO 19
 
 #define VFM_MPEG 1
--- a/dec_audio.c	Mon Feb 25 02:05:30 2002 +0000
+++ b/dec_audio.c	Mon Feb 25 02:48:37 2002 +0000
@@ -425,21 +425,21 @@
   sh_audio->ds->ss_div = MS_ADPCM_SAMPLES_PER_BLOCK;
   sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign;
   break;
-case AFM_FOX61ADPCM:
-  sh_audio->audio_out_minsize=FOX61_ADPCM_SAMPLES_PER_BLOCK * 4;
-  sh_audio->ds->ss_div=FOX61_ADPCM_SAMPLES_PER_BLOCK;
-  sh_audio->ds->ss_mul=FOX61_ADPCM_BLOCK_SIZE;
+case AFM_DK4ADPCM:
+  sh_audio->audio_out_minsize=DK4_ADPCM_SAMPLES_PER_BLOCK * 4;
+  sh_audio->ds->ss_div=DK4_ADPCM_SAMPLES_PER_BLOCK;
+  sh_audio->ds->ss_mul=sh_audio->wf->nBlockAlign;
   break;
-case AFM_FOX62ADPCM:
-  sh_audio->audio_out_minsize=FOX62_ADPCM_SAMPLES_PER_BLOCK * 4;
-  sh_audio->ds->ss_div=FOX62_ADPCM_SAMPLES_PER_BLOCK;
-  sh_audio->ds->ss_mul=FOX62_ADPCM_BLOCK_SIZE;
+case AFM_DK3ADPCM:
+  sh_audio->audio_out_minsize=DK3_ADPCM_SAMPLES_PER_BLOCK * 4;
+  sh_audio->ds->ss_div=DK3_ADPCM_SAMPLES_PER_BLOCK;
+  sh_audio->ds->ss_mul=DK3_ADPCM_BLOCK_SIZE;
   break;
 case AFM_ROQAUDIO:
   // minsize was stored in wf->nBlockAlign by the RoQ demuxer
   sh_audio->audio_out_minsize=sh_audio->wf->nBlockAlign;
-  sh_audio->ds->ss_div=FOX62_ADPCM_SAMPLES_PER_BLOCK;
-  sh_audio->ds->ss_mul=FOX62_ADPCM_BLOCK_SIZE;
+  sh_audio->ds->ss_div=DK3_ADPCM_SAMPLES_PER_BLOCK;
+  sh_audio->ds->ss_mul=DK3_ADPCM_BLOCK_SIZE;
   sh_audio->context = roq_decode_audio_init();
   break;
 case AFM_MPEG:
@@ -724,17 +724,17 @@
   sh_audio->i_bps = sh_audio->wf->nBlockAlign *
     (sh_audio->channels*sh_audio->samplerate) / MS_ADPCM_SAMPLES_PER_BLOCK;
   break;
-case AFM_FOX61ADPCM:
+case AFM_DK4ADPCM:
   sh_audio->channels=sh_audio->wf->nChannels;
   sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
-  sh_audio->i_bps=FOX61_ADPCM_BLOCK_SIZE*
-    (sh_audio->channels*sh_audio->samplerate) / FOX61_ADPCM_SAMPLES_PER_BLOCK;
+  sh_audio->i_bps = sh_audio->wf->nBlockAlign *
+    (sh_audio->channels*sh_audio->samplerate) / DK4_ADPCM_SAMPLES_PER_BLOCK;
   break;
-case AFM_FOX62ADPCM:
+case AFM_DK3ADPCM:
   sh_audio->channels=sh_audio->wf->nChannels;
   sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
-  sh_audio->i_bps=FOX62_ADPCM_BLOCK_SIZE*
-    (sh_audio->channels*sh_audio->samplerate) / FOX62_ADPCM_SAMPLES_PER_BLOCK;
+  sh_audio->i_bps=DK3_ADPCM_BLOCK_SIZE*
+    (sh_audio->channels*sh_audio->samplerate) / DK3_ADPCM_SAMPLES_PER_BLOCK;
   break;
 case AFM_ROQAUDIO:
   sh_audio->channels=sh_audio->wf->nChannels;
@@ -1163,21 +1163,24 @@
           sh_audio->wf->nBlockAlign);
         break;
       }
-      case AFM_FOX61ADPCM:
-      { unsigned char ibuf[FOX61_ADPCM_BLOCK_SIZE]; // bytes / stereo frame
-        if (demux_read_data(sh_audio->ds, ibuf, FOX61_ADPCM_BLOCK_SIZE) != 
-          FOX61_ADPCM_BLOCK_SIZE)
+      case AFM_DK4ADPCM:
+      { static unsigned char *ibuf = NULL;
+        if (!ibuf)
+          ibuf = (unsigned char *)malloc(sh_audio->wf->nBlockAlign);
+        if (demux_read_data(sh_audio->ds, ibuf, sh_audio->wf->nBlockAlign) != 
+          sh_audio->wf->nBlockAlign)
           break; // EOF
-        len=2*fox61_adpcm_decode_block((unsigned short*)buf,ibuf);
+        len=2*dk4_adpcm_decode_block((unsigned short*)buf,ibuf,
+          sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign);
         break;
       }
-      case AFM_FOX62ADPCM:
-      { unsigned char ibuf[FOX62_ADPCM_BLOCK_SIZE * 2]; // bytes / stereo frame
+      case AFM_DK3ADPCM:
+      { unsigned char ibuf[DK3_ADPCM_BLOCK_SIZE * 2]; // bytes / stereo frame
         if (demux_read_data(sh_audio->ds, ibuf,
-          FOX62_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) != 
-          FOX62_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) 
+          DK3_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) != 
+          DK3_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) 
           break; // EOF
-        len = 2 * fox62_adpcm_decode_block(
+        len = 2 * dk3_adpcm_decode_block(
           (unsigned short*)buf,ibuf);
         break;
       }
--- a/etc/codecs.conf	Mon Feb 25 02:05:30 2002 +0000
+++ b/etc/codecs.conf	Mon Feb 25 02:48:37 2002 +0000
@@ -384,19 +384,19 @@
   format 0x2
   driver msadpcm
 
-audiocodec fox61adpcm
+audiocodec dk4adpcm
   info "Duck DK4 ADPCM (rogue format number)"
   status working
   comment "This format number was used by Duck Corp. but not officially registered with Microsoft"
   format 0x61
-  driver fox61adpcm
+  driver dk4adpcm
 
-audiocodec fox62adpcm
+audiocodec dk3adpcm
   info "Duck DK3 ADPCM (rogue format number)"
   status working
   comment "This format number was used by Duck Corp. but not officially registered with Microsoft"
   format 0x62
-  driver fox62adpcm
+  driver dk3adpcm
 
 audiocodec roqaudio
   info "Id RoQ File Audio Decoder"