shithub: opus

Download patch

ref: 35095c6991197ca6b6bfa6870eecc10cba4042b7
parent: bc2c454886676a4c256b0df3958631c003469151
author: Jean-Marc Valin <[email protected]>
date: Thu Nov 4 09:24:44 EDT 2010

Squashed commit of the following:

commit a2cc77cb2744a2cb0551b9bfdf06b97457b6d449
Author: Jean-Marc Valin <[email protected]>
Date:   Thu Nov 4 13:11:21 2010 -0400

    Adding a switch to enable the post-filter (off by default)

commit 8e860dc0dfbe57e59fcbd5352588c5edff020e27
Author: Jean-Marc Valin <[email protected]>
Date:   Thu Nov 4 11:57:12 2010 -0400

    Allowing pitches up to 3000 Hz

commit 837412d37bbca32bb34bfb5941e132ff4b0a568c
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Nov 3 20:47:11 2010 -0400

    Pitch estimation tuning to prevent some cases of pitch halving

commit 34e20f24c85b40fffd1a15c5b632f2f78b26f081
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Nov 3 16:31:51 2010 -0400

    Resynthesis now purely a compile-time option with RESYNTH

commit d83fb5a9cc2ec4b6cce938662997643da1c5ed0d
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Nov 3 16:28:25 2010 -0400

    Fixes a divide by zero in remove_doubling()

commit bb91e05b7f8f91fd15a8a0daae3d8cb6bd8d81db
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Nov 3 15:55:48 2010 -0400

    Bring back resynthesis with RESYNTH macro

commit 31fe6f6b4997af0a46b8c62f523fe2dfdb7f56ae
Author: Jean-Marc Valin <[email protected]>
Date:   Tue Nov 2 17:55:04 2010 -0400

    Tuning the allocation tilt to give more bits to higher frequencies.

    Especially useful now that the post-filter can reduce low freq noise.

commit 919ba48f0369a87885334756cdfac2a448ce52d0
Author: Jean-Marc Valin <[email protected]>
Date:   Mon Nov 1 17:27:19 2010 -0400

    C89 fix

commit ee0dbb1855a82ee8c132ddaffcab4d072bb3455e
Author: Jean-Marc Valin <[email protected]>
Date:   Mon Nov 1 11:45:10 2010 -0400

    Complete fixed-point port of the pitch code (I think).

commit 4c7b3fd12a8f7469607b5ac57c85301a5de9fa81
Author: Jean-Marc Valin <[email protected]>
Date:   Mon Nov 1 10:55:43 2010 -0400

    More fixed-point pitch gain work

commit 26f1412188900199b63e187fcb0bd04db53c898a
Author: Jean-Marc Valin <[email protected]>
Date:   Mon Nov 1 10:39:25 2010 -0400

    Fixed-point version of the pitch gain calculation code

commit 27c73d008e9f50d282c3ad08e2f05f7006013ae1
Author: Jean-Marc Valin <[email protected]>
Date:   Sun Oct 31 16:50:26 2010 -0400

    Some more fixed-point work in remove_doubling()

commit 59354672cb3af794a0e46c0b2097d6441c75cdd1
Author: Jean-Marc Valin <[email protected]>
Date:   Sun Oct 31 09:57:36 2010 -0400

    Fixed a stupid fixed-point pf bug in the gain handling

commit be9e7dabf6c8b32bc049da260b58ff6085dc1ac3
Author: Jean-Marc Valin <[email protected]>
Date:   Sat Oct 30 01:52:09 2010 -0400

    Fixed-point: fixed frac_div32() that was broken a few commits ago.

commit 5b06270afc41a88915252cea14411be43650e704
Author: Jean-Marc Valin <[email protected]>
Date:   Fri Oct 29 17:45:44 2010 -0400

    This fixes VBR when encoding the pitch period with raw bits

commit 10e0488458ae558aa80d0b30cce70841ad081f73
Author: Jean-Marc Valin <[email protected]>
Date:   Fri Oct 29 16:50:31 2010 -0400

    Pitch period is now encoder with equal probability for each octave (rather than each lag).

    Max pitch gain allowed is now 0.625.

commit ca19396c1c1511c0e208b400efb51384fc7c200d
Author: Jean-Marc Valin <[email protected]>
Date:   Fri Oct 29 16:00:01 2010 -0400

    More fixed-point post-filter work

commit f3e42fde1b575bc587b2557b8b31a6085421a99c
Author: Jean-Marc Valin <[email protected]>
Date:   Fri Oct 29 14:39:23 2010 -0400

    More fixed-point work for the prefilter/postfilter

commit db945132d12b25ff25acc0701b91a1d8a81417d5
Author: Jean-Marc Valin <[email protected]>
Date:   Fri Oct 29 14:14:02 2010 -0400

    Making the pitch estimation work in fixed-point

    Even if there's still lots of float operations left.

commit acb3f96e04802ac4601295f83bef1f32593e261a
Author: Jean-Marc Valin <[email protected]>
Date:   Fri Oct 29 10:57:39 2010 -0400

    Making the PLC code consistent with the prefilter/postfilter

commit 8f64f5974ac846b8c35d0b692e0472f279206cf0
Author: Jean-Marc Valin <[email protected]>
Date:   Thu Oct 28 00:33:53 2010 -0400

    More tuning for remove_doubling()

commit 0c08f2ee9dcc135dd222fef30f5ad93e95e0d364
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Oct 27 17:48:02 2010 -0400

    Doing an interpolation step to improve the accuracy of the pitch estimate

    Also increasing the gain slightly.

commit 23d303e992f1fdc3d2668652603ae6311d3b91c5
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Oct 27 16:56:42 2010 -0400

    Implements a fixed 3-tap prefilter/postfilter to make the gain roll off with frequency

commit 881c5928adc1af9eb75c4b68e9eba94ab1d65adc
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Oct 27 14:47:30 2010 -0400

    Partially whitening the down-sampled signal before the pitch search

commit 4a8687deea8587007f14051cb966f6fd748893a1
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Oct 27 14:27:47 2010 -0400

    pitch_search() no longer computes the gain

commit a7f85bb6b10d9c509caec521ca444efb3f27df05
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Oct 27 14:00:53 2010 -0400

    remove_doubling() now works on the down-sampled signal

commit 06cb70e876873f79fed214ebbca35cb4c5057ec8
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Oct 27 11:28:53 2010 -0400

    Simplification to the pitch continuity code

commit 5201927c284a424eb8f21f63d358844b3de8c285
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Oct 27 11:04:02 2010 -0400

    Some more pitch doubling prevention code

commit 7ef63fbe1f78f79e1923bc42e06fbdf1ec28ffd3
Author: Jean-Marc Valin <[email protected]>
Date:   Wed Oct 27 06:49:28 2010 -0400

    Minor fix

commit eb37eaab32e7df074a7ddf0ae4781e57f827c4ad
Author: Jean-Marc Valin <[email protected]>
Date:   Tue Oct 26 18:32:25 2010 -0400

    Enforcing some pitch continuity

commit 751ef6edf2ee7721252cedb264bdf9b3f6244a9d
Author: Jean-Marc Valin <[email protected]>
Date:   Tue Oct 26 17:29:47 2010 -0400

    Code for preventing pitch doubling/halving

commit c12647ecb55b645005efbeede91880db72936f8d
Author: Jean-Marc Valin <[email protected]>
Date:   Tue Oct 26 00:04:34 2010 -0400

    Finally getting perfect reconstruction when pitch changes

    Post-filter now delays the filter coefs by the overlap so that the pre-filter
    and post-filter are synchronised.

commit f854311d945bb375039a4a4a4fea782b648581f8
Author: Jean-Marc Valin <[email protected]>
Date:   Mon Oct 25 14:59:13 2010 -0400

    Very simple/inefficient signalling of the prefilter period/gain

commit b4e1215432e3d89a29c998639a6d8b07e28c5a2a
Author: Jean-Marc Valin <[email protected]>
Date:   Mon Oct 25 14:09:17 2010 -0400

    using the actual pitch gain

commit e7cd4f07bb073b6955a001e56c0bbf16156f4195
Author: Jean-Marc Valin <[email protected]>
Date:   Mon Oct 25 12:16:11 2010 -0400

    Adding some pitch prediction though side information still isn't coded

commit 77a03aa27c9b6ed2fe80c27a1196b460ccb5079e
Author: Jean-Marc Valin <[email protected]>
Date:   Mon Oct 25 00:12:48 2010 -0400

    prefilter implemented as well

commit a3fd81b6ca213d4a9f8ddfa2883fd0e238d64d04
Author: Jean-Marc Valin <[email protected]>
Date:   Sun Oct 24 01:14:10 2010 -0400

    Implementing Raymond Chen's comb filter idea

    So far, only the post-filter is there.

--- a/configure.ac
+++ b/configure.ac
@@ -117,6 +117,13 @@
   AC_DEFINE([FIXED_DEBUG], , [Debug fixed-point implementation])
 fi])
 
+ac_enable_experimental_postfilter="no"
+AC_ARG_ENABLE(experimental-postfilter, [  --enable-experimental-postfilter     Enable this for testing only if you know what you're doing ],
+[if test "$enableval" = yes; then
+  ac_enable_experimental_postfilter="yes"
+  AC_DEFINE([ENABLE_POSTFILTER], , [Postfilter])
+fi])
+
 float_approx=$has_float_approx
 AC_ARG_ENABLE(float-approx, [  --enable-float-approx   enable fast approximations for floating point],
     [ if test "$enableval" = yes; then
--- a/libcelt/celt.c
+++ b/libcelt/celt.c
@@ -54,6 +54,8 @@
 #include "plc.h"
 
 static const int trim_cdf[7] = {0, 4, 10, 23, 119, 125, 128};
+#define COMBFILTER_MAXPERIOD 1024
+#define COMBFILTER_MINPERIOD 16
 
 /** Encoder state 
  @brief Encoder state
@@ -77,6 +79,9 @@
    int delayedIntra;
    int tonal_average;
 
+   int prefilter_period;
+   celt_word16 prefilter_gain;
+
    /* VBR-related parameters */
    celt_int32 vbr_reservoir;
    celt_int32 vbr_drift;
@@ -86,7 +91,12 @@
    celt_word32 preemph_memE[2];
    celt_word32 preemph_memD[2];
 
+#ifdef RESYNTH
+   celt_sig syn_mem[2][2*MAX_PERIOD];
+#endif
+
    celt_sig in_mem[1]; /* Size = channels*mode->overlap */
+   /* celt_sig prefilter_mem[],  Size = channels*COMBFILTER_PERIOD */
    /* celt_sig overlap_mem[],  Size = channels*mode->overlap */
    /* celt_word16 oldEBands[], Size = channels*mode->nbEBands */
 };
@@ -95,6 +105,7 @@
 {
    int size = sizeof(struct CELTEncoder)
          + (2*channels*mode->overlap-1)*sizeof(celt_sig)
+         + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig)
          + channels*mode->nbEBands*sizeof(celt_word16);
    return size;
 }
@@ -353,6 +364,46 @@
    }
 }
 
+#ifdef ENABLE_POSTFILTER
+/* FIXME: Handle the case where T = maxperiod */
+static void comb_filter(celt_word32 *y, celt_word32 *x, int T0, int T1, int N,
+      int C, celt_word16 g0, celt_word16 g1, const celt_word16 *window, int overlap)
+{
+   int i;
+   /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */
+   celt_word16 g00, g01, g02, g10, g11, g12;
+   celt_word16 t0, t1, t2;
+   /* zeros at theta = +/- 5*pi/6 */
+   t0 = QCONST16(.26795f, 15);
+   t1 = QCONST16(.46410f, 15);
+   t2 = QCONST16(.26795f, 15);
+   g00 = MULT16_16_Q15(g0, t0);
+   g01 = MULT16_16_Q15(g0, t1);
+   g02 = MULT16_16_Q15(g0, t2);
+   g10 = MULT16_16_Q15(g1, t0);
+   g11 = MULT16_16_Q15(g1, t1);
+   g12 = MULT16_16_Q15(g1, t2);
+   for (i=0;i<overlap;i++)
+   {
+      celt_word16 f;
+      f = MULT16_16_Q15(window[i],window[i]);
+      y[i] = x[i]
+               + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g01),x[i-T0])
+               + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g00),x[i-T0-1])
+               + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g02),x[i-T0+1])
+               + MULT16_32_Q15(MULT16_16_Q15(f,g11),x[i-T1])
+               + MULT16_32_Q15(MULT16_16_Q15(f,g10),x[i-T1-1])
+               + MULT16_32_Q15(MULT16_16_Q15(f,g12),x[i-T1+1]);
+
+   }
+   for (i=overlap;i<N;i++)
+      y[i] = x[i]
+               + MULT16_32_Q15(g11,x[i-T1])
+               + MULT16_32_Q15(g10,x[i-T1-1])
+               + MULT16_32_Q15(g12,x[i-T1+1]);
+}
+#endif /* ENABLE_POSTFILTER */
+
 static const signed char tf_select_table[4][8] = {
       {0, -1, 0, -1,    0,-1, 0,-1},
       {0, -1, 0, -2,    1, 0, 1 -1},
@@ -550,7 +601,7 @@
       const celt_word16 *bandLogE, int nbEBands, int LM, int C, int N0)
 {
    int i;
-   int trim_index = 3;
+   int trim_index = 2;
    if (C==2)
    {
       celt_word16 sum = 0; /* Q10 */
@@ -601,10 +652,10 @@
 }
 
 #ifdef FIXED_POINT
-int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, celt_int16 * optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
+int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
 {
 #else
-int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, celt_sig * optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
+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;
@@ -624,6 +675,7 @@
    VARDECL(int, fine_priority);
    VARDECL(int, tf_res);
    celt_sig *_overlap_mem;
+   celt_sig *prefilter_mem;
    celt_word16 *oldBandE;
    int shortBlocks=0;
    int isTransient=0;
@@ -636,6 +688,8 @@
    int codedBands;
    int tf_sum;
    int alloc_trim;
+   int pitch_index=0;
+   celt_word16 gain1 = 0;
    SAVE_STACK;
 
    if (nbCompressedBytes<0 || pcm==NULL)
@@ -648,8 +702,10 @@
       return CELT_BAD_ARG;
    M=1<<LM;
 
-   _overlap_mem = st->in_mem+C*(st->overlap);
-   oldBandE = (celt_word16*)(st->in_mem+2*C*(st->overlap));
+   prefilter_mem = st->in_mem+C*(st->overlap);
+   _overlap_mem = prefilter_mem+C*COMBFILTER_MAXPERIOD;
+   /*_overlap_mem = st->in_mem+C*(st->overlap);*/
+   oldBandE = (celt_word16*)(st->in_mem+C*(2*st->overlap+COMBFILTER_MAXPERIOD));
 
    if (enc==NULL)
    {
@@ -669,25 +725,112 @@
    N = M*st->mode->shortMdctSize;
    ALLOC(in, C*(N+st->overlap), celt_sig);
 
-   for (c=0;c<C;c++)
+   /* Find pitch period and gain */
    {
-      const celt_word16 * restrict pcmp = pcm+c;
-      celt_sig * restrict inp = in+c*(N+st->overlap)+st->overlap;
-      CELT_COPY(in+c*(N+st->overlap), st->in_mem+c*(st->overlap), st->overlap);
-      for (i=0;i<N;i++)
+      VARDECL(celt_sig, _pre);
+      celt_sig *pre[2];
+      SAVE_STACK;
+      c = 0;
+      ALLOC(_pre, C*(N+COMBFILTER_MAXPERIOD), celt_sig);
+
+      pre[0] = _pre;
+      pre[1] = _pre + (N+COMBFILTER_MAXPERIOD);
+
+      for (c=0;c<C;c++)
       {
-         /* Apply pre-emphasis */
-         celt_sig tmp = MULT16_16(st->mode->preemph[2], SCALEIN(*pcmp));
-         *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);
-         inp++;
-         pcmp+=C;
+         const celt_word16 * restrict pcmp = pcm+c;
+         celt_sig * restrict inp = in+c*(N+st->overlap)+st->overlap;
+
+         for (i=0;i<N;i++)
+         {
+            /* Apply pre-emphasis */
+            celt_sig tmp = MULT16_16(st->mode->preemph[2], SCALEIN(*pcmp));
+            *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);
+            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);
       }
-      CELT_COPY(st->in_mem+c*(st->overlap), in+c*(N+st->overlap)+N, st->overlap);
+
+#ifdef ENABLE_POSTFILTER
+      {
+         VARDECL(celt_word16, pitch_buf);
+         ALLOC(pitch_buf, (COMBFILTER_MAXPERIOD+N)>>1, celt_word16);
+         celt_word32 tmp=0;
+         celt_word32 mem0[2]={0,0};
+         celt_word16 mem1[2]={0,0};
+
+         pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD+N,
+                          C, mem0, mem1);
+         pitch_search(st->mode, pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N,
+               COMBFILTER_MAXPERIOD-COMBFILTER_MINPERIOD, &pitch_index, &tmp, 1<<LM);
+         pitch_index = COMBFILTER_MAXPERIOD-pitch_index;
+
+         gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD,
+               N, &pitch_index, st->prefilter_period, st->prefilter_gain);
+      }
+      if (pitch_index > COMBFILTER_MAXPERIOD)
+         pitch_index = COMBFILTER_MAXPERIOD;
+      gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1);
+      if (gain1 > QCONST16(.6f,15))
+         gain1 = QCONST16(.6f,15);
+      if (ABS16(gain1-st->prefilter_gain)<QCONST16(.1,15))
+         gain1=st->prefilter_gain;
+      if (gain1<QCONST16(.2f,15))
+      {
+         ec_enc_bit_prob(enc, 0, 32768);
+         gain1 = 0;
+      } else {
+         int qg;
+         int octave;
+#ifdef FIXED_POINT
+         qg = ((gain1+2048)>>12)-2;
+#else
+         qg = floor(.5+gain1*8)-2;
+#endif
+         ec_enc_bit_prob(enc, 1, 32768);
+         octave = EC_ILOG(pitch_index)-5;
+         ec_enc_uint(enc, octave, 6);
+         ec_enc_bits(enc, pitch_index-(16<<octave), 4+octave);
+         ec_enc_bits(enc, qg, 2);
+         gain1 = QCONST16(.125f,15)*(qg+2);
+      }
+      /*printf("%d %f\n", pitch_index, gain1);*/
+#else /* ENABLE_POSTFILTER */
+      ec_enc_bit_prob(enc, 0, 32768);
+#endif /* ENABLE_POSTFILTER */
+
+      for (c=0;c<C;c++)
+      {
+         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, C, -st->prefilter_gain, -gain1, 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);
+
+#ifdef ENABLE_POSTFILTER
+         if (N>COMBFILTER_MAXPERIOD)
+         {
+            CELT_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD);
+         } else {
+            CELT_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N);
+            CELT_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N);
+         }
+#endif /* ENABLE_POSTFILTER */
+      }
+
+      RESTORE_STACK;
    }
 
-   resynth = optional_resynthesis!=NULL;
+#ifdef RESYNTH
+   resynth = 1;
+#else
+   resynth = 0;
+#endif
 
    if (st->complexity > 1 && LM>0)
    {
@@ -881,10 +1024,10 @@
 
    quant_energy_finalise(st->mode, st->start, st->end, bandE, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_enc_tell(enc, 0), enc, C);
 
+#ifdef RESYNTH
    /* Re-synthesis of the coded audio if required */
    if (resynth)
    {
-      VARDECL(celt_sig, _out_mem);
       celt_sig *out_mem[2];
       celt_sig *overlap_mem[2];
 
@@ -897,6 +1040,10 @@
       /* Synthesis */
       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)
+         CELT_MOVE(st->syn_mem[1], st->syn_mem[1]+N, MAX_PERIOD);
+
       for (c=0;c<C;c++)
          for (i=0;i<M*st->mode->eBands[st->start];i++)
             freq[c*N+i] = 0;
@@ -904,24 +1051,32 @@
          for (i=M*st->mode->eBands[st->end];i<N;i++)
             freq[c*N+i] = 0;
 
-      ALLOC(_out_mem, C*N, celt_sig);
+      out_mem[0] = st->syn_mem[0]+MAX_PERIOD;
+      if (C==2)
+         out_mem[1] = st->syn_mem[1]+MAX_PERIOD;
 
       for (c=0;c<C;c++)
-      {
          overlap_mem[c] = _overlap_mem + c*st->overlap;
-         out_mem[c] = _out_mem+c*N;
-      }
 
       compute_inv_mdcts(st->mode, shortBlocks, freq, out_mem, overlap_mem, C, LM);
 
-      /* De-emphasis and put everything back at the right place 
-         in the synthesis history */
-      if (optional_resynthesis != NULL) {
-         deemphasis(out_mem, optional_resynthesis, N, C, st->mode->preemph, st->preemph_memD);
-
+#ifdef ENABLE_POSTFILTER
+      for (c=0;c<C;c++)
+      {
+         comb_filter(out_mem[c], out_mem[c], st->prefilter_period, st->prefilter_period, st->overlap, C,
+               st->prefilter_gain, st->prefilter_gain, NULL, 0);
+         comb_filter(out_mem[c]+st->overlap, out_mem[c]+st->overlap, st->prefilter_period, pitch_index, N-st->overlap, C,
+               st->prefilter_gain, gain1, st->mode->window, st->mode->overlap);
       }
+#endif /* ENABLE_POSTFILTER */
+
+      deemphasis(out_mem, (celt_word16*)pcm, N, C, st->mode->preemph, st->preemph_memD);
    }
+#endif
 
+   st->prefilter_period = pitch_index;
+   st->prefilter_gain = gain1;
+
    /* If there's any room left (can only happen for very high rates),
       fill it with zeros */
    while (ec_enc_tell(enc,0) + 8 <= nbCompressedBytes*8)
@@ -937,7 +1092,7 @@
 
 #ifdef FIXED_POINT
 #ifndef DISABLE_FLOAT_API
-int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, float * optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
+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;
    VARDECL(celt_int16, in);
@@ -960,13 +1115,11 @@
    for (j=0;j<C*N;j++)
      in[j] = FLOAT2INT16(pcm[j]);
 
-   if (optional_resynthesis != NULL) {
-     ret=celt_encode_with_ec(st,in,in,frame_size,compressed,nbCompressedBytes, enc);
-      for (j=0;j<C*N;j++)
-         optional_resynthesis[j]=in[j]*(1.f/32768.f);
-   } else {
-     ret=celt_encode_with_ec(st,in,NULL,frame_size,compressed,nbCompressedBytes, enc);
-   }
+   ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, enc);
+#ifdef RESYNTH
+   for (j=0;j<C*N;j++)
+      ((float*)pcm)[j]=in[j]*(1.f/32768.f);
+#endif
    RESTORE_STACK;
    return ret;
 
@@ -973,7 +1126,7 @@
 }
 #endif /*DISABLE_FLOAT_API*/
 #else
-int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, celt_int16 * optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
+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;
    VARDECL(celt_sig, in);
@@ -996,13 +1149,11 @@
      in[j] = SCALEOUT(pcm[j]);
    }
 
-   if (optional_resynthesis != NULL) {
-      ret = celt_encode_with_ec_float(st,in,in,frame_size,compressed,nbCompressedBytes, enc);
-      for (j=0;j<C*N;j++)
-         optional_resynthesis[j] = FLOAT2INT16(in[j]);
-   } else {
-      ret = celt_encode_with_ec_float(st,in,NULL,frame_size,compressed,nbCompressedBytes, enc);
-   }
+   ret = celt_encode_with_ec_float(st,in,frame_size,compressed,nbCompressedBytes, enc);
+#ifdef RESYNTH
+   for (j=0;j<C*N;j++)
+      ((celt_int16*)pcm)[j] = FLOAT2INT16(in[j]);
+#endif
    RESTORE_STACK;
    return ret;
 }
@@ -1010,29 +1161,16 @@
 
 int celt_encode(CELTEncoder * restrict st, const celt_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
 {
-   return celt_encode_with_ec(st, pcm, NULL, frame_size, compressed, nbCompressedBytes, NULL);
+   return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
 }
 
 #ifndef DISABLE_FLOAT_API
 int celt_encode_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
 {
-   return celt_encode_with_ec_float(st, pcm, NULL, frame_size, compressed, nbCompressedBytes, NULL);
+   return celt_encode_with_ec_float(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
 }
 #endif /* DISABLE_FLOAT_API */
 
-int celt_encode_resynthesis(CELTEncoder * restrict st, const celt_int16 * pcm, celt_int16 * optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes)
-{
-   return celt_encode_with_ec(st, pcm, optional_resynthesis, frame_size, compressed, nbCompressedBytes, NULL);
-}
-
-#ifndef DISABLE_FLOAT_API
-int celt_encode_resynthesis_float(CELTEncoder * restrict st, const float * pcm, float * optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes)
-{
-   return celt_encode_with_ec_float(st, pcm, optional_resynthesis, frame_size, compressed, nbCompressedBytes, NULL);
-}
-#endif /* DISABLE_FLOAT_API */
-
-
 int celt_encoder_ctl(CELTEncoder * restrict st, int request, ...)
 {
    va_list ap;
@@ -1146,6 +1284,8 @@
 
    int last_pitch_index;
    int loss_count;
+   int postfilter_period;
+   celt_word16 postfilter_gain;
 
    celt_sig preemph_memD[2];
    
@@ -1353,6 +1493,12 @@
          }
       }
 
+#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, C,
+                  st->postfilter_gain, st->postfilter_gain, 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];
 
@@ -1372,6 +1518,14 @@
       }
       for (i=0;i<N-overlap;i++)
          out_mem[c][MAX_PERIOD-N+overlap+i] = e[overlap+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, C,
+                  -st->postfilter_gain, -st->postfilter_gain, NULL, 0);
+#endif /* ENABLE_POSTFILTER */
+      for (i=0;i<overlap;i++)
+         out_mem[c][MAX_PERIOD+i] = e[i];
    }
 
    {
@@ -1423,6 +1577,8 @@
    int effEnd;
    int codedBands;
    int alloc_trim;
+   int postfilter_pitch;
+   celt_word16 postfilter_gain;
    SAVE_STACK;
 
    if (pcm==NULL)
@@ -1482,6 +1638,24 @@
    }
    nbAvailableBytes = len-nbFilledBytes;
 
+   if (ec_dec_bit_prob(dec, 32768))
+   {
+#ifdef ENABLE_POSTFILTER
+      int qg, octave;
+      octave = ec_dec_uint(dec, 6);
+      postfilter_pitch = (16<<octave)+ec_dec_bits(dec, 4+octave);
+      qg = ec_dec_bits(dec, 2);
+      postfilter_gain = QCONST16(.125f,15)*(qg+2);
+#else /* ENABLE_POSTFILTER */
+      RESTORE_STACK;
+      return CELT_CORRUPTED_DATA;
+#endif /* ENABLE_POSTFILTER */
+
+   } else {
+      postfilter_gain = 0;
+      postfilter_pitch = 0;
+   }
+
    /* Decode the global flags (first symbols in the stream) */
    intra_ener = ec_dec_bit_prob(dec, 8192);
    /* Get band energies */
@@ -1564,6 +1738,18 @@
 
    /* Compute inverse MDCTs */
    compute_inv_mdcts(st->mode, shortBlocks, freq, out_syn, overlap_mem, C, LM);
+
+#ifdef ENABLE_POSTFILTER
+   for (c=0;c<C;c++)
+   {
+      comb_filter(out_syn[c], out_syn[c], st->postfilter_period, st->postfilter_period, st->overlap, C,
+            st->postfilter_gain, st->postfilter_gain, NULL, 0);
+      comb_filter(out_syn[c]+st->overlap, out_syn[c]+st->overlap, st->postfilter_period, postfilter_pitch, N-st->overlap, C,
+            st->postfilter_gain, postfilter_gain, st->mode->window, st->mode->overlap);
+   }
+   st->postfilter_period = postfilter_pitch;
+   st->postfilter_gain = postfilter_gain;
+#endif /* ENABLE_POSTFILTER */
 
    deemphasis(out_syn, pcm, N, C, st->mode->preemph, st->preemph_memD);
    st->loss_count = 0;
--- a/libcelt/celt.h
+++ b/libcelt/celt.h
@@ -178,30 +178,6 @@
 
 /** Encodes a frame of audio.
  @param st Encoder state
- @param pcm PCM audio in float format, with a normal range of ±1.0. 
- *          Samples with a range beyond ±1.0 are supported but will 
- *          be clipped by decoders using the integer API and should 
- *          only be used if it is known that the far end supports 
- *          extended dynmaic range. There must be exactly
- *          frame_size samples per channel. 
- @param optional_resynthesis If not NULL, the encoder copies the audio signal that
- *          the decoder would decode. It is the same as calling the
- *          decoder on the compressed data, just faster.
- *          This may alias pcm. 
- @param compressed The compressed data is written here. This may not alias pcm or
- *                 optional_synthesis.
- @param nbCompressedBytes Maximum number of bytes to use for compressing the frame
- *          (can change from one frame to another)
- @return Number of bytes written to "compressed". Will be the same as 
- *       "nbCompressedBytes" unless the stream is VBR and will never be larger.
- *       If negative, an error has occurred (see error codes). It is IMPORTANT that
- *       the length returned be somehow transmitted to the decoder. Otherwise, no
- *       decoding is possible.
-*/
-EXPORT int celt_encode_resynthesis_float(CELTEncoder *st, const float *pcm, float *optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes);
-
-/** Encodes a frame of audio.
- @param st Encoder state
  @param pcm PCM audio in float format, with a normal range of ±1.0.
  *          Samples with a range beyond ±1.0 are supported but will
  *          be clipped by decoders using the integer API and should
@@ -219,26 +195,6 @@
  *       decoding is possible.
 */
 EXPORT int celt_encode_float(CELTEncoder *st, const float *pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes);
-
-/** Encodes a frame of audio.
- @param st Encoder state
- @param pcm PCM audio in signed 16-bit format (native endian). There must be 
- *          exactly frame_size samples per channel. 
- @param optional_resynthesis If not NULL, the encoder copies the audio signal that
- *                         the decoder would decode. It is the same as calling the
- *                         decoder on the compressed data, just faster.
- *                         This may alias pcm. 
- @param compressed The compressed data is written here. This may not alias pcm or
- *                         optional_synthesis.
- @param nbCompressedBytes Maximum number of bytes to use for compressing the frame
- *                        (can change from one frame to another)
- @return Number of bytes written to "compressed". Will be the same as 
- *       "nbCompressedBytes" unless the stream is VBR and will never be larger.
- *       If negative, an error has occurred (see error codes). It is IMPORTANT that
- *       the length returned be somehow transmitted to the decoder. Otherwise, no
- *       decoding is possible.
- */
-EXPORT int celt_encode_resynthesis(CELTEncoder *st, const celt_int16 *pcm, celt_int16 *optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes);
 
 /** Encodes a frame of audio.
  @param st Encoder state
--- a/libcelt/entenc.c
+++ b/libcelt/entenc.c
@@ -45,7 +45,15 @@
 }
 
 void ec_byte_shrink(ec_byte_buffer *_b, ec_uint32 _size){
-   _b->end_ptr=_b->buf+_size-1;
+   int i;
+   int d;
+   int N;
+   d = _b->storage-_size;
+   N = _b->storage-(_b->end_ptr-_b->buf)-1;
+   /* Copy "raw bytes" */
+   _b->end_ptr=_b->buf+_size-1-N;
+   for (i=0;i<N;i++)
+      _b->end_ptr[i+1] = _b->end_ptr[i+1+d];
    _b->storage=_size;
 }
 
--- a/libcelt/mathops.c
+++ b/libcelt/mathops.c
@@ -74,15 +74,15 @@
 {
    celt_word16 rcp;
    celt_word32 result, rem;
-   int shift = 30-celt_ilog2(b);
+   int shift = 29-celt_ilog2(b);
    a = SHL32(a,shift);
    b = SHL32(b,shift);
 
    /* 16-bit reciprocal */
-   rcp = ROUND16(celt_rcp(ROUND16(b,16)),2);
-   result = SHL32(MULT16_32_Q15(rcp, a),1);
+   rcp = ROUND16(celt_rcp(ROUND16(b,16)),3);
+   result = SHL32(MULT16_32_Q15(rcp, a),2);
    rem = a-MULT32_32_Q31(result, b);
-   result += SHL32(MULT16_32_Q15(rcp, rem),1);
+   result += SHL32(MULT16_32_Q15(rcp, rem),2);
    return result;
 }
 
--- a/libcelt/modes.c
+++ b/libcelt/modes.c
@@ -53,8 +53,8 @@
 static const unsigned char band_allocation[] = {
 /*0  200 400 600 800  1k 1.2 1.4 1.6  2k 2.4 2.8 3.2  4k 4.8 5.6 6.8  8k 9.6 12k 15.6 */
   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
- 80, 80, 75, 70, 65, 60, 55, 50, 44, 40, 35, 30, 15,  1,  0,  0,  0,  0,  0,  0,  0,
- 90, 85, 85, 85, 85, 82, 78, 74, 70, 65, 60, 54, 45, 35, 25, 15,  1,  0,  0,  0,  0,
+ 95, 90, 80, 75, 65, 60, 55, 50, 44, 40, 35, 30, 15,  1,  0,  0,  0,  0,  0,  0,  0,
+100, 95, 90, 88, 85, 82, 78, 74, 70, 65, 60, 54, 45, 35, 25, 15,  1,  0,  0,  0,  0,
 120,110,110,110,100, 96, 90, 88, 84, 76, 70, 65, 60, 45, 35, 25, 20,  1,  1,  0,  0,
 135,125,125,125,115,112,104,104,100, 96, 83, 78, 70, 55, 46, 36, 32, 28, 20,  8,  0,
 170,165,157,155,149,145,143,138,138,138,129,124,108, 96, 88, 83, 72, 56, 44, 28,  2,
--- a/libcelt/modes.h
+++ b/libcelt/modes.h
@@ -104,8 +104,8 @@
 };
 
 /* Prototypes for _ec versions of the encoder/decoder calls (not public) */
-int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, celt_int16 * optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
-int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, float * optional_resynthesis, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
+int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
+int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
 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 celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size, ec_dec *dec);
 #endif
--- a/libcelt/pitch.c
+++ b/libcelt/pitch.c
@@ -46,7 +46,8 @@
 #include "stack_alloc.h"
 #include "mathops.h"
 
-static void find_best_pitch(celt_word32 *xcorr, celt_word32 maxcorr, celt_word16 *y, int yshift, int len, int max_pitch, int best_pitch[2])
+static void find_best_pitch(celt_word32 *xcorr, celt_word32 maxcorr, celt_word16 *y,
+                            int yshift, int len, int max_pitch, int best_pitch[2])
 {
    int i, j;
    celt_word32 Syy=1;
@@ -96,28 +97,65 @@
    }
 }
 
+#include "plc.h"
 void pitch_downsample(celt_sig * restrict x[], celt_word16 * restrict x_lp, int len, int end, int _C, celt_sig * restrict xmem, celt_word16 * restrict filt_mem)
 {
    int i;
+   celt_word32 ac[5];
+   celt_word16 tmp=Q15ONE;
+   celt_word16 lpc[4], mem[4]={0,0,0,0};
    const int C = CHANNELS(_C);
    for (i=1;i<len>>1;i++)
-      x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), SIG_SHIFT);
-   x_lp[0] = SHR32(HALF32(HALF32(*xmem+x[0][1])+x[0][0]), SIG_SHIFT);
+      x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), SIG_SHIFT+2);
+   x_lp[0] = SHR32(HALF32(HALF32(*xmem+x[0][1])+x[0][0]), SIG_SHIFT+2);
    *xmem = x[0][end-1];
    if (C==2)
    {
       for (i=1;i<len>>1;i++)
-      x_lp[i] = SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), SIG_SHIFT);
-      x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), SIG_SHIFT);
+      x_lp[i] = SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), SIG_SHIFT+2);
+      x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), SIG_SHIFT+2);
       *xmem += x[1][end-1];
    }
+
+   _celt_autocorr(x_lp, ac, NULL, 0,
+                  4, len>>1);
+
+   /* Noise floor -40 dB */
+#ifdef FIXED_POINT
+   ac[0] += SHR32(ac[0],13);
+#else
+   ac[0] *= 1.0001f;
+#endif
+   /* Lag windowing */
+   for (i=1;i<=4;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]);
+#else
+      ac[i] -= ac[i]*(.008f*i)*(.008f*i);
+#endif
+   }
+
+   _celt_lpc(lpc, ac, 4);
+   for (i=0;i<4;i++)
+   {
+      tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp);
+      lpc[i] = MULT16_16_Q15(lpc[i], tmp);
+   }
+   fir(x_lp, lpc, x_lp, len>>1, 4, mem);
+
+   mem[0]=0;
+   lpc[0]=QCONST16(.8,12);
+   fir(x_lp, lpc, x_lp, len>>1, 1, mem);
+
 }
 
-void pitch_search(const CELTMode *m, const celt_word16 * restrict x_lp, celt_word16 * restrict y, int len, int max_pitch, int *pitch, celt_sig *xmem, int M)
+void pitch_search(const CELTMode *m, const celt_word16 * restrict x_lp, celt_word16 * restrict y,
+                  int len, int max_pitch, int *pitch, celt_sig *xmem, int M)
 {
    int i, j;
-   const int lag = MAX_PERIOD;
-   const int N = M*m->shortMdctSize;
+   int lag;
    int best_pitch[2]={0};
    VARDECL(celt_word16, x_lp4);
    VARDECL(celt_word16, y_lp4);
@@ -128,6 +166,8 @@
 
    SAVE_STACK;
 
+   lag = len+max_pitch;
+
    ALLOC(x_lp4, len>>2, celt_word16);
    ALLOC(y_lp4, lag>>2, celt_word16);
    ALLOC(xcorr, max_pitch>>1, celt_word32);
@@ -198,10 +238,135 @@
    }
    *pitch = 2*best_pitch[0]-offset;
 
-   CELT_MOVE(y, y+(N>>1), (lag-N)>>1);
-   CELT_MOVE(y+((lag-N)>>1), x_lp, N>>1);
-
    RESTORE_STACK;
+}
 
-   /*printf ("%d\n", *pitch);*/
+#ifdef ENABLE_POSTFILTER
+static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
+celt_word16 remove_doubling(celt_word16 *x, int maxperiod, int minperiod,
+      int N, int *_T0, int prev_period, celt_word16 prev_gain)
+{
+   int k, i, T, T0, k0;
+   celt_word16 g, g0;
+   celt_word16 pg;
+   celt_word32 xy,xx,yy;
+   celt_word32 xcorr[3];
+   celt_word32 best_xy, best_yy;
+   int offset;
+
+   maxperiod /= 2;
+   minperiod /= 2;
+   *_T0 /= 2;
+   prev_period /= 2;
+   N /= 2;
+   x += maxperiod;
+   if (*_T0>=maxperiod)
+      *_T0=maxperiod-1;
+
+   T = T0 = *_T0;
+   xx=xy=yy=0;
+   for (i=0;i<N;i++)
+   {
+      xy = MAC16_16(xy, x[i], x[i-T0]);
+      xx = MAC16_16(xx, x[i], x[i]);
+      yy = MAC16_16(yy, x[i-T0],x[i-T0]);
+   }
+   best_xy = xy;
+   best_yy = yy;
+#ifdef FIXED_POINT
+      {
+         celt_word32 x2y2;
+         int sh, t;
+         x2y2 = 1+HALF32(MULT32_32_Q31(xx,yy));
+         sh = celt_ilog2(x2y2)>>1;
+         t = VSHR32(x2y2, 2*(sh-7));
+         g = g0 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1);
+      }
+#else
+      g = g0 = xy/sqrt(1+xx*yy);
+#endif
+   k0 = 1;
+   /* Look for any pitch at T/k */
+   for (k=2;k<=15;k++)
+   {
+      int T1, T1b;
+      celt_word16 g1;
+      celt_word16 cont=0;
+      T1 = (2*T0+k)/(2*k);
+      if (T1 < minperiod)
+         break;
+      /* Look for another strong correlation at T1b */
+      if (k==2)
+      {
+         if (T1+T0>maxperiod)
+            T1b = T0;
+         else
+            T1b = T0+T1;
+      } else
+      {
+         T1b = (2*second_check[k]*T0+k)/(2*k);
+      }
+      xy=yy=0;
+      for (i=0;i<N;i++)
+      {
+         xy = MAC16_16(xy, x[i], x[i-T1]);
+         yy = MAC16_16(yy, x[i-T1], x[i-T1]);
+
+         xy = MAC16_16(xy, x[i], x[i-T1b]);
+         yy = MAC16_16(yy, x[i-T1b], x[i-T1b]);
+      }
+#ifdef FIXED_POINT
+      {
+         celt_word32 x2y2;
+         int sh, t;
+         x2y2 = 1+MULT32_32_Q31(xx,yy);
+         sh = celt_ilog2(x2y2)>>1;
+         t = VSHR32(x2y2, 2*(sh-7));
+         g1 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1);
+      }
+#else
+      g1 = xy/sqrt(1+2.f*xx*1.f*yy);
+#endif
+      if (abs(T1-prev_period)<=1)
+         cont = prev_gain;
+      else if (abs(T1-prev_period)<=2 && 5*k*k < T0)
+         cont = HALF32(prev_gain);
+      else
+         cont = 0;
+      if (g1 > QCONST16(.3f,15) + MULT16_16_Q15(QCONST16(.4f,15),g0)-cont)
+      {
+         best_xy = xy;
+         best_yy = yy;
+         T = T1;
+         g = g1;
+      }
+   }
+   if (best_yy <= best_xy)
+      pg = Q15ONE;
+   else
+      pg = SHR32(frac_div32(best_xy,best_yy+1),16);
+
+   for (k=0;k<3;k++)
+   {
+      int T1 = T+k-1;
+      xy = 0;
+      for (i=0;i<N;i++)
+         xy = MAC16_16(xy, x[i], x[i-T1]);
+      xcorr[k] = xy;
+   }
+   if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0]))
+      offset = 1;
+   else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2]))
+      offset = -1;
+   else
+      offset = 0;
+   if (pg > g)
+      pg = g;
+   *_T0 = 2*T+offset;
+
+   if (*_T0<2*minperiod)
+      *_T0=2*minperiod;
+   return pg;
 }
+
+#endif /* ENABLE_POSTFILTER */
--- a/libcelt/pitch.h
+++ b/libcelt/pitch.h
@@ -43,6 +43,10 @@
 
 void pitch_downsample(celt_sig * restrict x[], celt_word16 * restrict x_lp, int len, int end, int _C, celt_sig * restrict xmem, celt_word16 * restrict filt_mem);
 
-void pitch_search(const CELTMode *m, const celt_word16 * restrict x_lp, celt_word16 * restrict y, int len, int max_pitch, int *pitch, celt_sig *xmem, int M);
+void pitch_search(const CELTMode *m, const celt_word16 * restrict x_lp, celt_word16 * restrict y,
+                  int len, int max_pitch, int *pitch, celt_sig *xmem, int M);
+
+celt_word16 remove_doubling(celt_word16 *x, int maxperiod, int minperiod,
+      int N, int *T0, int prev_period, celt_word16 prev_gain);
 
 #endif
--- a/libcelt/plc.c
+++ b/libcelt/plc.c
@@ -166,7 +166,7 @@
    }
 #ifdef FIXED_POINT
    {
-      float ac0=0;
+      celt_word32 ac0=0;
       int shift;
       for(i=0;i<n;i++)
          ac0 += SHR32(MULT16_16(xx[i],xx[i]),8);
--- a/libcelt/rate.c
+++ b/libcelt/rate.c
@@ -283,8 +283,8 @@
       thresh[j] = 3*(C*(m->eBands[j+1]-m->eBands[j])<<LM<<BITRES)>>3;
    /* Tilt of the allocation curve */
    for (j=start;j<end;j++)
-      trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-3)*(m->nbEBands-j-1)
-            <<(LM+BITRES)>>5;
+      trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(2*alloc_trim-7)*(m->nbEBands-j-1)
+            <<(LM+BITRES)>>6;
 
    lo = 0;
    hi = m->nbAllocVectors - 1;
--- a/libcelt/testcelt.c
+++ b/libcelt/testcelt.c
@@ -134,7 +134,7 @@
       err = fread(in, sizeof(short), frame_size*channels, fin);
       if (feof(fin))
          break;
-      len = celt_encode_resynthesis(enc, in, in, frame_size, data, bytes_per_packet);
+      len = celt_encode(enc, in, frame_size, data, bytes_per_packet);
       if (len <= 0)
          fprintf (stderr, "celt_encode() failed: %s\n", celt_strerror(len));
 
@@ -194,7 +194,7 @@
    celt_mode_destroy(mode);
    free(in);
    free(out);
-#if !(defined (FIXED_POINT) && defined(STATIC_MODES))
+#ifdef RESYNTH
    if (rmsd > 0)
    {
       rmsd = sqrt(rmsd/(1.0*frame_size*channels*count));