Propagate balance from compute_allocation() to quant_all_bands().
[opus.git] / libcelt / celt.c
index 66bf401..c6c8124 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
  */
@@ -70,9 +96,11 @@ struct CELTEncoder {
    const CELTMode *mode;     /**< Mode used by the encoder */
    int overlap;
    int channels;
+   int stream_channels;
    
    int force_intra;
    int complexity;
+   int upsample;
    int start, end;
 
    celt_int32 vbr_rate_norm; /* Target number of 8th bits per frame */
@@ -118,7 +146,13 @@ struct CELTEncoder {
    /* celt_word16 oldEBands[], Size = 2*channels*mode->nbEBands */
 };
 
-int celt_encoder_get_size(const CELTMode *mode, int channels)
+int celt_encoder_get_size(int channels)
+{
+   CELTMode *mode = celt_mode_create(48000, 960, NULL);
+   return celt_encoder_get_size_custom(mode, channels);
+}
+
+int celt_encoder_get_size_custom(const CELTMode *mode, int channels)
 {
    int size = sizeof(struct CELTEncoder)
          + (2*channels*mode->overlap-1)*sizeof(celt_sig)
@@ -127,24 +161,40 @@ int celt_encoder_get_size(const CELTMode *mode, int channels)
    return size;
 }
 
-CELTEncoder *celt_encoder_create(int channels, int *error)
+CELTEncoder *celt_encoder_create(int sampling_rate, int channels, int *error)
 {
-   CELTMode *mode = celt_mode_create(48000, 960, NULL);
-   return celt_encoder_init(
-         (CELTEncoder *)celt_alloc(celt_encoder_get_size(mode, channels)),
-         channels, error);
+   CELTEncoder *st;
+   st = (CELTEncoder *)celt_alloc(celt_encoder_get_size(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_custom(
-         (CELTEncoder *)celt_alloc(celt_encoder_get_size(mode, channels)),
-         mode, channels, error);
+   CELTEncoder *st = (CELTEncoder *)celt_alloc(celt_encoder_get_size_custom(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, int channels, int *error)
+CELTEncoder *celt_encoder_init(CELTEncoder *st, int sampling_rate, int channels, int *error)
 {
-   return celt_encoder_init_custom(st, celt_mode_create(48000, 960, NULL), channels, 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)
@@ -156,19 +206,20 @@ CELTEncoder *celt_encoder_init_custom(CELTEncoder *st, const CELTMode *mode, int
       return NULL;
    }
 
-   if (st==NULL)
+   if (st==NULL || mode==NULL)
    {
       if (error)
          *error = CELT_ALLOC_FAIL;
       return NULL;
    }
 
-   CELT_MEMSET((char*)st, 0, celt_encoder_get_size(mode, channels));
+   CELT_MEMSET((char*)st, 0, celt_encoder_get_size_custom(mode, channels));
    
    st->mode = mode;
    st->overlap = mode->overlap;
-   st->channels = channels;
+   st->stream_channels = st->channels = channels;
 
+   st->upsample = 1;
    st->start = 0;
    st->end = st->mode->effEBands;
    st->constrained_vbr = 1;
@@ -385,10 +436,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;
@@ -402,9 +454,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);
@@ -802,6 +860,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    VARDECL(int, fine_quant);
    VARDECL(celt_word16, error);
    VARDECL(int, pulses);
+   VARDECL(int, cap);
    VARDECL(int, offsets);
    VARDECL(int, fine_priority);
    VARDECL(int, tf_res);
@@ -812,7 +871,8 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    int shortBlocks=0;
    int isTransient=0;
    int resynth;
-   const int C = CHANNELS(st->channels);
+   const int CC = CHANNELS(st->channels);
+   const int C = CHANNELS(st->stream_channels);
    int LM, M;
    int tf_select;
    int nbFilledBytes, nbAvailableBytes;
@@ -830,6 +890,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    celt_int32 vbr_rate;
    celt_int32 total_bits;
    celt_int32 total_boost;
+   celt_int32 balance;
    celt_int32 tell;
    int prefilter_tapset=0;
    int pf_on;
@@ -841,6 +902,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;
@@ -848,12 +910,12 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
       return CELT_BAD_ARG;
    M=1<<LM;
 
-   prefilter_mem = st->in_mem+C*(st->overlap);
-   _overlap_mem = prefilter_mem+C*COMBFILTER_MAXPERIOD;
+   prefilter_mem = st->in_mem+CC*(st->overlap);
+   _overlap_mem = prefilter_mem+CC*COMBFILTER_MAXPERIOD;
    /*_overlap_mem = st->in_mem+C*(st->overlap);*/
-   oldBandE = (celt_word16*)(st->in_mem+C*(2*st->overlap+COMBFILTER_MAXPERIOD));
-   oldLogE = oldBandE + C*st->mode->nbEBands;
-   oldLogE2 = oldLogE + C*st->mode->nbEBands;
+   oldBandE = (celt_word16*)(st->in_mem+CC*(2*st->overlap+COMBFILTER_MAXPERIOD));
+   oldLogE = oldBandE + CC*st->mode->nbEBands;
+   oldLogE2 = oldLogE + CC*st->mode->nbEBands;
 
    if (enc==NULL)
    {
@@ -904,7 +966,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
       effEnd = st->mode->effEBands;
 
    N = M*st->mode->shortMdctSize;
-   ALLOC(in, C*(N+st->overlap), celt_sig);
+   ALLOC(in, CC*(N+st->overlap), celt_sig);
 
    /* Find pitch period and gain */
    {
@@ -912,30 +974,40 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
       celt_sig *pre[2];
       SAVE_STACK;
       c = 0;
-      ALLOC(_pre, C*(N+COMBFILTER_MAXPERIOD), celt_sig);
+      ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig);
 
       pre[0] = _pre;
       pre[1] = _pre + (N+COMBFILTER_MAXPERIOD);
 
       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+=CC;
+            } 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);
-      } while (++c<C);
+      } while (++c<CC);
 
       if (tell==1)
          ec_enc_bit_logp(enc, silence, 15);
@@ -962,7 +1034,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
          VARDECL(celt_word16, pitch_buf);
          ALLOC(pitch_buf, (COMBFILTER_MAXPERIOD+N)>>1, celt_word16);
 
-         pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, C);
+         pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC);
          pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N,
                COMBFILTER_MAXPERIOD-COMBFILTER_MINPERIOD, &pitch_index);
          pitch_index = COMBFILTER_MAXPERIOD-pitch_index;
@@ -1051,7 +1123,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
             CELT_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N);
          }
 #endif /* ENABLE_POSTFILTER */
-      } while (++c<C);
+      } while (++c<CC);
 
       RESTORE_STACK;
    }
@@ -1068,7 +1140,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    {
       if (st->complexity > 1)
       {
-         isTransient = transient_analysis(in, N+st->overlap, C,
+         isTransient = transient_analysis(in, N+st->overlap, CC,
                   st->overlap);
          if (isTransient)
             shortBlocks = M;
@@ -1076,12 +1148,28 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
       ec_enc_bit_logp(enc, isTransient, 3);
    }
 
-   ALLOC(freq, C*N, celt_sig); /**< Interleaved signal MDCTs */
-   ALLOC(bandE,st->mode->nbEBands*C, celt_ener);
-   ALLOC(bandLogE,st->mode->nbEBands*C, celt_word16);
+   ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */
+   ALLOC(bandE,st->mode->nbEBands*CC, celt_ener);
+   ALLOC(bandLogE,st->mode->nbEBands*CC, celt_word16);
    /* Compute MDCTs */
-   compute_mdcts(st->mode, shortBlocks, in, freq, C, LM);
+   compute_mdcts(st->mode, shortBlocks, in, freq, CC, LM);
 
+   if (CC==2&&C==1)
+   {
+      for (i=0;i<N;i++)
+         freq[i] = ADD32(HALF32(freq[i]), HALF32(freq[N+i]));
+   }
+   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);
@@ -1120,9 +1208,13 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
       ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5);
    }
 
+   ALLOC(cap, st->mode->nbEBands, int);
    ALLOC(offsets, st->mode->nbEBands, int);
 
    for (i=0;i<st->mode->nbEBands;i++)
+      cap[i] = st->mode->cache.caps[st->mode->nbEBands*(2*LM+C-1)+i]
+            << C+LM+BITRES-2;
+   for (i=0;i<st->mode->nbEBands;i++)
       offsets[i] = 0;
    /* Dynamic allocation code */
    /* Make sure that dynamic allocation can't make us bust the budget */
@@ -1167,7 +1259,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
       dynalloc_loop_logp = dynalloc_logp;
       boost = 0;
       for (j = 0; tell+(dynalloc_loop_logp<<BITRES) < total_bits-total_boost
-            && boost < (64<<LM)*(C<<BITRES); j++)
+            && boost < cap[i]; j++)
       {
          int flag;
          flag = j<offsets[i];
@@ -1306,9 +1398,9 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    bits = (nbCompressedBytes*8<<BITRES) - ec_enc_tell(enc, BITRES) - 1;
    anti_collapse_rsv = isTransient&&LM>=2&&bits>=(LM+2<<BITRES) ? (1<<BITRES) : 0;
    bits -= anti_collapse_rsv;
-   codedBands = compute_allocation(st->mode, st->start, st->end, offsets,
-         alloc_trim, &intensity, &dual_stereo, bits, pulses, fine_quant,
-         fine_priority, C, LM, enc, 1, st->lastCodedBands);
+   codedBands = compute_allocation(st->mode, st->start, st->end, offsets, cap,
+         alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses,
+         fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands);
    st->lastCodedBands = codedBands;
 
    quant_fine_energy(st->mode, st->start, st->end, oldBandE, error, fine_quant, enc, C);
@@ -1328,7 +1420,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    ALLOC(collapse_masks, st->mode->nbEBands, unsigned char);
    quant_all_bands(1, st->mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks,
          bandE, pulses, shortBlocks, st->spread_decision, dual_stereo, intensity, tf_res, resynth,
-         nbCompressedBytes*(8<<BITRES)-anti_collapse_rsv, enc, LM, codedBands, &st->rng);
+         nbCompressedBytes*(8<<BITRES)-anti_collapse_rsv, balance, enc, LM, codedBands, &st->rng);
 
    if (anti_collapse_rsv > 0)
    {
@@ -1370,7 +1462,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
       denormalise_bands(st->mode, X, freq, bandE, effEnd, C, M);
 
       CELT_MOVE(st->syn_mem[0], st->syn_mem[0]+N, MAX_PERIOD);
-      if (C==2)
+      if (CC==2)
          CELT_MOVE(st->syn_mem[1], st->syn_mem[1]+N, MAX_PERIOD);
 
       c=0; do
@@ -1382,15 +1474,21 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
             freq[c*N+i] = 0;
       while (++c<C);
 
+      if (CC==2&&C==1)
+      {
+         for (i=0;i<N;i++)
+            freq[N+i] = freq[i];
+      }
+
       out_mem[0] = st->syn_mem[0]+MAX_PERIOD;
-      if (C==2)
+      if (CC==2)
          out_mem[1] = st->syn_mem[1]+MAX_PERIOD;
 
       c=0; do
          overlap_mem[c] = _overlap_mem + c*st->overlap;
-      while (++c<C);
+      while (++c<CC);
 
-      compute_inv_mdcts(st->mode, shortBlocks, freq, out_mem, overlap_mem, C, LM);
+      compute_inv_mdcts(st->mode, shortBlocks, freq, out_mem, overlap_mem, CC, LM);
 
 #ifdef ENABLE_POSTFILTER
       c=0; do {
@@ -1409,10 +1507,10 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
                   st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset,
                   st->mode->window, st->mode->overlap);
          }
-      } while (++c<C);
+      } while (++c<CC);
 #endif /* ENABLE_POSTFILTER */
 
-      deemphasis(out_mem, (celt_word16*)pcm, N, C, st->mode->preemph, st->preemph_memD);
+      deemphasis(out_mem, (celt_word16*)pcm, N, CC, 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;
@@ -1423,6 +1521,11 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    st->prefilter_gain = gain1;
    st->prefilter_tapset = prefilter_tapset;
 
+   if (CC==2&&C==1) {
+      for (i=0;i<st->mode->nbEBands;i++)
+         oldBandE[st->mode->nbEBands+i]=oldBandE[i];
+   }
+
    /* In case start or end were to change */
    c=0; do
    {
@@ -1430,15 +1533,15 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
          oldBandE[c*st->mode->nbEBands+i]=0;
       for (i=st->end;i<st->mode->nbEBands;i++)
          oldBandE[c*st->mode->nbEBands+i]=0;
-   } while (++c<C);
+   } while (++c<CC);
    if (!isTransient)
    {
-      for (i=0;i<C*st->mode->nbEBands;i++)
+      for (i=0;i<CC*st->mode->nbEBands;i++)
          oldLogE2[i] = oldLogE[i];
-      for (i=0;i<C*st->mode->nbEBands;i++)
+      for (i=0;i<CC*st->mode->nbEBands;i++)
          oldLogE[i] = oldBandE[i];
    } else {
-      for (i=0;i<C*st->mode->nbEBands;i++)
+      for (i=0;i<CC*st->mode->nbEBands;i++)
          oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]);
    }
    if (isTransient)
@@ -1462,22 +1565,15 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
 #ifndef DISABLE_FLOAT_API
 int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
 {
-   int j, ret, C, N, LM, M;
+   int j, ret, C, N;
    VARDECL(celt_int16, in);
    SAVE_STACK;
 
    if (pcm==NULL)
       return CELT_BAD_ARG;
 
-   for (LM=0;LM<4;LM++)
-      if (st->mode->shortMdctSize<<LM==frame_size)
-         break;
-   if (LM>=MAX_CONFIG_SIZES)
-      return CELT_BAD_ARG;
-   M=1<<LM;
-
    C = CHANNELS(st->channels);
-   N = M*st->mode->shortMdctSize;
+   N = frame_size;
    ALLOC(in, C*N, celt_int16);
 
    for (j=0;j<C*N;j++)
@@ -1496,22 +1592,15 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int
 #else
 int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
 {
-   int j, ret, C, N, LM, M;
+   int j, ret, C, N;
    VARDECL(celt_sig, in);
    SAVE_STACK;
 
    if (pcm==NULL)
       return CELT_BAD_ARG;
 
-   for (LM=0;LM<4;LM++)
-      if (st->mode->shortMdctSize<<LM==frame_size)
-         break;
-   if (LM>=MAX_CONFIG_SIZES)
-      return CELT_BAD_ARG;
-   M=1<<LM;
-
    C=CHANNELS(st->channels);
-   N=M*st->mode->shortMdctSize;
+   N=frame_size;
    ALLOC(in, C*N, celt_sig);
    for (j=0;j<C*N;j++) {
      in[j] = SCALEOUT(pcm[j]);
@@ -1612,10 +1701,18 @@ int celt_encoder_ctl(CELTEncoder * restrict st, int request, ...)
          st->vbr_rate_norm = value>0?IMAX(1,((value<<(BITRES+3))+(frame_rate>>1))/frame_rate):0;
       }
       break;
+      case CELT_SET_CHANNELS_REQUEST:
+      {
+         celt_int32 value = va_arg(ap, celt_int32);
+         if (value<1 || value>2)
+            goto bad_arg;
+         st->stream_channels = value;
+      }
+      break;
       case CELT_RESET_STATE:
       {
          CELT_MEMSET((char*)&st->ENCODER_RESET_START, 0,
-               celt_encoder_get_size(st->mode, st->channels)-
+               celt_encoder_get_size_custom(st->mode, st->channels)-
                ((char*)&st->ENCODER_RESET_START - (char*)st));
          st->vbr_offset = 0;
          st->delayedIntra = 1;
@@ -1650,7 +1747,9 @@ struct CELTDecoder {
    const CELTMode *mode;
    int overlap;
    int channels;
+   int stream_channels;
 
+   int downsample;
    int start, end;
 
    /* Everything beyond this point gets cleared on a reset */
@@ -1676,7 +1775,13 @@ struct CELTDecoder {
    /* celt_word16 backgroundLogE[], Size = channels*mode->nbEBands */
 };
 
-int celt_decoder_get_size(const CELTMode *mode, int channels)
+int celt_decoder_get_size(int channels)
+{
+   const CELTMode *mode = celt_mode_create(48000, 960, NULL);
+   return celt_decoder_get_size_custom(mode, channels);
+}
+
+int celt_decoder_get_size_custom(const CELTMode *mode, int channels)
 {
    int size = sizeof(struct CELTDecoder)
             + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig)
@@ -1685,24 +1790,40 @@ int celt_decoder_get_size(const CELTMode *mode, int channels)
    return size;
 }
 
-CELTDecoder *celt_decoder_create(int channels, int *error)
+CELTDecoder *celt_decoder_create(int sampling_rate, int channels, int *error)
 {
-   const CELTMode *mode = celt_mode_create(48000, 960, NULL);
-   return celt_decoder_init(
-         (CELTDecoder *)celt_alloc(celt_decoder_get_size(mode, channels)),
-         channels, error);
+   CELTDecoder *st;
+   st = (CELTDecoder *)celt_alloc(celt_decoder_get_size(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)
 {
-   return celt_decoder_init_custom(
-         (CELTDecoder *)celt_alloc(celt_decoder_get_size(mode, channels)),
-         mode, channels, error);
+   CELTDecoder *st = (CELTDecoder *)celt_alloc(celt_decoder_get_size_custom(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 channels, int *error)
+CELTDecoder *celt_decoder_init(CELTDecoder *st, int sampling_rate, int channels, int *error)
 {
-   return celt_decoder_init_custom(st, celt_mode_create(48000, 960, NULL), 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_custom(CELTDecoder *st, const CELTMode *mode, int channels, int *error)
@@ -1721,12 +1842,13 @@ CELTDecoder *celt_decoder_init_custom(CELTDecoder *st, const CELTMode *mode, int
       return NULL;
    }
 
-   CELT_MEMSET((char*)st, 0, celt_decoder_get_size(mode, channels));
+   CELT_MEMSET((char*)st, 0, celt_decoder_get_size_custom(mode, channels));
 
    st->mode = mode;
    st->overlap = mode->overlap;
-   st->channels = channels;
+   st->stream_channels = st->channels = channels;
 
+   st->downsample = 1;
    st->start = 0;
    st->end = st->mode->effEBands;
 
@@ -1955,7 +2077,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++;
 
@@ -1979,6 +2101,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    VARDECL(celt_ener, bandE);
    VARDECL(int, fine_quant);
    VARDECL(int, pulses);
+   VARDECL(int, cap);
    VARDECL(int, offsets);
    VARDECL(int, fine_priority);
    VARDECL(int, tf_res);
@@ -1993,7 +2116,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    int shortBlocks;
    int isTransient;
    int intra_ener;
-   const int C = CHANNELS(st->channels);
+   const int CC = CHANNELS(st->channels);
    int LM, M;
    int effEnd;
    int codedBands;
@@ -2003,18 +2126,21 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    int intensity=0;
    int dual_stereo=0;
    celt_int32 total_bits;
+   celt_int32 balance;
    celt_int32 tell;
    int dynalloc_logp;
    int postfilter_tapset;
    int anti_collapse_rsv;
    int anti_collapse_on=0;
    int silence;
+   const int C = CHANNELS(st->stream_channels);
 
    SAVE_STACK;
 
    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;
@@ -2026,12 +2152,12 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
       decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+st->overlap);
       out_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE-MAX_PERIOD;
       overlap_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE;
-   } while (++c<C);
-   lpc = (celt_word16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*C);
-   oldBandE = lpc+C*LPC_ORDER;
-   oldLogE = oldBandE + C*st->mode->nbEBands;
-   oldLogE2 = oldLogE + C*st->mode->nbEBands;
-   backgroundLogE = oldLogE2  + C*st->mode->nbEBands;
+   } while (++c<CC);
+   lpc = (celt_word16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*CC);
+   oldBandE = lpc+CC*LPC_ORDER;
+   oldLogE = oldBandE + CC*st->mode->nbEBands;
+   oldLogE2 = oldLogE + CC*st->mode->nbEBands;
+   backgroundLogE = oldLogE2  + CC*st->mode->nbEBands;
 
    N = M*st->mode->shortMdctSize;
 
@@ -2039,17 +2165,17 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    if (effEnd > st->mode->effEBands)
       effEnd = st->mode->effEBands;
 
-   ALLOC(freq, C*N, celt_sig); /**< Interleaved signal MDCTs */
-   ALLOC(X, C*N, celt_norm);   /**< Interleaved normalised MDCTs */
-   ALLOC(bandE, st->mode->nbEBands*C, celt_ener);
+   ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */
+   ALLOC(X, CC*N, celt_norm);   /**< Interleaved normalised MDCTs */
+   ALLOC(bandE, st->mode->nbEBands*CC, celt_ener);
    c=0; do
       for (i=0;i<M*st->mode->eBands[st->start];i++)
          X[c*N+i] = 0;
-   while (++c<C);
+   while (++c<CC);
    c=0; do   
       for (i=M*st->mode->eBands[effEnd];i<N;i++)
          X[c*N+i] = 0;
-   while (++c<C);
+   while (++c<CC);
 
    if (data == NULL || len<=1)
    {
@@ -2069,6 +2195,21 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
       dec = &_dec;
    }
 
+   if (CC==1&&C==2)
+   {
+      RESTORE_STACK;
+      return CELT_CORRUPTED_DATA;
+   } else if (CC==2&&C==1)
+   {
+      for (i=0;i<st->mode->nbEBands;i++)
+      {
+         oldBandE[i]=MAX16(oldBandE[i],oldBandE[st->mode->nbEBands+i]);
+         oldLogE[i]=MAX16(oldLogE[i],oldLogE[st->mode->nbEBands+i]);
+         oldLogE2[i]=MAX16(oldLogE2[i],oldLogE2[st->mode->nbEBands+i]);
+         backgroundLogE[i]=MAX16(backgroundLogE[i],backgroundLogE[st->mode->nbEBands+i]);
+      }
+   }
+
    total_bits = len*8;
    tell = ec_dec_tell(dec, 0);
 
@@ -2133,9 +2274,14 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
       spread_decision = ec_dec_icdf(dec, spread_icdf, 5);
 
    ALLOC(pulses, st->mode->nbEBands, int);
+   ALLOC(cap, st->mode->nbEBands, int);
    ALLOC(offsets, st->mode->nbEBands, int);
    ALLOC(fine_priority, st->mode->nbEBands, int);
 
+   for (i=0;i<st->mode->nbEBands;i++)
+      cap[i] = st->mode->cache.caps[st->mode->nbEBands*(2*LM+C-1)+i]
+            << C+LM+BITRES-2;
+
    dynalloc_logp = 6;
    total_bits<<=BITRES;
    tell = ec_dec_tell(dec, BITRES);
@@ -2150,8 +2296,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
       quanta = IMIN(width<<BITRES, IMAX(6<<BITRES, width));
       dynalloc_loop_logp = dynalloc_logp;
       boost = 0;
-      while (tell+(dynalloc_loop_logp<<BITRES) < total_bits &&
-            boost < (64<<LM)*(C<<BITRES))
+      while (tell+(dynalloc_loop_logp<<BITRES) < total_bits && boost < cap[i])
       {
          int flag;
          flag = ec_dec_bit_logp(dec, dynalloc_loop_logp);
@@ -2175,9 +2320,9 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    bits = (len*8<<BITRES) - ec_dec_tell(dec, BITRES) - 1;
    anti_collapse_rsv = isTransient&&LM>=2&&bits>=(LM+2<<BITRES) ? (1<<BITRES) : 0;
    bits -= anti_collapse_rsv;
-   codedBands = compute_allocation(st->mode, st->start, st->end, offsets,
-         alloc_trim, &intensity, &dual_stereo, bits, pulses, fine_quant,
-         fine_priority, C, LM, dec, 0, 0);
+   codedBands = compute_allocation(st->mode, st->start, st->end, offsets, cap,
+         alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses,
+         fine_quant, fine_priority, C, LM, dec, 0, 0);
    
    unquant_fine_energy(st->mode, st->start, st->end, oldBandE, fine_quant, dec, C);
 
@@ -2185,7 +2330,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    ALLOC(collapse_masks, st->mode->nbEBands, unsigned char);
    quant_all_bands(0, st->mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks,
          NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res, 1,
-         len*(8<<BITRES)-anti_collapse_rsv, dec, LM, codedBands, &st->rng);
+         len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng);
 
    if (anti_collapse_rsv > 0)
    {
@@ -2213,24 +2358,33 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    denormalise_bands(st->mode, X, freq, bandE, effEnd, C, M);
 
    CELT_MOVE(decode_mem[0], decode_mem[0]+N, DECODE_BUFFER_SIZE-N);
-   if (C==2)
+   if (CC==2)
       CELT_MOVE(decode_mem[1], decode_mem[1]+N, DECODE_BUFFER_SIZE-N);
 
    c=0; do
       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)
+   if (CC==2)
       out_syn[1] = out_mem[1]+MAX_PERIOD-N;
 
+   if (CC==2&&C==1)
+   {
+      for (i=0;i<N;i++)
+         freq[N+i] = freq[i];
+   }
+
    /* Compute inverse MDCTs */
-   compute_inv_mdcts(st->mode, shortBlocks, freq, out_syn, overlap_mem, C, LM);
+   compute_inv_mdcts(st->mode, shortBlocks, freq, out_syn, overlap_mem, CC, LM);
 
 #ifdef ENABLE_POSTFILTER
    c=0; do {
@@ -2249,7 +2403,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
                st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset,
                st->mode->window, st->mode->overlap);
       }
-   } while (++c<C);
+   } while (++c<CC);
    st->postfilter_period_old = st->postfilter_period;
    st->postfilter_gain_old = st->postfilter_gain;
    st->postfilter_tapset_old = st->postfilter_tapset;
@@ -2258,6 +2412,11 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    st->postfilter_tapset = postfilter_tapset;
 #endif /* ENABLE_POSTFILTER */
 
+   if (CC==2&&C==1) {
+      for (i=0;i<st->mode->nbEBands;i++)
+         oldBandE[st->mode->nbEBands+i]=oldBandE[i];
+   }
+
    /* In case start or end were to change */
    c=0; do
    {
@@ -2265,22 +2424,22 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
          oldBandE[c*st->mode->nbEBands+i]=0;
       for (i=st->end;i<st->mode->nbEBands;i++)
          oldBandE[c*st->mode->nbEBands+i]=0;
-   } while (++c<C);
+   } while (++c<CC);
    if (!isTransient)
    {
-      for (i=0;i<C*st->mode->nbEBands;i++)
+      for (i=0;i<CC*st->mode->nbEBands;i++)
          oldLogE2[i] = oldLogE[i];
-      for (i=0;i<C*st->mode->nbEBands;i++)
+      for (i=0;i<CC*st->mode->nbEBands;i++)
          oldLogE[i] = oldBandE[i];
-      for (i=0;i<C*st->mode->nbEBands;i++)
+      for (i=0;i<CC*st->mode->nbEBands;i++)
          backgroundLogE[i] = MIN16(backgroundLogE[i] + M*QCONST16(0.001f,DB_SHIFT), oldBandE[i]);
    } else {
-      for (i=0;i<C*st->mode->nbEBands;i++)
+      for (i=0;i<CC*st->mode->nbEBands;i++)
          oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]);
    }
    st->rng = dec->rng;
 
-   deemphasis(out_syn, pcm, N, C, st->mode->preemph, st->preemph_memD);
+   deemphasis(out_syn, pcm, N, CC, 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))
@@ -2293,22 +2452,15 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
 #ifndef DISABLE_FLOAT_API
 int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size, ec_dec *dec)
 {
-   int j, ret, C, N, LM, M;
+   int j, ret, C, N;
    VARDECL(celt_int16, out);
    SAVE_STACK;
 
    if (pcm==NULL)
       return CELT_BAD_ARG;
 
-   for (LM=0;LM<4;LM++)
-      if (st->mode->shortMdctSize<<LM==frame_size)
-         break;
-   if (LM>=MAX_CONFIG_SIZES)
-      return CELT_BAD_ARG;
-   M=1<<LM;
-
    C = CHANNELS(st->channels);
-   N = M*st->mode->shortMdctSize;
+   N = frame_size;
    
    ALLOC(out, C*N, celt_int16);
    ret=celt_decode_with_ec(st, data, len, out, frame_size, dec);
@@ -2323,22 +2475,15 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
 #else
 int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, celt_int16 * restrict pcm, int frame_size, ec_dec *dec)
 {
-   int j, ret, C, N, LM, M;
+   int j, ret, C, N;
    VARDECL(celt_sig, out);
    SAVE_STACK;
 
    if (pcm==NULL)
       return CELT_BAD_ARG;
 
-   for (LM=0;LM<4;LM++)
-      if (st->mode->shortMdctSize<<LM==frame_size)
-         break;
-   if (LM>=MAX_CONFIG_SIZES)
-      return CELT_BAD_ARG;
-   M=1<<LM;
-
    C = CHANNELS(st->channels);
-   N = M*st->mode->shortMdctSize;
+   N = frame_size;
    ALLOC(out, C*N, celt_sig);
 
    ret=celt_decode_with_ec_float(st, data, len, out, frame_size, dec);
@@ -2395,10 +2540,18 @@ int celt_decoder_ctl(CELTDecoder * restrict st, int request, ...)
          st->end = value;
       }
       break;
+      case CELT_SET_CHANNELS_REQUEST:
+      {
+         celt_int32 value = va_arg(ap, celt_int32);
+         if (value<1 || value>2)
+            goto bad_arg;
+         st->stream_channels = value;
+      }
+      break;
       case CELT_RESET_STATE:
       {
          CELT_MEMSET((char*)&st->DECODER_RESET_START, 0,
-               celt_decoder_get_size(st->mode, st->channels)-
+               celt_decoder_get_size_custom(st->mode, st->channels)-
                ((char*)&st->DECODER_RESET_START - (char*)st));
       }
       break;