Commit b3bfb299 authored by Mike Melanson's avatar Mike Melanson

Creative ADPCM decoder, format 0x200, courtesy of Konstantin Shishkov

Originally committed as revision 3589 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 8bcb147f
......@@ -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:
......
......@@ -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
......
......@@ -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
......@@ -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
......
......@@ -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
......
......@@ -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 },
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment