]> git.sesse.net Git - ffmpeg/commitdiff
Creative ADPCM decoder, format 0x200, courtesy of Konstantin Shishkov
authorMike Melanson <mike@multimedia.cx>
Tue, 12 Oct 2004 12:47:49 +0000 (12:47 +0000)
committerMike Melanson <mike@multimedia.cx>
Tue, 12 Oct 2004 12:47:49 +0000 (12:47 +0000)
Originally committed as revision 3589 to svn://svn.ffmpeg.org/ffmpeg/trunk

Changelog
doc/ffmpeg-doc.texi
libavcodec/adpcm.c
libavcodec/allcodecs.c
libavcodec/avcodec.h
libavformat/wav.c

index 86b467b36881f687c7c3960e06b1f1a842003cfe..f3c1093ccd3179745c701ecca5a32c8b9444a56e 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -3,6 +3,7 @@ version <next>
 - IBM Ultimotion (ULTI) video decoder
 - Sierra Online audio file demuxer and decoder
 - Apple QuickDraw (qdrw) video decoder
+- Creative ADPCM audio decoder
 
 version 0.4.9-pre1:
 
index d1b80b342c10a199a015ca7dd229b6161a55a842..e3e341256c6eedd025b216ad4fa5aa99dbf46799 100644 (file)
@@ -805,6 +805,7 @@ solutions.
 @tab used in Sega Dreamcast games
 @item Electronic Arts ADPCM  @tab      @tab X
 @tab used in various EA titles
+@item Creative ADPCM         @tab      @tab X
 @item RA144                  @tab      @tab X
 @tab Real 14400 bit/s codec
 @item RA288                  @tab      @tab X
index 0755e24fefaf2148ead8df173fb38b6a7ad94f53..40c2d430ffc5ff902334aa2c60d7909f23734550 100644 (file)
@@ -103,6 +103,11 @@ static int ea_adpcm_table[] = {
     3, 4, 7, 8, 10, 11, 0, -1, -3, -4
 };
 
+static int ct_adpcm_table[8] = {
+    0x00E6, 0x00E6, 0x00E6, 0x00E6,
+    0x0133, 0x0199, 0x0200, 0x0266
+};
+
 /* end of tables */
 
 typedef struct ADPCMChannelStatus {
@@ -361,6 +366,9 @@ static int adpcm_decode_init(AVCodecContext * avctx)
     c->status[0].step = c->status[1].step = 0;
 
     switch(avctx->codec->id) {
+    case CODEC_ID_ADPCM_CT:
+       c->status[0].step = c->status[1].step = 511;
+       break;
     default:
         break;
     }
@@ -411,6 +419,37 @@ static inline short adpcm_ms_expand_nibble(ADPCMChannelStatus *c, char nibble)
     return (short)predictor;
 }
 
+static inline short adpcm_ct_expand_nibble(ADPCMChannelStatus *c, char nibble)
+{
+    int predictor;
+    int sign, delta, diff;
+    int new_step;
+
+    sign = nibble & 8;
+    delta = nibble & 7;
+    /* perform direct multiplication instead of series of jumps proposed by
+     * the reference ADPCM implementation since modern CPUs can do the mults
+     * quickly enough */
+    diff = ((2 * delta + 1) * c->step) >> 3;
+    predictor = c->predictor;
+    /* predictor update is not so trivial: predictor is multiplied on 254/256 before updating */
+    if(sign)
+       predictor = ((predictor * 254) >> 8) - diff;
+    else
+       predictor = ((predictor * 254) >> 8) + diff;
+    /* calculate new step and clamp it to range 511..32767 */
+    new_step = (ct_adpcm_table[nibble & 7] * c->step) >> 8;
+    c->step = new_step;
+    if(c->step < 511)
+       c->step = 511;
+    if(c->step > 32767)
+       c->step = 32767;
+
+    CLAMP_TO_SHORT(predictor);
+    c->predictor = predictor;
+    return (short)predictor;
+}
+
 static void xa_decode(short *out, const unsigned char *in, 
     ADPCMChannelStatus *left, ADPCMChannelStatus *right, int inc)
 {
@@ -840,6 +879,22 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
             src++;
         }
         break;
+    case CODEC_ID_ADPCM_CT:
+       while (src < buf + buf_size) {
+            if (st) {
+                *samples++ = adpcm_ct_expand_nibble(&c->status[0], 
+                    (src[0] >> 4) & 0x0F);
+                *samples++ = adpcm_ct_expand_nibble(&c->status[1], 
+                    src[0] & 0x0F);
+            } else {
+                *samples++ = adpcm_ct_expand_nibble(&c->status[0], 
+                    (src[0] >> 4) & 0x0F);
+                *samples++ = adpcm_ct_expand_nibble(&c->status[0], 
+                    src[0] & 0x0F);
+            }
+           src++;
+        }
+        break;
     default:
         return -1;
     }
@@ -895,5 +950,6 @@ ADPCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm);
 ADPCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
 ADPCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
 ADPCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
+ADPCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
 
 #undef ADPCM_CODEC
index f6ab7d9e1cc60359bca7d42bf2e5d6c7f590bacb..b9228c162f1481b000a121cf7a26aa42b0ca4228 100644 (file)
@@ -223,6 +223,7 @@ PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
 PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
 PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
 PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726);
+PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
 
 #undef PCM_CODEC
 
index 6fb667e96046792e70e38b645e150eb8d6c891b6..a1888faf2c0d2d1728a8aac89f7e199ea8202b2b 100644 (file)
@@ -128,6 +128,7 @@ enum CodecID {
     CODEC_ID_ADPCM_ADX,
     CODEC_ID_ADPCM_EA,
     CODEC_ID_ADPCM_G726,
+    CODEC_ID_ADPCM_CT,
 
        /* AMR */
     CODEC_ID_AMR_NB,
@@ -1916,6 +1917,7 @@ PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
 PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
 PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
 PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726);
+PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
 
 #undef PCM_CODEC
 
index 0bc3c3408be7bd0e11ebd2981096b5def7877ed9..50d8593ff32bb5049319c16e8b73e8082a8ededd 100644 (file)
@@ -38,6 +38,7 @@ const CodecTag codec_wav_tags[] = {
     { CODEC_ID_VORBIS, ('V'<<8)+'o' }, //HACK/FIXME, does vorbis in WAV/AVI have an (in)official id?
     { CODEC_ID_SONIC, 0x2048 },
     { CODEC_ID_SONIC_LS, 0x2048 },
+    { CODEC_ID_ADPCM_CT, 0x200 },
     { 0, 0 },
 };