]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/nellymoserdec.c
fix adpcm ima qt decoding, channel at init is 0, correct stereo out since samples...
[ffmpeg] / libavcodec / nellymoserdec.c
index bf955a2734355ca11d65252f2286a26a54c9d108..470465d9d285a22ca195d5aba129c608ee3e296b 100644 (file)
@@ -46,7 +46,7 @@
 #define NELLY_BIT_CAP     6
 #define NELLY_BASE_OFF    4228
 #define NELLY_BASE_SHIFT  19
-#define NELLY_SAMPLES     256
+#define NELLY_SAMPLES     (2 * NELLY_BUF_LEN)
 
 static const float dequantization_table[127] = {
 0.0000000000,-0.8472560048, 0.7224709988, -1.5247479677, -0.4531480074, 0.3753609955, 1.4717899561,
@@ -91,21 +91,19 @@ static const int16_t nelly_delta_table[32] = {
 
 typedef struct NellyMoserDecodeContext {
     AVCodecContext* avctx;
-    float           float_buf[NELLY_SAMPLES];
-    float           state[64];
+    DECLARE_ALIGNED_16(float,float_buf[NELLY_SAMPLES]);
+    float           state[128];
     AVRandomState   random_state;
     GetBitContext   gb;
     int             add_bias;
-    int             scale_bias;
+    float           scale_bias;
     DSPContext      dsp;
-    FFTContext      fftc;
+    MDCTContext     imdct_ctx;
+    DECLARE_ALIGNED_16(float,imdct_tmp[NELLY_BUF_LEN]);
+    DECLARE_ALIGNED_16(float,imdct_out[NELLY_BUF_LEN * 2]);
 } NellyMoserDecodeContext;
 
-
-DECLARE_ALIGNED_16(float,sine_window[128]);
-DECLARE_ALIGNED_16(float,tcos[64]);
-DECLARE_ALIGNED_16(float,tsin[64]);
-DECLARE_ALIGNED_16(float,cos_tab[64]);
+static DECLARE_ALIGNED_16(float,sine_window[128]);
 
 static inline int signed_shift(int i, int shift) {
     if (shift > 0)
@@ -113,95 +111,22 @@ static inline int signed_shift(int i, int shift) {
     return i >> -shift;
 }
 
-static void antialias(float *buf, float *audio)
-{
-    int i, end, mid_hi, mid_lo;
-
-    end = NELLY_BUF_LEN-1;
-    mid_hi = NELLY_BUF_LEN/2;
-    mid_lo = mid_hi-1;
 
-    for (i = 0; i < NELLY_BUF_LEN/4; i++) {
-        audio[2*i]      =   buf[2*i      ]*tcos[i       ] - buf[end-2*i]*tsin[i];
-        audio[2*i+1]    = -(buf[end-2*i  ]*tcos[i       ] + buf[2*i    ]*tsin[i]);
-        audio[end-2*i-1]=   buf[end-2*i-1]*tcos[mid_lo-i] - buf[2*i+1  ]*tsin[mid_lo-i];
-        audio[end-2*i  ]= -(buf[2*i+1    ]*tcos[mid_lo-i] + buf[end-2*i]*tsin[mid_lo-i]);
-    }
-}
-
-static void complex2signal(float *audio)
+static void overlap_and_window(NellyMoserDecodeContext *s, float *state, float *audio, float *a_in)
 {
-    int i, end, mid_hi, mid_lo;
-    float *aptr, *sigptr, a, b, c, d, e, f, g;
-
-    end = NELLY_BUF_LEN-1;
-    mid_hi = NELLY_BUF_LEN/2;
-    mid_lo = mid_hi-1;
-
-    a = -audio[end];
-    b = audio[end-1];
-    c = -audio[1];
-    d = cos_tab[0];
-    e = audio[0];
-    f = cos_tab[mid_lo];
-    g = cos_tab[1];
-
-    audio[0] = d*e;
-    audio[1] = b*g-a*f;
-    audio[end-1] = a*g+b*f;
-    audio[end] = c*(-d);
-
-    aptr = audio+end-2;
-    sigptr = cos_tab+mid_hi-1;
-
-    for (i = 3; i < NELLY_BUF_LEN/2; i += 2) {
-        a = audio[i-1];
-        b = -audio[i];
-        c = cos_tab[i/2];
-        d = *sigptr;
-        e = *(aptr-1);
-        f = -(*aptr);
-
-        audio[i-1] = a*c+b*d;
-        *aptr = a*d-b*c;
-
-        a = cos_tab[(i/2)+1];
-        b = *(sigptr-1);
-
-        *(aptr-1) = b*e+a*f;
-        audio[i] = a*e-b*f;
-
-        sigptr--;
-        aptr -= 2;
-    }
-}
-
-static void overlap_and_window(NellyMoserDecodeContext *s, float *state, float *audio)
-{
-    int bot, mid_up, mid_down, top;
-    float s_bot, s_top;
+    int bot, top;
 
     bot = 0;
     top = NELLY_BUF_LEN-1;
-    mid_up = NELLY_BUF_LEN/2;
-    mid_down = (NELLY_BUF_LEN/2)-1;
-
-    while (bot < NELLY_BUF_LEN/4) {
-        s_bot = audio[bot];
-        s_top = audio[top];
-        audio[bot] =  (audio[mid_up]*sine_window[bot]-state[bot   ]*sine_window[top])/s->scale_bias + s->add_bias;
-        audio[top] = (-state[bot   ]*sine_window[bot]-audio[mid_up]*sine_window[top])/s->scale_bias + s->add_bias;
-        state[bot] =  audio[mid_down];
 
-        audio[mid_down] =  (s_top          *sine_window[mid_down]-state[mid_down]*sine_window[mid_up])/s->scale_bias + s->add_bias;
-        audio[mid_up  ] = (-state[mid_down]*sine_window[mid_down]-s_top          *sine_window[mid_up])/s->scale_bias + s->add_bias;
-        state[mid_down] =  s_bot;
+    while (bot < NELLY_BUF_LEN) {
+        audio[bot] = a_in [bot]*sine_window[bot]
+                    +state[bot]*sine_window[top] + s->add_bias;
 
         bot++;
-        mid_up++;
-        mid_down--;
         top--;
     }
+    memcpy(state, a_in + NELLY_BUF_LEN, sizeof(float)*NELLY_BUF_LEN);
 }
 
 static int sum_bits(short *buf, short shift, short off)
@@ -229,7 +154,7 @@ static int headroom(int *la)
 }
 
 
-static void get_sample_bits(float *buf, int *bits)
+static void get_sample_bits(const float *buf, int *bits)
 {
     int i, j;
     short sbuf[128];
@@ -339,10 +264,10 @@ static void get_sample_bits(float *buf, int *bits)
     }
 }
 
-void nelly_decode_block(NellyMoserDecodeContext *s, unsigned char block[NELLY_BLOCK_LEN], float audio[NELLY_SAMPLES])
+void nelly_decode_block(NellyMoserDecodeContext *s, const unsigned char block[NELLY_BLOCK_LEN], float audio[NELLY_SAMPLES])
 {
     int i,j;
-    float buf[NELLY_BUF_LEN], pows[NELLY_BUF_LEN];
+    float buf[NELLY_FILL_LEN], pows[NELLY_FILL_LEN];
     float *aptr, *bptr, *pptr, val, pval;
     int bits[NELLY_BUF_LEN];
     unsigned char v;
@@ -355,7 +280,7 @@ void nelly_decode_block(NellyMoserDecodeContext *s, unsigned char block[NELLY_BL
     for (i=0 ; i<NELLY_BANDS ; i++) {
         if (i > 0)
             val += nelly_delta_table[get_bits(&s->gb, 5)];
-        pval = pow(2, val/2048);
+        pval = -pow(2, val/2048) * s->scale_bias;
         for (j = 0; j < nelly_band_sizes_table[i]; j++) {
             *bptr++ = val;
             *pptr++ = pval;
@@ -363,51 +288,51 @@ void nelly_decode_block(NellyMoserDecodeContext *s, unsigned char block[NELLY_BL
 
     }
 
-    memset(&buf[NELLY_FILL_LEN],0,4*sizeof(float));
-    memset(&pows[NELLY_FILL_LEN],0,4*sizeof(float));
-
     get_sample_bits(buf, bits);
 
     for (i = 0; i < 2; i++) {
-        aptr = audio+i*128;
+        aptr = audio + i * NELLY_BUF_LEN;
+
         init_get_bits(&s->gb, block, NELLY_BLOCK_LEN * 8);
         skip_bits(&s->gb, NELLY_HEADER_BITS + i*NELLY_DETAIL_BITS);
 
         for (j = 0; j < NELLY_FILL_LEN; j++) {
             if (bits[j] <= 0) {
-                buf[j] = M_SQRT1_2*pows[j];
+                aptr[j] = M_SQRT1_2*pows[j];
                 if (av_random(&s->random_state) & 1)
-                    buf[j] *= -1.0;
+                    aptr[j] *= -1.0;
             } else {
                 v = get_bits(&s->gb, bits[j]);
-                buf[j] = dequantization_table[(1<<bits[j])-1+v]*pows[j];
+                aptr[j] = dequantization_table[(1<<bits[j])-1+v]*pows[j];
             }
         }
-
-        antialias(buf, aptr);
-        ff_fft_permute(&s->fftc, (FFTComplex*)aptr);
-        ff_fft_calc(&s->fftc, (FFTComplex*)aptr);
-        complex2signal(aptr);
-        overlap_and_window(s, s->state, aptr);
+        memset(&aptr[NELLY_FILL_LEN], 0,
+               (NELLY_BUF_LEN - NELLY_FILL_LEN) * sizeof(float));
+
+        s->imdct_ctx.fft.imdct_calc(&s->imdct_ctx, s->imdct_out,
+                                    aptr, s->imdct_tmp);
+        /* XXX: overlapping and windowing should be part of a more
+           generic imdct function */
+        overlap_and_window(s, s->state, aptr, s->imdct_out);
     }
 }
 
-static int decode_init(AVCodecContext * avctx) {
+static av_cold int decode_init(AVCodecContext * avctx) {
     NellyMoserDecodeContext *s = avctx->priv_data;
     int i;
-    float alpha;
 
     s->avctx = avctx;
     av_init_random(0, &s->random_state);
-    ff_fft_init(&s->fftc, 6, 1);
+    ff_mdct_init(&s->imdct_ctx, 8, 1);
+
     dsputil_init(&s->dsp, avctx);
 
     if(s->dsp.float_to_int16 == ff_float_to_int16_c) {
         s->add_bias = 385;
-        s->scale_bias = 32768;
+        s->scale_bias = 1.0/(8*32768);
     } else {
         s->add_bias = 0;
-        s->scale_bias = 1;
+        s->scale_bias = 1.0/(1*8);
     }
 
     /* Generate overlap window */
@@ -416,21 +341,12 @@ static int decode_init(AVCodecContext * avctx) {
             sine_window[i] = sin((i + 0.5) / 256.0 * M_PI);
         }
 
-    /* Generate tables */
-    if (!tcos[0])
-        for(i=0;i<64;i++) {
-            alpha = 2*M_PI * (i + 1.0 / 4.0) / 256;
-            tcos[i] = cos(alpha);
-            tsin[i] = -sin(alpha);
-            cos_tab[i] = cos(i/128.0*M_PI)/8.0;
-        }
-
     return 0;
 }
 
 static int decode_tag(AVCodecContext * avctx,
                       void *data, int *data_size,
-                      uint8_t * buf, int buf_size) {
+                      const uint8_t * buf, int buf_size) {
     NellyMoserDecodeContext *s = avctx->priv_data;
     int blocks, i;
     int16_t* samples;
@@ -447,8 +363,10 @@ static int decode_tag(AVCodecContext * avctx,
             blocks = 2; break;
         case 256:   // 22050Hz
             blocks = 4; break;
+        case 512:   // 44100Hz
+            blocks = 8; break;
         default:
-            av_log(avctx, AV_LOG_DEBUG, "Tag size %d unknown, report sample!\n", buf_size);
+            av_log(avctx, AV_LOG_ERROR, "Tag size %d unknown, report sample!\n", buf_size);
             return buf_size;
     }
 
@@ -458,13 +376,13 @@ static int decode_tag(AVCodecContext * avctx,
         *data_size += NELLY_SAMPLES*sizeof(int16_t);
     }
 
-    return blocks*NELLY_SAMPLES*sizeof(int16_t);
+    return buf_size;
 }
 
-static int decode_end(AVCodecContext * avctx) {
+static av_cold int decode_end(AVCodecContext * avctx) {
     NellyMoserDecodeContext *s = avctx->priv_data;
 
-    ff_fft_end(&s->fftc);
+    ff_mdct_end(&s->imdct_ctx);
     return 0;
 }