Merge branch 'exp_api_change'
[opus.git] / libcelt / celt.c
index 9aaaa6e..a9a4717 100644 (file)
@@ -63,6 +63,32 @@ static const unsigned char tapset_icdf[3]={2,1,0};
 #define COMBFILTER_MAXPERIOD 1024
 #define COMBFILTER_MINPERIOD 15
 
+static int resampling_factor(celt_int32 rate)
+{
+   int ret;
+   switch (rate)
+   {
+   case 48000:
+      ret = 1;
+      break;
+   case 24000:
+      ret = 2;
+      break;
+   case 16000:
+      ret = 3;
+      break;
+   case 12000:
+      ret = 4;
+      break;
+   case 8000:
+      ret = 6;
+      break;
+   default:
+      ret = 0;
+   }
+   return ret;
+}
+
 /** Encoder state 
  @brief Encoder state
  */
@@ -73,6 +99,7 @@ struct CELTEncoder {
    
    int force_intra;
    int complexity;
+   int upsample;
    int start, end;
 
    celt_int32 vbr_rate_norm; /* Target number of 8th bits per frame */
@@ -127,14 +154,44 @@ int celt_encoder_get_size(const CELTMode *mode, int channels)
    return size;
 }
 
-CELTEncoder *celt_encoder_create(const CELTMode *mode, int channels, int *error)
+CELTEncoder *celt_encoder_create(int sampling_rate, int channels, int *error)
+{
+   CELTEncoder *st;
+   CELTMode *mode = celt_mode_create(48000, 960, NULL);
+   st = (CELTEncoder *)celt_alloc(celt_encoder_get_size(mode, channels));
+   if (st!=NULL && celt_encoder_init(st, sampling_rate, channels, error)==NULL)
+   {
+      celt_encoder_destroy(st);
+      st = NULL;
+   }
+   return st;
+}
+
+CELTEncoder *celt_encoder_create_custom(const CELTMode *mode, int channels, int *error)
 {
-   return celt_encoder_init(
-         (CELTEncoder *)celt_alloc(celt_encoder_get_size(mode, channels)),
-         mode, channels, error);
+   CELTEncoder *st = (CELTEncoder *)celt_alloc(celt_encoder_get_size(mode, channels));
+   if (st!=NULL && celt_encoder_init_custom(st, mode, channels, error)==NULL)
+   {
+      celt_encoder_destroy(st);
+      st = NULL;
+   }
+   return st;
 }
 
-CELTEncoder *celt_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels, int *error)
+CELTEncoder *celt_encoder_init(CELTEncoder *st, int sampling_rate, int channels, int *error)
+{
+   celt_encoder_init_custom(st, celt_mode_create(48000, 960, NULL), channels, error);
+   st->upsample = resampling_factor(sampling_rate);
+   if (st->upsample==0)
+   {
+      if (error)
+         *error = CELT_BAD_ARG;
+      return NULL;
+   }
+   return st;
+}
+
+CELTEncoder *celt_encoder_init_custom(CELTEncoder *st, const CELTMode *mode, int channels, int *error)
 {
    if (channels < 0 || channels > 2)
    {
@@ -143,7 +200,7 @@ CELTEncoder *celt_encoder_init(CELTEncoder *st, const CELTMode *mode, int channe
       return NULL;
    }
 
-   if (st==NULL)
+   if (st==NULL || mode==NULL)
    {
       if (error)
          *error = CELT_ALLOC_FAIL;
@@ -156,6 +213,7 @@ CELTEncoder *celt_encoder_init(CELTEncoder *st, const CELTMode *mode, int channe
    st->overlap = mode->overlap;
    st->channels = channels;
 
+   st->upsample = 1;
    st->start = 0;
    st->end = st->mode->effEBands;
    st->constrained_vbr = 1;
@@ -372,10 +430,11 @@ static void compute_inv_mdcts(const CELTMode *mode, int shortBlocks, celt_sig *X
    } while (++c<C);
 }
 
-static void deemphasis(celt_sig *in[], celt_word16 *pcm, int N, int _C, const celt_word16 *coef, celt_sig *mem)
+static void deemphasis(celt_sig *in[], celt_word16 *pcm, int N, int _C, int downsample, const celt_word16 *coef, celt_sig *mem)
 {
    const int C = CHANNELS(_C);
    int c;
+   int count=0;
    c=0; do {
       int j;
       celt_sig * restrict x;
@@ -389,9 +448,15 @@ static void deemphasis(celt_sig *in[], celt_word16 *pcm, int N, int _C, const ce
          m = MULT16_32_Q15(coef[0], tmp)
            - MULT16_32_Q15(coef[1], *x);
          tmp = SHL32(MULT16_32_Q15(coef[3], tmp), 2);
-         *y = SCALEOUT(SIG2WORD16(tmp));
          x++;
-         y+=C;
+         /* Technically the store could be moved outside of the if because
+            the stores we don't want will just be overwritten */
+         if (++count==downsample)
+         {
+            *y = SCALEOUT(SIG2WORD16(tmp));
+            y+=C;
+            count=0;
+         }
       }
       mem[c] = m;
    } while (++c<C);
@@ -829,6 +894,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    if (nbCompressedBytes<2 || pcm==NULL)
      return CELT_BAD_ARG;
 
+   frame_size *= st->upsample;
    for (LM=0;LM<4;LM++)
       if (st->mode->shortMdctSize<<LM==frame_size)
          break;
@@ -907,19 +973,29 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
 
       silence = 1;
       c=0; do {
+         int count = 0;
          const celt_word16 * restrict pcmp = pcm+c;
          celt_sig * restrict inp = in+c*(N+st->overlap)+st->overlap;
 
          for (i=0;i<N;i++)
          {
+            celt_sig x, tmp;
+
+            x = SCALEIN(*pcmp);
+            if (++count==st->upsample)
+            {
+               count=0;
+               pcmp+=C;
+            } else {
+               x = 0;
+            }
             /* Apply pre-emphasis */
-            celt_sig tmp = MULT16_16(st->mode->preemph[2], SCALEIN(*pcmp));
+            tmp = MULT16_16(st->mode->preemph[2], x);
             *inp = tmp + st->preemph_memE[c];
             st->preemph_memE[c] = MULT16_32_Q15(st->mode->preemph[1], *inp)
                                    - MULT16_32_Q15(st->mode->preemph[0], tmp);
             silence = silence && *inp == 0;
             inp++;
-            pcmp+=C;
          }
          CELT_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD);
          CELT_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+st->overlap)+st->overlap, N);
@@ -1070,6 +1146,17 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    /* Compute MDCTs */
    compute_mdcts(st->mode, shortBlocks, in, freq, C, LM);
 
+   if (st->upsample != 1)
+   {
+      c=0; do
+      {
+         int bound = N/st->upsample;
+         for (i=0;i<bound;i++)
+            freq[c*N+i] *= st->upsample;
+         for (;i<N;i++)
+            freq[c*N+i] = 0;
+      } while (++c<C);
+   }
    ALLOC(X, C*N, celt_norm);         /**< Interleaved normalised MDCTs */
 
    compute_band_energies(st->mode, freq, bandE, effEnd, C, M);
@@ -1404,7 +1491,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
       } while (++c<C);
 #endif /* ENABLE_POSTFILTER */
 
-      deemphasis(out_mem, (celt_word16*)pcm, N, C, st->mode->preemph, st->preemph_memD);
+      deemphasis(out_mem, (celt_word16*)pcm, N, C, st->upsample, st->mode->preemph, st->preemph_memD);
       st->prefilter_period_old = st->prefilter_period;
       st->prefilter_gain_old = st->prefilter_gain;
       st->prefilter_tapset_old = st->prefilter_tapset;
@@ -1643,6 +1730,7 @@ struct CELTDecoder {
    int overlap;
    int channels;
 
+   int downsample;
    int start, end;
 
    /* Everything beyond this point gets cleared on a reset */
@@ -1677,14 +1765,44 @@ int celt_decoder_get_size(const CELTMode *mode, int channels)
    return size;
 }
 
-CELTDecoder *celt_decoder_create(const CELTMode *mode, int channels, int *error)
+CELTDecoder *celt_decoder_create(int sampling_rate, int channels, int *error)
+{
+   CELTDecoder *st;
+   const CELTMode *mode = celt_mode_create(48000, 960, NULL);
+   st = (CELTDecoder *)celt_alloc(celt_decoder_get_size(mode, channels));
+   if (st!=NULL && celt_decoder_init(st, sampling_rate, channels, error)==NULL)
+   {
+      celt_decoder_destroy(st);
+      st = NULL;
+   }
+   return st;
+}
+
+CELTDecoder *celt_decoder_create_custom(const CELTMode *mode, int channels, int *error)
+{
+   CELTDecoder *st = (CELTDecoder *)celt_alloc(celt_decoder_get_size(mode, channels));
+   if (st!=NULL && celt_decoder_init_custom(st, mode, channels, error)==NULL)
+   {
+      celt_decoder_destroy(st);
+      st = NULL;
+   }
+   return st;
+}
+
+CELTDecoder *celt_decoder_init(CELTDecoder *st, int sampling_rate, int channels, int *error)
 {
-   return celt_decoder_init(
-         (CELTDecoder *)celt_alloc(celt_decoder_get_size(mode, channels)),
-         mode, channels, error);
+   celt_decoder_init_custom(st, celt_mode_create(48000, 960, NULL), channels, error);
+   st->downsample = resampling_factor(sampling_rate);
+   if (st->downsample==0)
+   {
+      if (error)
+         *error = CELT_BAD_ARG;
+      return NULL;
+   }
+   return st;
 }
 
-CELTDecoder *celt_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels, int *error)
+CELTDecoder *celt_decoder_init_custom(CELTDecoder *st, const CELTMode *mode, int channels, int *error)
 {
    if (channels < 0 || channels > 2)
    {
@@ -1706,6 +1824,7 @@ CELTDecoder *celt_decoder_init(CELTDecoder *st, const CELTMode *mode, int channe
    st->overlap = mode->overlap;
    st->channels = channels;
 
+   st->downsample = 1;
    st->start = 0;
    st->end = st->mode->effEBands;
 
@@ -1934,7 +2053,7 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p
          out_mem[c][MAX_PERIOD+i] = e[i];
    } while (++c<C);
 
-   deemphasis(out_syn, pcm, N, C, st->mode->preemph, st->preemph_memD);
+   deemphasis(out_syn, pcm, N, C, st->downsample, st->mode->preemph, st->preemph_memD);
    
    st->loss_count++;
 
@@ -1995,6 +2114,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    if (pcm==NULL)
       return CELT_BAD_ARG;
 
+   frame_size *= st->downsample;
    for (LM=0;LM<4;LM++)
       if (st->mode->shortMdctSize<<LM==frame_size)
          break;
@@ -2204,10 +2324,13 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
       for (i=0;i<M*st->mode->eBands[st->start];i++)
          freq[c*N+i] = 0;
    while (++c<C);
-   c=0; do
+   c=0; do {
+      int bound = M*st->mode->eBands[effEnd];
+      if (st->downsample!=1)
+         bound = IMIN(bound, N/st->downsample);
       for (i=M*st->mode->eBands[effEnd];i<N;i++)
          freq[c*N+i] = 0;
-   while (++c<C);
+   while (++c<C);
 
    out_syn[0] = out_mem[0]+MAX_PERIOD-N;
    if (C==2)
@@ -2264,7 +2387,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    }
    st->rng = dec->rng;
 
-   deemphasis(out_syn, pcm, N, C, st->mode->preemph, st->preemph_memD);
+   deemphasis(out_syn, pcm, N, C, st->downsample, st->mode->preemph, st->preemph_memD);
    st->loss_count = 0;
    RESTORE_STACK;
    if (ec_dec_tell(dec,0) > 8*len || ec_dec_get_error(dec))