Eliminate the ec_int32 and ec_uint32 typedefs.
[opus.git] / libcelt / celt.c
index 180ffa0..47697c0 100644 (file)
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    
-   - Neither the name of the Xiph.org Foundation nor the names of its
-   contributors may be used to endorse or promote products derived from
-   this software without specific prior written permission.
-   
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
 #define CELT_C
 
+/* Always enable postfilter for Opus */
+#if defined(OPUS_BUILD) && !defined(ENABLE_POSTFILTER)
+#define ENABLE_POSTFILTER
+#endif
+
 #include "os_support.h"
 #include "mdct.h"
 #include <math.h>
@@ -63,6 +64,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,18 +97,23 @@ struct CELTEncoder {
    const CELTMode *mode;     /**< Mode used by the encoder */
    int overlap;
    int channels;
+   int stream_channels;
    
    int force_intra;
+   int clip;
+   int disable_pf;
    int complexity;
+   int upsample;
    int start, end;
 
-   celt_int32 vbr_rate_norm; /* Target number of 8th bits per frame */
+   celt_int32 bitrate;
+   int vbr;
    int constrained_vbr;      /* If zero, VBR can do whatever it likes with the rate */
 
    /* Everything beyond this point gets cleared on a reset */
 #define ENCODER_RESET_START rng
 
-   ec_uint32 rng;
+   celt_uint32 rng;
    int spread_decision;
    int delayedIntra;
    int tonal_average;
@@ -118,7 +150,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,14 +165,43 @@ 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;
+   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(
-         (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, 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,24 +210,27 @@ 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;
       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;
+   st->clip = 1;
 
-   st->vbr_rate_norm = 0;
+   st->bitrate = 255000*channels;
+   st->vbr = 0;
    st->vbr_offset = 0;
    st->force_intra  = 0;
    st->delayedIntra = 1;
@@ -247,9 +317,9 @@ static int transient_analysis(const celt_word32 * restrict in, int len, int C,
    for (i=0;i<N;i++)
    {
       int j;
-      float max_abs=0;
+      celt_word16 max_abs=0;
       for (j=0;j<block;j++)
-         max_abs = MAX32(max_abs, tmp[i*block+j]);
+         max_abs = MAX16(max_abs, ABS16(tmp[i*block+j]));
       bins[i] = max_abs;
    }
    for (i=0;i<N;i++)
@@ -372,10 +442,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 +460,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);
@@ -610,10 +687,10 @@ static void tf_encode(int start, int end, int isTransient, int *tf_res, int LM,
    int tf_select_rsv;
    int tf_changed;
    int logp;
-   ec_uint32 budget;
-   ec_uint32 tell;
-   budget = enc->buf->storage*8;
-   tell = ec_enc_tell(enc, 0);
+   celt_uint32 budget;
+   celt_uint32 tell;
+   budget = enc->storage*8;
+   tell = ec_tell(enc);
    logp = isTransient ? 2 : 4;
    /* Reserve space to code the tf_select decision. */
    tf_select_rsv = LM>0 && tell+logp+1 <= budget;
@@ -624,7 +701,7 @@ static void tf_encode(int start, int end, int isTransient, int *tf_res, int LM,
       if (tell+logp<=budget)
       {
          ec_enc_bit_logp(enc, tf_res[i] ^ curr, logp);
-         tell = ec_enc_tell(enc, 0);
+         tell = ec_tell(enc);
          curr = tf_res[i];
          tf_changed |= curr;
       }
@@ -650,11 +727,11 @@ static void tf_decode(int start, int end, int isTransient, int *tf_res, int LM,
    int tf_select_rsv;
    int tf_changed;
    int logp;
-   ec_uint32 budget;
-   ec_uint32 tell;
+   celt_uint32 budget;
+   celt_uint32 tell;
 
-   budget = dec->buf->storage*8;
-   tell = ec_dec_tell(dec, 0);
+   budget = dec->storage*8;
+   tell = ec_tell(dec);
    logp = isTransient ? 2 : 4;
    tf_select_rsv = LM>0 && tell+logp+1<=budget;
    budget -= tf_select_rsv;
@@ -664,7 +741,7 @@ static void tf_decode(int start, int end, int isTransient, int *tf_res, int LM,
       if (tell+logp<=budget)
       {
          curr ^= ec_dec_bit_logp(dec, logp);
-         tell = ec_dec_tell(dec, 0);
+         tell = ec_tell(dec);
          tf_changed |= curr;
       }
       tf_res[i] = curr;
@@ -683,8 +760,19 @@ static void tf_decode(int start, int end, int isTransient, int *tf_res, int LM,
    }
 }
 
+static void init_caps(const CELTMode *m,int *cap,int LM,int C)
+{
+   int i;
+   for (i=0;i<m->nbEBands;i++)
+   {
+      int N;
+      N=(m->eBands[i+1]-m->eBands[i])<<LM;
+      cap[i] = (m->cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2;
+   }
+}
+
 static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X,
-      const celt_word16 *bandLogE, int nbEBands, int LM, int C, int N0)
+      const celt_word16 *bandLogE, int end, int LM, int C, int N0)
 {
    int i;
    celt_word32 diff=0;
@@ -716,12 +804,12 @@ static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X,
 
    /* Estimate spectral tilt */
    c=0; do {
-      for (i=0;i<nbEBands-1;i++)
+      for (i=0;i<end-1;i++)
       {
-         diff += bandLogE[i+c*nbEBands]*(celt_int32)(2+2*i-nbEBands);
+         diff += bandLogE[i+c*m->nbEBands]*(celt_int32)(2+2*i-m->nbEBands);
       }
    } while (++c<0);
-   diff /= C*(nbEBands-1);
+   diff /= C*(end-1);
    /*printf("%f\n", diff);*/
    if (diff > QCONST16(2.f, DB_SHIFT))
       trim_index--;
@@ -771,16 +859,17 @@ static int stereo_analysis(const CELTMode *m, const celt_norm *X,
 }
 
 #ifdef FIXED_POINT
+CELT_STATIC
 int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
 {
 #else
+CELT_STATIC
 int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
 {
 #endif
    int i, c, N;
-   int bits;
-   ec_byte_buffer buf;
-   ec_enc         _enc;
+   celt_int32 bits;
+   ec_enc _enc;
    VARDECL(celt_sig, in);
    VARDECL(celt_sig, freq);
    VARDECL(celt_norm, X);
@@ -789,6 +878,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);
@@ -799,7 +889,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;
@@ -817,6 +908,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;
@@ -828,37 +920,58 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    if (nbCompressedBytes<2 || pcm==NULL)
      return CELT_BAD_ARG;
 
-   for (LM=0;LM<4;LM++)
+   /* Can't produce more than 1275 output bytes */
+   nbCompressedBytes = IMIN(nbCompressedBytes,1275);
+   frame_size *= st->upsample;
+   for (LM=0;LM<=st->mode->maxLM;LM++)
       if (st->mode->shortMdctSize<<LM==frame_size)
          break;
-   if (LM>=MAX_CONFIG_SIZES)
+   if (LM>st->mode->maxLM)
       return CELT_BAD_ARG;
    M=1<<LM;
+   N = M*st->mode->shortMdctSize;
 
-   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)
    {
-      ec_byte_writeinit_buffer(&buf, compressed, nbCompressedBytes);
-      ec_enc_init(&_enc,&buf);
-      enc = &_enc;
       tell=1;
       nbFilledBytes=0;
    } else {
-      tell=ec_enc_tell(enc, 0);
+      tell=ec_tell(enc);
       nbFilledBytes=(tell+4)>>3;
    }
    nbAvailableBytes = nbCompressedBytes - nbFilledBytes;
 
-   vbr_rate = st->vbr_rate_norm<<LM;
+   if (st->vbr)
+   {
+      celt_int32 den=st->mode->Fs>>BITRES;
+      vbr_rate=(st->bitrate*frame_size+(den>>1))/den;
+      effectiveBytes = vbr_rate>>(3+BITRES);
+   } else {
+      celt_int32 tmp;
+      vbr_rate = 0;
+      tmp = st->bitrate*frame_size;
+      if (tell>1)
+         tmp += tell;
+      nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes,
+            (tmp+4*st->mode->Fs)/(8*st->mode->Fs)));
+      effectiveBytes = nbCompressedBytes;
+   }
+
+   if (enc==NULL)
+   {
+      ec_enc_init(&_enc, compressed, nbCompressedBytes);
+      enc = &_enc;
+   }
+
    if (vbr_rate>0)
    {
-      effectiveBytes = st->vbr_rate_norm>>BITRES<<LM>>3;
       /* Computes the max bit-rate allowed in VBR mode to avoid violating the
           target rate and buffering.
          We must do this up front so that bust-prevention logic triggers
@@ -869,60 +982,71 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
          celt_int32 max_allowed;
          /* We could use any multiple of vbr_rate as bound (depending on the
              delay).
-            This is clamped to ensure we use at least one byte if the encoder
+            This is clamped to ensure we use at least two bytes if the encoder
              was entirely empty, but to allow 0 in hybrid mode. */
          vbr_bound = vbr_rate;
-         max_allowed = IMIN(IMAX((tell+7>>3)-nbFilledBytes,
+         max_allowed = IMIN(IMAX(tell==1?2:0,
                vbr_rate+vbr_bound-st->vbr_reservoir>>(BITRES+3)),
                nbAvailableBytes);
          if(max_allowed < nbAvailableBytes)
          {
             nbCompressedBytes = nbFilledBytes+max_allowed;
             nbAvailableBytes = max_allowed;
-            ec_byte_shrink(&buf, nbCompressedBytes);
+            ec_enc_shrink(enc, nbCompressedBytes);
          }
       }
-   } else
-      effectiveBytes = nbCompressedBytes;
+   }
    total_bits = nbCompressedBytes*8;
 
    effEnd = st->end;
    if (effEnd > st->mode->effEBands)
       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 */
    {
       VARDECL(celt_sig, _pre);
       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);
+#ifndef FIXED_POINT
+            if (st->clip)
+               x = MAX32(-65536.f, MIN32(65536.f,x));
+#endif
+            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);
@@ -936,20 +1060,20 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
             effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2);
             total_bits=nbCompressedBytes*8;
             nbAvailableBytes=2;
-            ec_byte_shrink(&buf, nbCompressedBytes);
+            ec_enc_shrink(enc, nbCompressedBytes);
          }
          /* Pretend we've filled all the remaining bits with zeros
             (that's what the initialiser did anyway) */
          tell = nbCompressedBytes*8;
-         enc->nbits_total+=tell-ec_enc_tell(enc,0);
+         enc->nbits_total+=tell-ec_tell(enc);
       }
 #ifdef ENABLE_POSTFILTER
-      if (nbAvailableBytes>12*C && st->start==0 && !silence)
+      if (nbAvailableBytes>12*C && st->start==0 && !silence && !st->disable_pf && st->complexity >= 5)
       {
          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;
@@ -983,48 +1107,58 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
       pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15));
       if (gain1<pf_threshold)
       {
-         if(st->start==0 && tell+17<=total_bits)
+         if(st->start==0 && tell+16<=total_bits)
             ec_enc_bit_logp(enc, 0, 1);
          gain1 = 0;
          pf_on = 0;
       } else {
+         /*This block is not gated by a total bits check only because
+           of the nbAvailableBytes check above.*/
          int qg;
          int octave;
 
-         if (gain1 > QCONST16(.6f,15))
-            gain1 = QCONST16(.6f,15);
          if (ABS16(gain1-st->prefilter_gain)<QCONST16(.1f,15))
             gain1=st->prefilter_gain;
 
 #ifdef FIXED_POINT
-         qg = ((gain1+2048)>>12)-2;
+         qg = ((gain1+1536)>>10)/3-1;
 #else
-         qg = floor(.5+gain1*8)-2;
+         qg = floor(.5+gain1*32/3)-1;
 #endif
+         qg = IMAX(0, IMIN(7, qg));
          ec_enc_bit_logp(enc, 1, 1);
          pitch_index += 1;
          octave = EC_ILOG(pitch_index)-5;
          ec_enc_uint(enc, octave, 6);
          ec_enc_bits(enc, pitch_index-(16<<octave), 4+octave);
          pitch_index -= 1;
-         ec_enc_bits(enc, qg, 2);
-         gain1 = QCONST16(.125f,15)*(qg+2);
-         ec_enc_icdf(enc, prefilter_tapset, tapset_icdf, 2);
+         ec_enc_bits(enc, qg, 3);
+         if (ec_tell(enc)+2<=total_bits)
+            ec_enc_icdf(enc, prefilter_tapset, tapset_icdf, 2);
+         else
+           prefilter_tapset = 0;
+         gain1 = QCONST16(0.09375f,15)*(qg+1);
          pf_on = 1;
       }
       /*printf("%d %f\n", pitch_index, gain1);*/
 #else /* ENABLE_POSTFILTER */
-      if(st->start==0 && tell+17<=total_bits)
+      if(st->start==0 && tell+16<=total_bits)
          ec_enc_bit_logp(enc, 0, 1);
       pf_on = 0;
 #endif /* ENABLE_POSTFILTER */
 
       c=0; do {
+         int offset = st->mode->shortMdctSize-st->mode->overlap;
          st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
          CELT_COPY(in+c*(N+st->overlap), st->in_mem+c*(st->overlap), st->overlap);
 #ifdef ENABLE_POSTFILTER
-         comb_filter(in+c*(N+st->overlap)+st->overlap, pre[c]+COMBFILTER_MAXPERIOD,
-               st->prefilter_period, pitch_index, N, -st->prefilter_gain, -gain1,
+         if (offset)
+            comb_filter(in+c*(N+st->overlap)+st->overlap, pre[c]+COMBFILTER_MAXPERIOD,
+                  st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain,
+                  st->prefilter_tapset, st->prefilter_tapset, NULL, 0);
+
+         comb_filter(in+c*(N+st->overlap)+st->overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset,
+               st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1,
                st->prefilter_tapset, prefilter_tapset, st->mode->window, st->mode->overlap);
 #endif /* ENABLE_POSTFILTER */
          CELT_COPY(st->in_mem+c*(st->overlap), in+c*(N+st->overlap)+N, st->overlap);
@@ -1038,7 +1172,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;
    }
@@ -1051,11 +1185,11 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
 
    isTransient = 0;
    shortBlocks = 0;
-   if (LM>0 && ec_enc_tell(enc, 0)+3<=total_bits)
+   if (LM>0 && ec_tell(enc)+3<=total_bits)
    {
       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;
@@ -1063,12 +1197,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);
@@ -1093,7 +1243,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    tf_encode(st->start, st->end, isTransient, tf_res, LM, tf_select, enc);
 
    st->spread_decision = SPREAD_NORMAL;
-   if (ec_enc_tell(enc, 0)+4<=total_bits)
+   if (ec_tell(enc)+4<=total_bits)
    {
       if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C)
       {
@@ -1107,8 +1257,10 @@ 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);
 
+   init_caps(st->mode,cap,LM,C);
    for (i=0;i<st->mode->nbEBands;i++)
       offsets[i] = 0;
    /* Dynamic allocation code */
@@ -1124,7 +1276,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
          t1 = 2;
          t2 = 4;
       }
-      for (i=1;i<st->mode->nbEBands-1;i++)
+      for (i=st->start+1;i<st->end-1;i++)
       {
          celt_word32 d2;
          d2 = 2*bandLogE[i]-bandLogE[i-1]-bandLogE[i+1];
@@ -1140,7 +1292,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    dynalloc_logp = 6;
    total_bits<<=BITRES;
    total_boost = 0;
-   tell = ec_enc_tell(enc, BITRES);
+   tell = ec_tell_frac(enc);
    for (i=st->start;i<st->end;i++)
    {
       int width, quanta;
@@ -1154,12 +1306,12 @@ 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];
          ec_enc_bit_logp(enc, flag, dynalloc_loop_logp);
-         tell = ec_enc_tell(enc, BITRES);
+         tell = ec_tell_frac(enc);
          if (!flag)
             break;
          boost += quanta;
@@ -1175,9 +1327,9 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    if (tell+(6<<BITRES) <= total_bits - total_boost)
    {
       alloc_trim = alloc_trim_analysis(st->mode, X, bandLogE,
-            st->mode->nbEBands, LM, C, N);
+            st->end, LM, C, N);
       ec_enc_icdf(enc, alloc_trim, trim_icdf, 7);
-      tell = ec_enc_tell(enc, BITRES);
+      tell = ec_tell_frac(enc);
    }
 
    /* Variable bitrate */
@@ -1252,7 +1404,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
      }
      nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes);
      /* This moves the raw bits to take into account the new compressed size */
-     ec_byte_shrink(&buf, nbCompressedBytes);
+     ec_enc_shrink(enc, nbCompressedBytes);
    }
    if (C==2)
    {
@@ -1289,13 +1441,13 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    ALLOC(pulses, st->mode->nbEBands, int);
    ALLOC(fine_priority, st->mode->nbEBands, int);
 
-   /* bits =   packet size        -       where we are         - safety*/
-   bits = (nbCompressedBytes*8<<BITRES) - ec_enc_tell(enc, BITRES) - 1;
+   /* bits =           packet size                    - where we are - safety*/
+   bits = ((celt_int32)nbCompressedBytes*8<<BITRES) - ec_tell_frac(enc) - 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);
@@ -1312,17 +1464,17 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
 #endif
 
    /* Residual quantisation */
-   ALLOC(collapse_masks, st->mode->nbEBands, unsigned char);
+   ALLOC(collapse_masks, C*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)
    {
       anti_collapse_on = st->consec_transient<2;
       ec_enc_bits(enc, anti_collapse_on, 1);
    }
-   quant_energy_finalise(st->mode, st->start, st->end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_enc_tell(enc, 0), enc, C);
+   quant_energy_finalise(st->mode, st->start, st->end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C);
 
    if (silence)
    {
@@ -1349,7 +1501,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
 #endif
       if (anti_collapse_on)
       {
-         anti_collapse(st->mode, X, collapse_masks, LM, C, N,
+         anti_collapse(st->mode, X, collapse_masks, LM, C, CC, N,
                st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng);
       }
 
@@ -1357,7 +1509,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
@@ -1369,37 +1521,37 @@ 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 {
          st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
          st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD);
+         comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, st->mode->shortMdctSize,
+               st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset,
+               st->mode->window, st->overlap);
          if (LM!=0)
-         {
-            comb_filter(out_mem[c], out_mem[c], st->prefilter_period, st->prefilter_period, st->overlap,
-                  st->prefilter_gain, st->prefilter_gain, st->prefilter_tapset, st->prefilter_tapset,
-                  NULL, 0);
-            comb_filter(out_mem[c]+st->overlap, out_mem[c]+st->overlap, st->prefilter_period, pitch_index, N-st->overlap,
+            comb_filter(out_mem[c]+st->mode->shortMdctSize, out_mem[c]+st->mode->shortMdctSize, st->prefilter_period, pitch_index, N-st->mode->shortMdctSize,
                   st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset,
                   st->mode->window, st->mode->overlap);
-         } else {
-            comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, N,
-                  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;
@@ -1409,6 +1561,19 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    st->prefilter_period = pitch_index;
    st->prefilter_gain = gain1;
    st->prefilter_tapset = prefilter_tapset;
+#ifdef RESYNTH
+   if (LM!=0)
+   {
+      st->prefilter_period_old = st->prefilter_period;
+      st->prefilter_gain_old = st->prefilter_gain;
+      st->prefilter_tapset_old = st->prefilter_tapset;
+   }
+#endif
+
+   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
@@ -1417,13 +1582,16 @@ 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<CC*st->mode->nbEBands;i++)
+         oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]);
    }
    if (isTransient)
       st->consec_transient++;
@@ -1436,7 +1604,7 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
    ec_enc_done(enc);
    
    RESTORE_STACK;
-   if (ec_enc_get_error(enc))
+   if (ec_get_error(enc))
       return CELT_CORRUPTED_DATA;
    else
       return nbCompressedBytes;
@@ -1444,24 +1612,19 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
 
 #ifdef FIXED_POINT
 #ifndef DISABLE_FLOAT_API
+CELT_STATIC
 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);
+   ALLOC_STACK;
    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++)
@@ -1478,24 +1641,19 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int
 }
 #endif /*DISABLE_FLOAT_API*/
 #else
+CELT_STATIC
 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);
+   ALLOC_STACK;
    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]);
@@ -1567,14 +1725,8 @@ int celt_encoder_ctl(CELTEncoder * restrict st, int request, ...)
          int value = va_arg(ap, celt_int32);
          if (value<0 || value>2)
             goto bad_arg;
-         if (value==0)
-         {
-            st->force_intra   = 1;
-         } else if (value==1) {
-            st->force_intra   = 0;
-         } else {
-            st->force_intra   = 0;
-         }   
+         st->disable_pf = value<=1;
+         st->force_intra = value==0;
       }
       break;
       case CELT_SET_VBR_CONSTRAINT_REQUEST:
@@ -1583,23 +1735,33 @@ int celt_encoder_ctl(CELTEncoder * restrict st, int request, ...)
          st->constrained_vbr = value;
       }
       break;
-      case CELT_SET_VBR_RATE_REQUEST:
+      case CELT_SET_VBR_REQUEST:
+      {
+         celt_int32 value = va_arg(ap, celt_int32);
+         st->vbr = value;
+      }
+      break;
+      case CELT_SET_BITRATE_REQUEST:
       {
          celt_int32 value = va_arg(ap, celt_int32);
-         int frame_rate;
-         int N = st->mode->shortMdctSize;
-         if (value<0)
+         if (value<=500)
             goto bad_arg;
-         if (value>3072000)
-            value = 3072000;
-         frame_rate = ((st->mode->Fs<<3)+(N>>1))/N;
-         st->vbr_rate_norm = ((value<<(BITRES+3))+(frame_rate>>1))/frame_rate;
+         value = IMIN(value, 260000*st->channels);
+         st->bitrate = 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->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;
@@ -1607,6 +1769,12 @@ int celt_encoder_ctl(CELTEncoder * restrict st, int request, ...)
          st->tonal_average = QCONST16(1.f,8);
       }
       break;
+      case CELT_SET_INPUT_CLIPPING_REQUEST:
+      {
+         celt_int32 value = va_arg(ap, celt_int32);
+         st->clip = value;
+      }
+      break;
       default:
          goto bad_request;
    }
@@ -1634,13 +1802,15 @@ 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 */
 #define DECODER_RESET_START rng
 
-   ec_uint32 rng;
+   celt_uint32 rng;
    int last_pitch_index;
    int loss_count;
    int postfilter_period;
@@ -1660,7 +1830,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)
@@ -1669,14 +1845,43 @@ 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;
+   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(
-         (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, const CELTMode *mode, int channels, int *error)
+CELTDecoder *celt_decoder_init(CELTDecoder *st, int sampling_rate, int channels, int *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)
 {
    if (channels < 0 || channels > 2)
    {
@@ -1692,12 +1897,13 @@ CELTDecoder *celt_decoder_init(CELTDecoder *st, const CELTMode *mode, int channe
       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;
 
@@ -1728,6 +1934,7 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p
    celt_word16 *lpc;
    celt_word32 *out_syn[2];
    celt_word16 *oldBandE, *oldLogE2, *backgroundLogE;
+   int plc=1;
    SAVE_STACK;
    
    c=0; do {
@@ -1760,19 +1967,29 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p
       log2Amp(st->mode, st->start, st->end, bandE, backgroundLogE, C);
 
       seed = st->rng;
-      for (i=0;i<C*N;i++)
+      for (c=0;c<C;c++)
       {
-            seed = lcg_rand(seed);
-            X[i] = (celt_int32)(seed)>>20;
+         for (i=0;i<st->mode->effEBands;i++)
+         {
+            int j;
+            int boffs;
+            int blen;
+            boffs = N*c+(st->mode->eBands[i]<<LM);
+            blen = (st->mode->eBands[i+1]-st->mode->eBands[i])<<LM;
+            for (j=0;j<blen;j++)
+            {
+               seed = lcg_rand(seed);
+               X[boffs+j] = (celt_int32)(seed)>>20;
+            }
+            renormalise_vector(X+boffs, blen, Q15ONE);
+         }
       }
       st->rng = seed;
-      for (c=0;c<C;c++)
-         for (i=0;i<st->mode->nbEBands;i++)
-            renormalise_vector(X+N*c+(st->mode->eBands[i]<<LM), (st->mode->eBands[i+1]-st->mode->eBands[i])<<LM, Q15ONE);
 
-      denormalise_bands(st->mode, X, freq, bandE, st->mode->nbEBands, C, 1<<LM);
+      denormalise_bands(st->mode, X, freq, bandE, st->mode->effEBands, C, 1<<LM);
 
       compute_inv_mdcts(st->mode, 0, freq, out_syn, overlap_mem, C, LM);
+      plc = 0;
    } else if (st->loss_count == 0)
    {
       celt_word16 pitch_buf[MAX_PERIOD>>1];
@@ -1790,143 +2007,146 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p
       fade = QCONST16(.8f,15);
    }
 
-   c=0; do {
-      /* FIXME: This is more memory than necessary */
-      celt_word32 e[2*MAX_PERIOD];
-      celt_word16 exc[2*MAX_PERIOD];
-      celt_word32 ac[LPC_ORDER+1];
-      celt_word16 decay = 1;
-      celt_word32 S1=0;
-      celt_word16 mem[LPC_ORDER]={0};
-
-      offset = MAX_PERIOD-pitch_index;
-      for (i=0;i<MAX_PERIOD;i++)
-         exc[i] = ROUND16(out_mem[c][i], SIG_SHIFT);
-
-      if (st->loss_count == 0)
-      {
-         _celt_autocorr(exc, ac, st->mode->window, st->mode->overlap,
-                        LPC_ORDER, MAX_PERIOD);
+   if (plc)
+   {
+      c=0; do {
+         /* FIXME: This is more memory than necessary */
+         celt_word32 e[2*MAX_PERIOD];
+         celt_word16 exc[2*MAX_PERIOD];
+         celt_word32 ac[LPC_ORDER+1];
+         celt_word16 decay = 1;
+         celt_word32 S1=0;
+         celt_word16 mem[LPC_ORDER]={0};
+
+         offset = MAX_PERIOD-pitch_index;
+         for (i=0;i<MAX_PERIOD;i++)
+            exc[i] = ROUND16(out_mem[c][i], SIG_SHIFT);
+
+         if (st->loss_count == 0)
+         {
+            _celt_autocorr(exc, ac, st->mode->window, st->mode->overlap,
+                  LPC_ORDER, MAX_PERIOD);
 
-         /* Noise floor -40 dB */
+            /* Noise floor -40 dB */
 #ifdef FIXED_POINT
-         ac[0] += SHR32(ac[0],13);
+            ac[0] += SHR32(ac[0],13);
 #else
-         ac[0] *= 1.0001f;
+            ac[0] *= 1.0001f;
 #endif
-         /* Lag windowing */
-         for (i=1;i<=LPC_ORDER;i++)
-         {
-            /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+            /* Lag windowing */
+            for (i=1;i<=LPC_ORDER;i++)
+            {
+               /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
 #ifdef FIXED_POINT
-            ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
+               ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
 #else
-            ac[i] -= ac[i]*(.008f*i)*(.008f*i);
+               ac[i] -= ac[i]*(.008f*i)*(.008f*i);
 #endif
-         }
+            }
 
-         _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER);
-      }
-      for (i=0;i<LPC_ORDER;i++)
-         mem[i] = ROUND16(out_mem[c][MAX_PERIOD-1-i], SIG_SHIFT);
-      fir(exc, lpc+c*LPC_ORDER, exc, MAX_PERIOD, LPC_ORDER, mem);
-      /*for (i=0;i<MAX_PERIOD;i++)printf("%d ", exc[i]); printf("\n");*/
-      /* Check if the waveform is decaying (and if so how fast) */
-      {
-         celt_word32 E1=1, E2=1;
-         int period;
-         if (pitch_index <= MAX_PERIOD/2)
-            period = pitch_index;
-         else
-            period = MAX_PERIOD/2;
-         for (i=0;i<period;i++)
+            _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER);
+         }
+         for (i=0;i<LPC_ORDER;i++)
+            mem[i] = ROUND16(out_mem[c][MAX_PERIOD-1-i], SIG_SHIFT);
+         fir(exc, lpc+c*LPC_ORDER, exc, MAX_PERIOD, LPC_ORDER, mem);
+         /*for (i=0;i<MAX_PERIOD;i++)printf("%d ", exc[i]); printf("\n");*/
+         /* Check if the waveform is decaying (and if so how fast) */
          {
-            E1 += SHR32(MULT16_16(exc[MAX_PERIOD-period+i],exc[MAX_PERIOD-period+i]),8);
-            E2 += SHR32(MULT16_16(exc[MAX_PERIOD-2*period+i],exc[MAX_PERIOD-2*period+i]),8);
+            celt_word32 E1=1, E2=1;
+            int period;
+            if (pitch_index <= MAX_PERIOD/2)
+               period = pitch_index;
+            else
+               period = MAX_PERIOD/2;
+            for (i=0;i<period;i++)
+            {
+               E1 += SHR32(MULT16_16(exc[MAX_PERIOD-period+i],exc[MAX_PERIOD-period+i]),8);
+               E2 += SHR32(MULT16_16(exc[MAX_PERIOD-2*period+i],exc[MAX_PERIOD-2*period+i]),8);
+            }
+            if (E1 > E2)
+               E1 = E2;
+            decay = celt_sqrt(frac_div32(SHR(E1,1),E2));
          }
-         if (E1 > E2)
-            E1 = E2;
-         decay = celt_sqrt(frac_div32(SHR(E1,1),E2));
-      }
 
-      /* Copy excitation, taking decay into account */
-      for (i=0;i<len+st->mode->overlap;i++)
-      {
-         celt_word16 tmp;
-         if (offset+i >= MAX_PERIOD)
+         /* Copy excitation, taking decay into account */
+         for (i=0;i<len+st->mode->overlap;i++)
          {
-            offset -= pitch_index;
-            decay = MULT16_16_Q15(decay, decay);
+            celt_word16 tmp;
+            if (offset+i >= MAX_PERIOD)
+            {
+               offset -= pitch_index;
+               decay = MULT16_16_Q15(decay, decay);
+            }
+            e[i] = SHL32(EXTEND32(MULT16_16_Q15(decay, exc[offset+i])), SIG_SHIFT);
+            tmp = ROUND16(out_mem[c][offset+i],SIG_SHIFT);
+            S1 += SHR32(MULT16_16(tmp,tmp),8);
          }
-         e[i] = SHL32(EXTEND32(MULT16_16_Q15(decay, exc[offset+i])), SIG_SHIFT);
-         tmp = ROUND16(out_mem[c][offset+i],SIG_SHIFT);
-         S1 += SHR32(MULT16_16(tmp,tmp),8);
-      }
-      for (i=0;i<LPC_ORDER;i++)
-         mem[i] = ROUND16(out_mem[c][MAX_PERIOD-1-i], SIG_SHIFT);
-      for (i=0;i<len+st->mode->overlap;i++)
-         e[i] = MULT16_32_Q15(fade, e[i]);
-      iir(e, lpc+c*LPC_ORDER, e, len+st->mode->overlap, LPC_ORDER, mem);
+         for (i=0;i<LPC_ORDER;i++)
+            mem[i] = ROUND16(out_mem[c][MAX_PERIOD-1-i], SIG_SHIFT);
+         for (i=0;i<len+st->mode->overlap;i++)
+            e[i] = MULT16_32_Q15(fade, e[i]);
+         iir(e, lpc+c*LPC_ORDER, e, len+st->mode->overlap, LPC_ORDER, mem);
 
-      {
-         celt_word32 S2=0;
-         for (i=0;i<len+overlap;i++)
          {
-            celt_word16 tmp = ROUND16(e[i],SIG_SHIFT);
-            S2 += SHR32(MULT16_16(tmp,tmp),8);
-         }
-         /* This checks for an "explosion" in the synthesis */
+            celt_word32 S2=0;
+            for (i=0;i<len+overlap;i++)
+            {
+               celt_word16 tmp = ROUND16(e[i],SIG_SHIFT);
+               S2 += SHR32(MULT16_16(tmp,tmp),8);
+            }
+            /* This checks for an "explosion" in the synthesis */
 #ifdef FIXED_POINT
-         if (!(S1 > SHR32(S2,2)))
+            if (!(S1 > SHR32(S2,2)))
 #else
-         /* Float test is written this way to catch NaNs at the same time */
-         if (!(S1 > 0.2f*S2))
+               /* Float test is written this way to catch NaNs at the same time */
+               if (!(S1 > 0.2f*S2))
 #endif
-         {
-            for (i=0;i<len+overlap;i++)
-               e[i] = 0;
-         } else if (S1 < S2)
-         {
-            celt_word16 ratio = celt_sqrt(frac_div32(SHR32(S1,1)+1,S2+1));
-            for (i=0;i<len+overlap;i++)
-               e[i] = MULT16_32_Q15(ratio, e[i]);
+               {
+                  for (i=0;i<len+overlap;i++)
+                     e[i] = 0;
+               } else if (S1 < S2)
+               {
+                  celt_word16 ratio = celt_sqrt(frac_div32(SHR32(S1,1)+1,S2+1));
+                  for (i=0;i<len+overlap;i++)
+                     e[i] = MULT16_32_Q15(ratio, e[i]);
+               }
          }
-      }
 
 #ifdef ENABLE_POSTFILTER
-      /* Apply post-filter to the MDCT overlap of the previous frame */
-      comb_filter(out_mem[c]+MAX_PERIOD, out_mem[c]+MAX_PERIOD, st->postfilter_period, st->postfilter_period, st->overlap,
-                  st->postfilter_gain, st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset,
-                  NULL, 0);
+         /* Apply post-filter to the MDCT overlap of the previous frame */
+         comb_filter(out_mem[c]+MAX_PERIOD, out_mem[c]+MAX_PERIOD, st->postfilter_period, st->postfilter_period, st->overlap,
+               st->postfilter_gain, st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset,
+               NULL, 0);
 #endif /* ENABLE_POSTFILTER */
 
-      for (i=0;i<MAX_PERIOD+st->mode->overlap-N;i++)
-         out_mem[c][i] = out_mem[c][N+i];
+         for (i=0;i<MAX_PERIOD+st->mode->overlap-N;i++)
+            out_mem[c][i] = out_mem[c][N+i];
 
-      /* Apply TDAC to the concealed audio so that it blends with the
+         /* Apply TDAC to the concealed audio so that it blends with the
          previous and next frames */
-      for (i=0;i<overlap/2;i++)
-      {
-         celt_word32 tmp;
-         tmp = MULT16_32_Q15(st->mode->window[i],           e[N+overlap-1-i]) +
-               MULT16_32_Q15(st->mode->window[overlap-i-1], e[N+i          ]);
-         out_mem[c][MAX_PERIOD+i] = MULT16_32_Q15(st->mode->window[overlap-i-1], tmp);
-         out_mem[c][MAX_PERIOD+overlap-i-1] = MULT16_32_Q15(st->mode->window[i], tmp);
-      }
-      for (i=0;i<N;i++)
-         out_mem[c][MAX_PERIOD-N+i] = e[i];
+         for (i=0;i<overlap/2;i++)
+         {
+            celt_word32 tmp;
+            tmp = MULT16_32_Q15(st->mode->window[i],           e[N+overlap-1-i]) +
+                  MULT16_32_Q15(st->mode->window[overlap-i-1], e[N+i          ]);
+            out_mem[c][MAX_PERIOD+i] = MULT16_32_Q15(st->mode->window[overlap-i-1], tmp);
+            out_mem[c][MAX_PERIOD+overlap-i-1] = MULT16_32_Q15(st->mode->window[i], tmp);
+         }
+         for (i=0;i<N;i++)
+            out_mem[c][MAX_PERIOD-N+i] = e[i];
 
 #ifdef ENABLE_POSTFILTER
-      /* Apply pre-filter to the MDCT overlap for the next frame (post-filter will be applied then) */
-      comb_filter(e, out_mem[c]+MAX_PERIOD, st->postfilter_period, st->postfilter_period, st->overlap,
-                  -st->postfilter_gain, -st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset,
-                  NULL, 0);
+         /* Apply pre-filter to the MDCT overlap for the next frame (post-filter will be applied then) */
+         comb_filter(e, out_mem[c]+MAX_PERIOD, st->postfilter_period, st->postfilter_period, st->overlap,
+               -st->postfilter_gain, -st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset,
+               NULL, 0);
 #endif /* ENABLE_POSTFILTER */
-      for (i=0;i<overlap;i++)
-         out_mem[c][MAX_PERIOD+i] = e[i];
-   } while (++c<C);
+         for (i=0;i<overlap;i++)
+            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++;
 
@@ -1934,22 +2154,24 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p
 }
 
 #ifdef FIXED_POINT
+CELT_STATIC
 int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, celt_int16 * restrict pcm, int frame_size, ec_dec *dec)
 {
 #else
+CELT_STATIC
 int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, celt_sig * restrict pcm, int frame_size, ec_dec *dec)
 {
 #endif
    int c, i, N;
    int spread_decision;
-   int bits;
+   celt_int32 bits;
    ec_dec _dec;
-   ec_byte_buffer buf;
    VARDECL(celt_sig, freq);
    VARDECL(celt_norm, X);
    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);
@@ -1964,7 +2186,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;
@@ -1974,22 +2196,25 @@ 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)
+   if (len<0 || len>1275 || pcm==NULL)
       return CELT_BAD_ARG;
 
-   for (LM=0;LM<4;LM++)
+   frame_size *= st->downsample;
+   for (LM=0;LM<=st->mode->maxLM;LM++)
       if (st->mode->shortMdctSize<<LM==frame_size)
          break;
-   if (LM>=MAX_CONFIG_SIZES)
+   if (LM>st->mode->maxLM)
       return CELT_BAD_ARG;
    M=1<<LM;
 
@@ -1997,12 +2222,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;
 
@@ -2010,17 +2235,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)
    {
@@ -2035,13 +2260,22 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    
    if (dec == NULL)
    {
-      ec_byte_readinit(&buf,(unsigned char*)data,len);
-      ec_dec_init(&_dec,&buf);
+      ec_dec_init(&_dec,(unsigned char*)data,len);
       dec = &_dec;
    }
 
+   if (C>CC)
+   {
+      RESTORE_STACK;
+      return CELT_CORRUPTED_DATA;
+   } else if (C<CC)
+   {
+      for (i=0;i<st->mode->nbEBands;i++)
+         oldBandE[i]=MAX16(oldBandE[i],oldBandE[st->mode->nbEBands+i]);
+   }
+
    total_bits = len*8;
-   tell = ec_dec_tell(dec, 0);
+   tell = ec_tell(dec);
 
    if (tell==1)
       silence = ec_dec_bit_logp(dec, 15);
@@ -2051,13 +2285,13 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    {
       /* Pretend we've read all the remaining bits */
       tell = len*8;
-      dec->nbits_total+=tell-ec_dec_tell(dec,0);
+      dec->nbits_total+=tell-ec_tell(dec);
    }
 
    postfilter_gain = 0;
    postfilter_pitch = 0;
    postfilter_tapset = 0;
-   if (st->start==0 && tell+17 <= total_bits)
+   if (st->start==0 && tell+16 <= total_bits)
    {
       if(ec_dec_bit_logp(dec, 1))
       {
@@ -2065,21 +2299,22 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
          int qg, octave;
          octave = ec_dec_uint(dec, 6);
          postfilter_pitch = (16<<octave)+ec_dec_bits(dec, 4+octave)-1;
-         qg = ec_dec_bits(dec, 2);
-         postfilter_tapset = ec_dec_icdf(dec, tapset_icdf, 2);
-         postfilter_gain = QCONST16(.125f,15)*(qg+2);
+         qg = ec_dec_bits(dec, 3);
+         if (ec_tell(dec)+2<=total_bits)
+            postfilter_tapset = ec_dec_icdf(dec, tapset_icdf, 2);
+         postfilter_gain = QCONST16(.09375f,15)*(qg+1);
 #else /* ENABLE_POSTFILTER */
          RESTORE_STACK;
          return CELT_CORRUPTED_DATA;
 #endif /* ENABLE_POSTFILTER */
       }
-      tell = ec_dec_tell(dec, 0);
+      tell = ec_tell(dec);
    }
 
    if (LM > 0 && tell+3 <= total_bits)
    {
       isTransient = ec_dec_bit_logp(dec, 3);
-      tell = ec_dec_tell(dec, 0);
+      tell = ec_tell(dec);
    }
    else
       isTransient = 0;
@@ -2098,18 +2333,21 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    ALLOC(tf_res, st->mode->nbEBands, int);
    tf_decode(st->start, st->end, isTransient, tf_res, LM, dec);
 
-   tell = ec_dec_tell(dec, 0);
+   tell = ec_tell(dec);
    spread_decision = SPREAD_NORMAL;
    if (tell+4 <= total_bits)
       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);
 
+   init_caps(st->mode,cap,LM,C);
+
    dynalloc_logp = 6;
    total_bits<<=BITRES;
-   tell = ec_dec_tell(dec, BITRES);
+   tell = ec_tell_frac(dec);
    for (i=st->start;i<st->end;i++)
    {
       int width, quanta;
@@ -2121,12 +2359,11 @@ 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);
-         tell = ec_dec_tell(dec, BITRES);
+         tell = ec_tell_frac(dec);
          if (!flag)
             break;
          boost += quanta;
@@ -2143,20 +2380,20 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    alloc_trim = tell+(6<<BITRES) <= total_bits ?
          ec_dec_icdf(dec, trim_icdf, 7) : 5;
 
-   bits = (len*8<<BITRES) - ec_dec_tell(dec, BITRES) - 1;
+   bits = ((celt_int32)len*8<<BITRES) - ec_tell_frac(dec) - 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);
 
    /* Decode fixed codebook */
-   ALLOC(collapse_masks, st->mode->nbEBands, unsigned char);
+   ALLOC(collapse_masks, C*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)
    {
@@ -2164,10 +2401,10 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    }
 
    unquant_energy_finalise(st->mode, st->start, st->end, oldBandE,
-         fine_quant, fine_priority, len*8-ec_dec_tell(dec, 0), dec, C);
+         fine_quant, fine_priority, len*8-ec_tell(dec), dec, C);
 
    if (anti_collapse_on)
-      anti_collapse(st->mode, X, collapse_masks, LM, C, N,
+      anti_collapse(st->mode, X, collapse_masks, LM, C, CC, N,
             st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng);
 
    log2Amp(st->mode, st->start, st->end, bandE, oldBandE, C);
@@ -2184,51 +2421,66 @@ 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
-      for (i=M*st->mode->eBands[effEnd];i<N;i++)
+   c=0; do {
+      int bound = M*st->mode->eBands[effEnd];
+      if (st->downsample!=1)
+         bound = IMIN(bound, N/st->downsample);
+      for (i=bound;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 {
       st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD);
       st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD);
+      comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, st->mode->shortMdctSize,
+            st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset,
+            st->mode->window, st->overlap);
       if (LM!=0)
-      {
-         comb_filter(out_syn[c], out_syn[c], st->postfilter_period, st->postfilter_period, st->overlap,
-               st->postfilter_gain, st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset,
-               NULL, 0);
-         comb_filter(out_syn[c]+st->overlap, out_syn[c]+st->overlap, st->postfilter_period, postfilter_pitch, N-st->overlap,
+         comb_filter(out_syn[c]+st->mode->shortMdctSize, out_syn[c]+st->mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-st->mode->shortMdctSize,
                st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset,
                st->mode->window, st->mode->overlap);
-      } else {
-         comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, N-st->overlap,
-               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;
    st->postfilter_period = postfilter_pitch;
    st->postfilter_gain = postfilter_gain;
    st->postfilter_tapset = postfilter_tapset;
+   if (LM!=0)
+   {
+      st->postfilter_period_old = st->postfilter_period;
+      st->postfilter_gain_old = st->postfilter_gain;
+      st->postfilter_tapset_old = st->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
    {
@@ -2236,22 +2488,25 @@ 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<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))
+   if (ec_tell(dec) > 8*len || ec_get_error(dec))
       return CELT_CORRUPTED_DATA;
    else
       return CELT_OK;
@@ -2259,24 +2514,19 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
 
 #ifdef FIXED_POINT
 #ifndef DISABLE_FLOAT_API
+CELT_STATIC
 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);
+   ALLOC_STACK;
    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);
@@ -2289,24 +2539,19 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
 }
 #endif /*DISABLE_FLOAT_API*/
 #else
+CELT_STATIC
 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);
+   ALLOC_STACK;
    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);
@@ -2358,15 +2603,23 @@ int celt_decoder_ctl(CELTDecoder * restrict st, int request, ...)
       case CELT_SET_END_BAND_REQUEST:
       {
          celt_int32 value = va_arg(ap, celt_int32);
-         if (value<0 || value>=st->mode->nbEBands)
+         if (value<1 || value>st->mode->nbEBands)
             goto bad_arg;
          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;