changeset 5408:f9cd6381e327

reworked ADPCM decoders; changes include: * fixed MS IMA ADPCM * dissolved adpcm.c/.h into appropriate ad_* decoders * DK4 audio is handled directly by IMA ADPCM decoder (this obsoletes ad_dk4adpcm.c)
author melanson
date Sat, 30 Mar 2002 22:27:45 +0000
parents e7034890adc5
children 05424017e0f2
files adpcm.c adpcm.h etc/codecs.conf libmpcodecs/Makefile libmpcodecs/ad.c libmpcodecs/ad_dk3adpcm.c libmpcodecs/ad_imaadpcm.c libmpcodecs/ad_msadpcm.c
diffstat 8 files changed, 749 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/adpcm.c	Sat Mar 30 19:25:11 2002 +0000
+++ b/adpcm.c	Sat Mar 30 22:27:45 2002 +0000
@@ -9,6 +9,7 @@
     (C) 2001 Mike Melanson
 */
 
+#if 0
 #include "config.h"
 #include "bswap.h"
 #include "adpcm.h"
@@ -119,7 +120,7 @@
   }
 }
 
-int ima_adpcm_decode_block(unsigned short *output, unsigned char *input,
+int qt_ima_adpcm_decode_block(unsigned short *output, unsigned char *input,
   int channels)
 {
   int initial_predictor_l = 0;
@@ -180,6 +181,67 @@
   return IMA_ADPCM_SAMPLES_PER_BLOCK * channels;
 }
 
+int ms_ima_adpcm_decode_block(unsigned short *output, unsigned char *input,
+  int channels, int block_size)
+{
+  int initial_predictor_l = 0;
+  int initial_predictor_r = 0;
+  int initial_index_l = 0;
+  int initial_index_r = 0;
+  int i;
+
+  initial_predictor_l = BE_16(&input[0]);
+  initial_index_l = initial_predictor_l;
+
+  // mask, sign-extend, and clamp the predictor portion
+  initial_predictor_l &= 0xFF80;
+  SE_16BIT(initial_predictor_l);
+  CLAMP_S16(initial_predictor_l);
+
+  // mask and clamp the index portion
+  initial_index_l &= 0x7F;
+  CLAMP_0_TO_88(initial_index_l);
+
+  // handle stereo
+  if (channels > 1)
+  {
+    initial_predictor_r = BE_16(&input[IMA_ADPCM_BLOCK_SIZE]);
+    initial_index_r = initial_predictor_r;
+
+    // mask, sign-extend, and clamp the predictor portion
+    initial_predictor_r &= 0xFF80;
+    SE_16BIT(initial_predictor_r);
+    CLAMP_S16(initial_predictor_r);
+
+    // mask and clamp the index portion
+    initial_index_r &= 0x7F;
+    CLAMP_0_TO_88(initial_index_r);
+  }
+
+  // break apart all of the nibbles in the block
+  if (channels == 1)
+    for (i = 0; i < IMA_ADPCM_SAMPLES_PER_BLOCK / 2; i++)
+    {
+      output[i * 2 + 0] = input[2 + i] & 0x0F;
+      output[i * 2 + 1] = input[2 + i] >> 4;
+    }  
+  else
+    for (i = 0; i < IMA_ADPCM_SAMPLES_PER_BLOCK / 2 * 2; i++)
+    {
+      output[i * 4 + 0] = input[2 + i] & 0x0F;
+      output[i * 4 + 1] = input[2 + IMA_ADPCM_BLOCK_SIZE + i] & 0x0F;
+      output[i * 4 + 2] = input[2 + i] >> 4;
+      output[i * 4 + 3] = input[2 + IMA_ADPCM_BLOCK_SIZE + i] >> 4;
+    }  
+
+  decode_nibbles(output,
+    IMA_ADPCM_SAMPLES_PER_BLOCK * channels, channels,
+    initial_predictor_l, initial_index_l,
+    initial_predictor_r, initial_index_r);
+
+  return IMA_ADPCM_SAMPLES_PER_BLOCK * channels;
+}
+
 int ms_adpcm_decode_block(unsigned short *output, unsigned char *input,
   int channels, int block_size)
 {
@@ -439,3 +501,5 @@
 
   return out_ptr;
 }
+#endif
+
--- a/adpcm.h	Sat Mar 30 19:25:11 2002 +0000
+++ b/adpcm.h	Sat Mar 30 22:27:45 2002 +0000
@@ -20,8 +20,10 @@
 // this isn't exact
 #define DK3_ADPCM_SAMPLES_PER_BLOCK 6000
 
-int ima_adpcm_decode_block(unsigned short *output, unsigned char *input,
+int qt_ima_adpcm_decode_block(unsigned short *output, unsigned char *input,
   int channels);
+int ms_ima_adpcm_decode_block(unsigned short *output, unsigned char *input,
+  int channels, int block_size);
 int ms_adpcm_decode_block(unsigned short *output, unsigned char *input,
   int channels, int block_size);
 int dk4_adpcm_decode_block(unsigned short *output, unsigned char *input,
--- a/etc/codecs.conf	Sat Mar 30 19:25:11 2002 +0000
+++ b/etc/codecs.conf	Sat Mar 30 22:27:45 2002 +0000
@@ -904,7 +904,7 @@
   status working
   comment "This format number was used by Duck Corp. but not officially registered with Microsoft"
   format 0x61
-  driver dk4adpcm
+  driver imaadpcm
 
 audiocodec dk3adpcm
   info "Duck DK3 ADPCM (rogue format number)"
--- a/libmpcodecs/Makefile	Sat Mar 30 19:25:11 2002 +0000
+++ b/libmpcodecs/Makefile	Sat Mar 30 22:27:45 2002 +0000
@@ -3,7 +3,7 @@
 
 LIBNAME = libmpcodecs.a
 
-AUDIO_SRCS=dec_audio.c ad.c ad_a52.c ad_acm.c ad_alaw.c ad_dk3adpcm.c ad_dk4adpcm.c ad_dshow.c ad_dvdpcm.c ad_ffmpeg.c ad_hwac3.c ad_imaadpcm.c ad_mp3.c ad_msadpcm.c ad_pcm.c ad_roqaudio.c ad_msgsm.c ad_faad.c
+AUDIO_SRCS=dec_audio.c ad.c ad_a52.c ad_acm.c ad_alaw.c ad_dk3adpcm.c ad_dshow.c ad_dvdpcm.c ad_ffmpeg.c ad_hwac3.c ad_imaadpcm.c ad_mp3.c ad_msadpcm.c ad_pcm.c ad_roqaudio.c ad_msgsm.c ad_faad.c
 VIDEO_SRCS=dec_video.c vd.c vd_null.c vd_cinepak.c vd_qtrpza.c vd_ffmpeg.c vd_dshow.c vd_vfw.c vd_odivx.c vd_divx4.c vd_raw.c vd_xanim.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_nuv.c vd_libmpeg2.c vd_msrle.c vd_huffyuv.c vd_zlib.c
 
 ifeq ($(PNG),yes)
--- a/libmpcodecs/ad.c	Sat Mar 30 19:25:11 2002 +0000
+++ b/libmpcodecs/ad.c	Sat Mar 30 22:27:45 2002 +0000
@@ -25,7 +25,6 @@
 extern ad_functions_t mpcodecs_ad_alaw;
 extern ad_functions_t mpcodecs_ad_imaadpcm;
 extern ad_functions_t mpcodecs_ad_msadpcm;
-extern ad_functions_t mpcodecs_ad_dk4adpcm;
 extern ad_functions_t mpcodecs_ad_dk3adpcm;
 extern ad_functions_t mpcodecs_ad_roqaudio;
 extern ad_functions_t mpcodecs_ad_dshow;
@@ -47,7 +46,6 @@
   &mpcodecs_ad_alaw,
   &mpcodecs_ad_imaadpcm,
   &mpcodecs_ad_msadpcm,
-  &mpcodecs_ad_dk4adpcm,
   &mpcodecs_ad_dk3adpcm,
   &mpcodecs_ad_roqaudio,
   &mpcodecs_ad_msgsm,
--- a/libmpcodecs/ad_dk3adpcm.c	Sat Mar 30 19:25:11 2002 +0000
+++ b/libmpcodecs/ad_dk3adpcm.c	Sat Mar 30 22:27:45 2002 +0000
@@ -1,8 +1,19 @@
+/*
+    DK3 ADPCM Decoder for MPlayer
+      by Mike Melanson
+
+    This file is responsible for decoding audio data encoded with
+    Duck Corp's DK3 ADPCM algorithm. Details about the data format
+    can be found here:
+      http://www.pcisys.net/~melanson/codecs/
+*/
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "config.h"
+#include "bswap.h"
 #include "ad_internal.h"
 
 static ad_info_t info = 
@@ -17,27 +28,70 @@
 
 LIBAD_EXTERN(dk3adpcm)
 
-#include "adpcm.h"
+#define DK3_ADPCM_PREAMBLE_SIZE 16
+
+#define LE_16(x) (le2me_16(*(unsigned short *)(x)))
+#define LE_32(x) (le2me_32(*(unsigned int *)(x)))
 
-static int init(sh_audio_t *sh_audio)
+// useful macros
+// clamp a number between 0 and 88
+#define CLAMP_0_TO_88(x)  if (x < 0) x = 0; else if (x > 88) x = 88;
+// clamp a number within a signed 16-bit range
+#define CLAMP_S16(x)  if (x < -32768) x = -32768; \
+  else if (x > 32767) x = 32767;
+// clamp a number above 16
+#define CLAMP_ABOVE_16(x)  if (x < 16) x = 16;
+// sign extend a 16-bit value
+#define SE_16BIT(x)  if (x & 0x8000) x -= 0x10000;
+// sign extend a 4-bit value
+#define SE_4BIT(x)  if (x & 0x8) x -= 0x10;
+
+// pertinent tables
+static int adpcm_step[89] =
 {
-  sh_audio->channels=sh_audio->wf->nChannels;
-  sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
-  sh_audio->i_bps=DK3_ADPCM_BLOCK_SIZE*
-    (sh_audio->channels*sh_audio->samplerate) / DK3_ADPCM_SAMPLES_PER_BLOCK;
+  7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+  19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+  50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+  130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+  337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+  876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+  2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+  5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+  15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+static int adpcm_index[16] =
+{
+  -1, -1, -1, -1, 2, 4, 6, 8,
+  -1, -1, -1, -1, 2, 4, 6, 8
+};
+
+static int preinit(sh_audio_t *sh_audio)
+{
+  sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 6;
+  sh_audio->ds->ss_div = 
+    (sh_audio->wf->nBlockAlign - DK3_ADPCM_PREAMBLE_SIZE) * 8 / 3;
+  sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign;
   return 1;
 }
 
-static int preinit(sh_audio_t *sh_audio)
+static int init(sh_audio_t *sh_audio)
 {
-  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;
+  sh_audio->channels = sh_audio->wf->nChannels;
+  sh_audio->samplerate = sh_audio->wf->nSamplesPerSec;
+  sh_audio->i_bps =
+    (sh_audio->ds->ss_mul * sh_audio->samplerate) / sh_audio->ds->ss_div;
+
+  if ((sh_audio->a_in_buffer =
+    (unsigned char *)malloc(sh_audio->ds->ss_mul)) == NULL)
+    return 0;
+
   return 1;
 }
 
-static void uninit(sh_audio_t *sh)
+static void uninit(sh_audio_t *sh_audio)
 {
+  free(sh_audio->a_in_buffer);
 }
 
 static int control(sh_audio_t *sh,int cmd,void* arg, ...)
@@ -46,15 +100,143 @@
   return CONTROL_UNKNOWN;
 }
 
+#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
+static int dk3_adpcm_decode_block(unsigned short *output, unsigned char *input,
+  int block_size)
+{
+  int sum_pred;
+  int diff_pred;
+  int sum_index;
+  int diff_index;
+  int diff_channel;
+  int in_ptr = 0x10;
+  int out_ptr = 0;
+
+  unsigned char last_byte = 0;
+  unsigned char nibble;
+  int decode_top_nibble_next = 0;
+
+  // ADPCM work variables
+  int sign;
+  int delta;
+  int step;
+  int diff;
+
+  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 < block_size)
+//  while (in_ptr < 2048)
+  {
+    // process the first predictor of the sum channel
+    DK3_GET_NEXT_NIBBLE();
+
+    step = adpcm_step[sum_index];
+
+    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)
+      sum_pred -= diff;
+    else
+      sum_pred += diff;
+
+    CLAMP_S16(sum_pred);
+
+    sum_index += adpcm_index[nibble];
+    CLAMP_0_TO_88(sum_index);
+
+    // process the diff channel predictor
+    DK3_GET_NEXT_NIBBLE();
+
+    step = adpcm_step[diff_index];
+
+    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)
+      diff_pred -= diff;
+    else
+      diff_pred += diff;
+
+    CLAMP_S16(diff_pred);
+
+    diff_index += adpcm_index[nibble];
+    CLAMP_0_TO_88(diff_index);
+
+    // 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;
+
+    // process the second predictor of the sum channel
+    DK3_GET_NEXT_NIBBLE();
+
+    step = adpcm_step[sum_index];
+
+    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)
+      sum_pred -= diff;
+    else
+      sum_pred += diff;
+
+    CLAMP_S16(sum_pred);
+
+    sum_index += adpcm_index[nibble];
+    CLAMP_0_TO_88(sum_index);
+
+    // 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;
+}
+
 static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
 {
-  int len=-1;
-   unsigned char ibuf[DK3_ADPCM_BLOCK_SIZE * 2]; /* bytes / stereo frame */
-    if (demux_read_data(sh_audio->ds, ibuf,
-          DK3_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) != 
-          DK3_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) 
-      return len; /* EOF */
-    len = 2 * dk3_adpcm_decode_block(
-          (unsigned short*)buf,ibuf);
-    return len;
+  if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,
+    sh_audio->ds->ss_mul) != 
+    sh_audio->ds->ss_mul) 
+      return -1; /* EOF */
+
+  return 2 * dk3_adpcm_decode_block(
+    (unsigned short*)buf, sh_audio->a_in_buffer,
+    sh_audio->wf->nBlockAlign);
 }
--- a/libmpcodecs/ad_imaadpcm.c	Sat Mar 30 19:25:11 2002 +0000
+++ b/libmpcodecs/ad_imaadpcm.c	Sat Mar 30 22:27:45 2002 +0000
@@ -1,11 +1,71 @@
+/*
+    IMA ADPCM Decoder for MPlayer
+      by Mike Melanson
+
+    This file is in charge of decoding all of the various IMA ADPCM data
+    formats that various entities have created. Details about the data
+    formats can be found here:
+      http://www.pcisys.net/~melanson/codecs/
+
+    So far, this file handles these formats:
+      'ima4': IMA ADPCM found in QT files
+        0x11: IMA ADPCM found in MS AVI/ASF/WAV files
+        0x61: DK4 ADPCM found in certain AVI files on Sega Saturn CD-ROMs;
+              note that this is a 'rogue' format number in that it was
+              never officially registered with Microsoft
+*/
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "config.h"
+#include "bswap.h"
 #include "ad_internal.h"
 
-#include "../adpcm.h"
+#define MS_IMA_ADPCM_PREAMBLE_SIZE 4
+
+#define QT_IMA_ADPCM_PREAMBLE_SIZE 2
+#define QT_IMA_ADPCM_BLOCK_SIZE 0x22
+#define QT_IMA_ADPCM_SAMPLES_PER_BLOCK 64
+
+#define BE_16(x) (be2me_16(*(unsigned short *)(x)))
+#define BE_32(x) (be2me_32(*(unsigned int *)(x)))
+#define LE_16(x) (le2me_16(*(unsigned short *)(x)))
+#define LE_32(x) (le2me_32(*(unsigned int *)(x)))
+
+// pertinent tables for IMA ADPCM
+static int adpcm_step[89] =
+{
+  7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+  19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+  50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+  130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+  337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+  876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+  2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+  5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+  15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+static int adpcm_index[16] =
+{
+  -1, -1, -1, -1, 2, 4, 6, 8,
+  -1, -1, -1, -1, 2, 4, 6, 8
+};
+
+// useful macros
+// clamp a number between 0 and 88
+#define CLAMP_0_TO_88(x)  if (x < 0) x = 0; else if (x > 88) x = 88;
+// clamp a number within a signed 16-bit range
+#define CLAMP_S16(x)  if (x < -32768) x = -32768; \
+  else if (x > 32767) x = 32767;
+// clamp a number above 16
+#define CLAMP_ABOVE_16(x)  if (x < 16) x = 16;
+// sign extend a 16-bit value
+#define SE_16BIT(x)  if (x & 0x8000) x -= 0x10000;
+// sign extend a 4-bit value
+#define SE_4BIT(x)  if (x & 0x8) x -= 0x10;
 
 static ad_info_t info = 
 {
@@ -14,32 +74,52 @@
 	AFM_IMAADPCM,
 	"Nick Kurshev",
 	"Mike Melanson",
-	"ima4 (MOV files)"
+	""
 };
 
 LIBAD_EXTERN(imaadpcm)
 
+static int preinit(sh_audio_t *sh_audio)
+{
+  // not exactly sure what this field is for
+  sh_audio->audio_out_minsize = 8192;
+
+  // if format is "ima4", assume the audio is coming from a QT file which
+  // indicates constant block size, whereas an AVI/ASF/WAV file will fill
+  // in this field with 0x11
+  if ((sh_audio->format == 0x11) || (sh_audio->format == 0x61))
+  {
+    sh_audio->ds->ss_div = (sh_audio->wf->nBlockAlign - 
+      (MS_IMA_ADPCM_PREAMBLE_SIZE * sh_audio->wf->nChannels)) * 2;
+    sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign;
+  }
+  else
+  {
+    sh_audio->ds->ss_div = QT_IMA_ADPCM_SAMPLES_PER_BLOCK;
+    sh_audio->ds->ss_mul = QT_IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels;
+  }
+  return 1;
+}
+
 static int init(sh_audio_t *sh_audio)
 {
   /* IMA-ADPCM 4:1 audio codec:*/
   sh_audio->channels=sh_audio->wf->nChannels;
   sh_audio->samplerate=sh_audio->wf->nSamplesPerSec;
   /* decodes 34 byte -> 64 short*/
-  sh_audio->i_bps=IMA_ADPCM_BLOCK_SIZE*(sh_audio->channels*sh_audio->samplerate)/
-		  IMA_ADPCM_SAMPLES_PER_BLOCK;  /* 1:4 */
+  sh_audio->i_bps = 
+    (sh_audio->ds->ss_mul * sh_audio->samplerate) / sh_audio->ds->ss_div;
+
+  if ((sh_audio->a_in_buffer =
+    (unsigned char *)malloc(sh_audio->ds->ss_mul)) == NULL)
+    return 0;
+
   return 1;
 }
 
-static int preinit(sh_audio_t *sh_audio)
+static void uninit(sh_audio_t *sh_audio)
 {
-  sh_audio->audio_out_minsize=4096;
-  sh_audio->ds->ss_div=IMA_ADPCM_SAMPLES_PER_BLOCK;
-  sh_audio->ds->ss_mul=IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels;
-  return 1;
-}
-
-static void uninit(sh_audio_t *sh)
-{
+  free(sh_audio->a_in_buffer);
 }
 
 static int control(sh_audio_t *sh,int cmd,void* arg, ...)
@@ -48,12 +128,247 @@
   return CONTROL_UNKNOWN;
 }
 
+static void decode_nibbles(unsigned short *output,
+  int output_size, int channels,
+  int predictor_l, int index_l,
+  int predictor_r, int index_r)
+{
+  int step[2];
+  int predictor[2];
+  int index[2];
+  int diff;
+  int i;
+  int sign;
+  int delta;
+  int channel_number = 0;
+
+  step[0] = adpcm_step[index_l];
+  step[1] = adpcm_step[index_r];
+  predictor[0] = predictor_l;
+  predictor[1] = predictor_r;
+  index[0] = index_l;
+  index[1] = index_r;
+
+  for (i = 0; i < output_size; i++)
+  {
+    delta = output[i];
+
+    index[channel_number] += adpcm_index[delta];
+    CLAMP_0_TO_88(index[channel_number]);
+
+    sign = delta & 8;
+    delta = delta & 7;
+
+    diff = step[channel_number] >> 3;
+    if (delta & 4) diff += step[channel_number];
+    if (delta & 2) diff += step[channel_number] >> 1;
+    if (delta & 1) diff += step[channel_number] >> 2;
+
+    if (sign)
+      predictor[channel_number] -= diff;
+    else
+      predictor[channel_number] += diff;
+
+    CLAMP_S16(predictor[channel_number]);
+    output[i] = predictor[channel_number];
+    step[channel_number] = adpcm_step[index[channel_number]];
+
+    // toggle channel
+    channel_number ^= channels - 1;
+
+  }
+}
+
+static int qt_ima_adpcm_decode_block(unsigned short *output,
+  unsigned char *input, int channels)
+{
+  int initial_predictor_l = 0;
+  int initial_predictor_r = 0;
+  int initial_index_l = 0;
+  int initial_index_r = 0;
+  int i;
+
+  initial_predictor_l = BE_16(&input[0]);
+  initial_index_l = initial_predictor_l;
+
+  // mask, sign-extend, and clamp the predictor portion
+  initial_predictor_l &= 0xFF80;
+  SE_16BIT(initial_predictor_l);
+  CLAMP_S16(initial_predictor_l);
+
+  // mask and clamp the index portion
+  initial_index_l &= 0x7F;
+  CLAMP_0_TO_88(initial_index_l);
+
+  // handle stereo
+  if (channels > 1)
+  {
+    initial_predictor_r = BE_16(&input[QT_IMA_ADPCM_BLOCK_SIZE]);
+    initial_index_r = initial_predictor_r;
+
+    // mask, sign-extend, and clamp the predictor portion
+    initial_predictor_r &= 0xFF80;
+    SE_16BIT(initial_predictor_r);
+    CLAMP_S16(initial_predictor_r);
+
+    // mask and clamp the index portion
+    initial_index_r &= 0x7F;
+    CLAMP_0_TO_88(initial_index_r);
+  }
+
+  // break apart all of the nibbles in the block
+  if (channels == 1)
+    for (i = 0; i < QT_IMA_ADPCM_SAMPLES_PER_BLOCK / 2; i++)
+    {
+      output[i * 2 + 0] = input[2 + i] & 0x0F;
+      output[i * 2 + 1] = input[2 + i] >> 4;
+    }
+  else
+    for (i = 0; i < QT_IMA_ADPCM_SAMPLES_PER_BLOCK / 2 * 2; i++)
+    {
+      output[i * 4 + 0] = input[2 + i] & 0x0F;
+      output[i * 4 + 1] = input[2 + QT_IMA_ADPCM_BLOCK_SIZE + i] & 0x0F;
+      output[i * 4 + 2] = input[2 + i] >> 4;
+      output[i * 4 + 3] = input[2 + QT_IMA_ADPCM_BLOCK_SIZE + i] >> 4;
+    }
+
+  decode_nibbles(output,
+    QT_IMA_ADPCM_SAMPLES_PER_BLOCK * channels, channels,
+    initial_predictor_l, initial_index_l,
+    initial_predictor_r, initial_index_r);
+
+  return QT_IMA_ADPCM_SAMPLES_PER_BLOCK * channels;
+}
+
+static int ms_ima_adpcm_decode_block(unsigned short *output,
+  unsigned char *input, int channels, int block_size)
+{
+  int predictor_l = 0;
+  int predictor_r = 0;
+  int index_l = 0;
+  int index_r = 0;
+  int i;
+  int channel_counter;
+  int channel_index;
+  int channel_index_l;
+  int channel_index_r;
+
+  predictor_l = LE_16(&input[0]);
+  SE_16BIT(predictor_l);
+  index_l = input[2];
+  if (channels == 2)
+  {
+    predictor_r = LE_16(&input[4]);
+    SE_16BIT(predictor_r);
+    index_r = input[6];
+  }
+
+  if (channels == 1)
+    for (i = 0;
+      i < (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels) / 2; i++)
+    {
+      output[i * 2 + 0] = input[MS_IMA_ADPCM_PREAMBLE_SIZE + i] & 0x0F;
+      output[i * 2 + 1] = input[MS_IMA_ADPCM_PREAMBLE_SIZE + i] >> 4;
+    }
+  else
+  {
+    // encoded as 8 nibbles (4 bytes) per channel; switch channel every
+    // 4th byte
+    channel_counter = 0;
+    channel_index_l = 0;
+    channel_index_r = 1;
+    channel_index = channel_index_l;
+    for (i = 0;
+      i < (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels); i++)
+    {
+      output[channel_index + 0] =
+        input[MS_IMA_ADPCM_PREAMBLE_SIZE * 2 + i] & 0x0F;
+      output[channel_index + 2] =
+        input[MS_IMA_ADPCM_PREAMBLE_SIZE * 2 + i] >> 4;
+      channel_index += 4;
+      channel_counter++;
+      if (channel_counter == 4)
+      {
+        channel_index_l = channel_index;
+        channel_index = channel_index_r;
+      }
+      else if (channel_counter == 8)
+      {
+        channel_index_r = channel_index;
+        channel_index = channel_index_l;
+        channel_counter = 0;
+      }
+    }
+  }
+  
+  decode_nibbles(output,
+    (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels) * 2,
+    channels,
+    predictor_l, index_l,
+    predictor_r, index_r);
+
+  return (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels) * 2;
+}
+
+static int dk4_ima_adpcm_decode_block(unsigned short *output,
+  unsigned char *input, int channels, int block_size)
+{
+  int i;
+  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_l = output[0] = LE_16(&input[0]);
+  SE_16BIT(predictor_l);
+  index_l = input[2];
+  if (channels == 2)
+  {
+    predictor_r = output[1] = LE_16(&input[4]);
+    SE_16BIT(predictor_r);
+    index_r = input[6];
+  }
+
+  output_ptr = channels;
+  for (i = MS_IMA_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 - MS_IMA_ADPCM_PREAMBLE_SIZE * channels) * 2 - channels,
+    channels,
+    predictor_l, index_l,
+    predictor_r, index_r);
+
+  return (block_size - MS_IMA_ADPCM_PREAMBLE_SIZE * channels) * 2 - channels;
+}
+
 static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
 {
-    unsigned char ibuf[IMA_ADPCM_BLOCK_SIZE * 2]; /* bytes / stereo frame */
-    if (demux_read_data(sh_audio->ds, ibuf,
-      IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) != 
-      IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) 
-	return -1;
-    return 2*ima_adpcm_decode_block((unsigned short*)buf,ibuf, sh_audio->wf->nChannels);
+  if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,
+    sh_audio->ds->ss_mul) != 
+    sh_audio->ds->ss_mul) 
+    return -1;
+
+  if (sh_audio->format == 0x11)
+  {
+    return 2 * ms_ima_adpcm_decode_block(
+      (unsigned short*)buf, sh_audio->a_in_buffer, sh_audio->wf->nChannels,
+      sh_audio->ds->ss_mul);
+  }
+  else if (sh_audio->format == 0x61)
+  {
+    return 2 * dk4_ima_adpcm_decode_block(
+      (unsigned short*)buf, sh_audio->a_in_buffer, sh_audio->wf->nChannels,
+      sh_audio->ds->ss_mul);
+  }
+  else
+  {
+    return 2 * qt_ima_adpcm_decode_block(
+      (unsigned short*)buf, sh_audio->a_in_buffer, sh_audio->wf->nChannels);
+  }
 }
--- a/libmpcodecs/ad_msadpcm.c	Sat Mar 30 19:25:11 2002 +0000
+++ b/libmpcodecs/ad_msadpcm.c	Sat Mar 30 22:27:45 2002 +0000
@@ -1,8 +1,18 @@
+/*
+    MS ADPCM Decoder for MPlayer
+      by Mike Melanson
+
+    This file is responsible for decoding Microsoft ADPCM data.
+    Details about the data format can be found here:
+      http://www.pcisys.net/~melanson/codecs/
+*/
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "config.h"
+#include "bswap.h"
 #include "ad_internal.h"
 
 static ad_info_t info = 
@@ -17,8 +27,40 @@
 
 LIBAD_EXTERN(msadpcm)
 
+static int ms_adapt_table[] =
+{
+  230, 230, 230, 230, 307, 409, 512, 614,
+  768, 614, 512, 409, 307, 230, 230, 230
+};
+
+static int ms_adapt_coeff1[] =
+{
+  256, 512, 0, 192, 240, 460, 392
+};
+
+static int ms_adapt_coeff2[] =
+{
+  0, -256, 0, 64, 0, -208, -232
+};
+
 #define MS_ADPCM_PREAMBLE_SIZE 7
 
+#define LE_16(x) (le2me_16(*(unsigned short *)(x)))
+#define LE_32(x) (le2me_32(*(unsigned int *)(x)))
+
+// useful macros
+// clamp a number between 0 and 88
+#define CLAMP_0_TO_88(x)  if (x < 0) x = 0; else if (x > 88) x = 88;
+// clamp a number within a signed 16-bit range
+#define CLAMP_S16(x)  if (x < -32768) x = -32768; \
+  else if (x > 32767) x = 32767;
+// clamp a number above 16
+#define CLAMP_ABOVE_16(x)  if (x < 16) x = 16;
+// sign extend a 16-bit value
+#define SE_16BIT(x)  if (x & 0x8000) x -= 0x10000;
+// sign extend a 4-bit value
+#define SE_4BIT(x)  if (x & 0x8) x -= 0x10;
+
 static int preinit(sh_audio_t *sh_audio)
 {
   sh_audio->audio_out_minsize = sh_audio->wf->nBlockAlign * 4;
@@ -54,14 +96,110 @@
   return CONTROL_UNKNOWN;
 }
 
+static int ms_adpcm_decode_block(unsigned short *output, unsigned char *input,
+  int channels, int block_size)
+{
+  int current_channel = 0;
+  int idelta[2];
+  int sample1[2];
+  int sample2[2];
+  int coeff1[2];
+  int coeff2[2];
+  int stream_ptr = 0;
+  int out_ptr = 0;
+  int upper_nibble = 1;
+  int nibble;
+  int snibble;  // signed nibble
+  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++;
+  }
+
+  idelta[0] = LE_16(&input[stream_ptr]);
+  stream_ptr += 2;
+  SE_16BIT(idelta[0]);
+  if (channels == 2)
+  {
+    idelta[1] = LE_16(&input[stream_ptr]);
+    stream_ptr += 2;
+    SE_16BIT(idelta[1]);
+  }
+
+  sample1[0] = LE_16(&input[stream_ptr]);
+  stream_ptr += 2;
+  SE_16BIT(sample1[0]);
+  if (channels == 2)
+  {
+    sample1[1] = LE_16(&input[stream_ptr]);
+    stream_ptr += 2;
+    SE_16BIT(sample1[1]);
+  }
+
+  sample2[0] = LE_16(&input[stream_ptr]);
+  stream_ptr += 2;
+  SE_16BIT(sample2[0]);
+  if (channels == 2)
+  {
+    sample2[1] = LE_16(&input[stream_ptr]);
+    stream_ptr += 2;
+    SE_16BIT(sample2[1]);
+  }
+
+  while (stream_ptr < block_size)
+  {
+    // get the next nibble
+    if (upper_nibble)
+      nibble = snibble = input[stream_ptr] >> 4;
+    else
+      nibble = snibble = input[stream_ptr++] & 0x0F;
+    upper_nibble ^= 1;
+    SE_4BIT(snibble);
+
+    predictor = (
+      ((sample1[current_channel] * coeff1[current_channel]) +
+       (sample2[current_channel] * coeff2[current_channel])) / 256) +
+      (snibble * idelta[current_channel]);
+    CLAMP_S16(predictor);
+    sample2[current_channel] = sample1[current_channel];
+    sample1[current_channel] = predictor;
+    output[out_ptr++] = predictor;
+
+    // compute the next adaptive scale factor (a.k.a. the variable idelta)
+    idelta[current_channel] =
+      (ms_adapt_table[nibble] * idelta[current_channel]) / 256;
+    CLAMP_ABOVE_16(idelta[current_channel]);
+
+    // toggle the channel
+    current_channel ^= channels - 1;
+  }
+
+  return (block_size - (MS_ADPCM_PREAMBLE_SIZE * channels)) * 2;
+}
+
 static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
 {
   if (demux_read_data(sh_audio->ds, sh_audio->a_in_buffer,
-      sh_audio->ds->ss_mul) != 
-      sh_audio->ds->ss_mul) 
-         return -1; /* EOF */
+    sh_audio->ds->ss_mul) != 
+    sh_audio->ds->ss_mul) 
+      return -1; /* EOF */
 
   return 2 * ms_adpcm_decode_block(
-          (unsigned short*)buf, sh_audio->a_in_buffer,
-          sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign);
+    (unsigned short*)buf, sh_audio->a_in_buffer,
+    sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign);
 }