public sealed override void Unquantify(float[] exc, int es, int nsf, Bits bits)
 {
     for (int i = 0; i < this.nb_subvect; i++)
     {
         if (this.have_sign != 0)
         {
             this.signs[i] = bits.Unpack(1);
         }
         else
         {
             this.signs[i] = 0;
         }
         this.ind[i] = bits.Unpack(this.shape_bits);
     }
     for (int i = 0; i < this.nb_subvect; i++)
     {
         float num = 1f;
         if (this.signs[i] != 0)
         {
             num = -1f;
         }
         for (int j = 0; j < this.subvect_size; j++)
         {
             exc[es + this.subvect_size * i + j] += num * 0.03125f * (float)this.shape_cb[this.ind[i] * this.subvect_size + j];
         }
     }
 }
Esempio n. 2
0
        public void Init(Bits bits)
        {
            float num = 1f;

            if (bits.Unpack(1) != 0)
            {
                num = -1f;
            }
            int num2 = bits.Unpack(5);

            this.balance = (float)Math.Exp((double)num * 0.25 * (double)num2);
            num2         = bits.Unpack(2);
            this.e_ratio = Stereo.e_ratio_quant[num2];
        }
Esempio n. 3
0
        /// <summary>
        /// Codebook Search Unquantification (Split Shape).
        /// </summary>
        public sealed override void Unquantify(SpeexWord32[] exc, int es, int nsf, Bits bits)
        {
            int i, j;

            /* Decode codewords and gains */
            for (i = 0; i < nb_subvect; i++)
            {
                if (have_sign != 0)
                {
                    signs[i] = bits.Unpack(1);
                }
                else
                {
                    signs[i] = 0;
                }
                ind[i] = bits.Unpack(shape_bits);
            }

            /* Compute decoded excitation */
            for (i = 0; i < nb_subvect; i++)
            {
                float s = 1.0f;
                if (signs[i] != 0)
                {
                    s = -1.0f;
                }
#if FIXED_POINT
                if (s == 1)
                {
                    for (j = 0; j < subvect_size; j++)
                    {
                        exc[subvect_size * i + j] = (int)(shape_cb[ind[i] * subvect_size + j]) >> (14 - 5);
                    }
                }
                else
                {
                    for (j = 0; j < subvect_size; j++)
                    {
                        exc[subvect_size * i + j] = -((int)(shape_cb[ind[i] * subvect_size + j]) << (14 - 5));
                    }
                }
#else
                for (j = 0; j < subvect_size; j++)
                {
                    exc[es + subvect_size * i + j] += s * 0.03125f * (float)shape_cb[ind[i] * subvect_size + j];
                }
#endif
            }
        }
Esempio n. 4
0
        protected internal void UnpackPlus(float[] lsp, int[] tab, Bits bits, float k, int ti, int li)
        {
            int num = bits.Unpack(6);

            for (int i = 0; i < ti; i++)
            {
                lsp[i + li] += k * (float)tab[num * ti + i];
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Callback handler for intensity stereo info
        /// </summary>
        public void Init(Bits bits)
        {
            SpeexWord16 sign = 1;
            int         tmp;

            if (bits.Unpack(1) != 0)
            {
                sign = -1;
            }
            tmp = bits.Unpack(5);
#if FIXED_POINT
            balance = (int)Math.Exp(sign * (tmp << 9));
#else
            balance = (float)Math.Exp(sign * .25d * tmp);
#endif
            tmp     = bits.Unpack(2);
            e_ratio = e_ratio_quant[tmp];
        }
Esempio n. 6
0
        /// <summary>
        /// Long Term Prediction Unquantification (3Tap).
        /// </summary>
        /// <returns>pitch</returns>
        public sealed override int Unquant(
            float[] exc, int es, int start, float pitch_coef,
            int nsf, float[] gain_val, Bits bits, int count_lost,
            int subframe_offset, float last_pitch_gain)
        {
            int i, pitch, gain_index;

            pitch      = bits.Unpack(pitch_bits);
            pitch     += start;
            gain_index = bits.Unpack(gain_bits);

            gain[0] = 0.015625f * (float)gain_cdbk[gain_index * 3] + .5f;
            gain[1] = 0.015625f * (float)gain_cdbk[gain_index * 3 + 1] + .5f;
            gain[2] = 0.015625f * (float)gain_cdbk[gain_index * 3 + 2] + .5f;

            if (count_lost != 0 && pitch > subframe_offset)
            {
                float gain_sum = Math.Abs(gain[1]);
                float tmp      = (count_lost < 4) ? last_pitch_gain
                                                : 0.4f * last_pitch_gain;
                if (tmp > .95f)
                {
                    tmp = .95f;
                }
                if (gain[0] > 0)
                {
                    gain_sum += gain[0];
                }
                else
                {
                    gain_sum -= .5f * gain[0];
                }
                if (gain[2] > 0)
                {
                    gain_sum += gain[2];
                }
                else
                {
                    gain_sum -= .5f * gain[0];
                }
                if (gain_sum > tmp)
                {
                    float fact = tmp / gain_sum;
                    for (i = 0; i < 3; i++)
                    {
                        gain[i] *= fact;
                    }
                }
            }

            gain_val[0] = gain[0];
            gain_val[1] = gain[1];
            gain_val[2] = gain[2];

            for (i = 0; i < 3; i++)
            {
                int j, tmp1, tmp2, pp = pitch + 1 - i;

                tmp1 = nsf;
                if (tmp1 > pp)
                {
                    tmp1 = pp;
                }
                tmp2 = nsf;
                if (tmp2 > pp + pitch)
                {
                    tmp2 = pp + pitch;
                }

                for (j = 0; j < tmp1; j++)
                {
                    e[i][j] = exc[es + j - pp];
                }
                for (j = tmp1; j < tmp2; j++)
                {
                    e[i][j] = exc[es + j - pp - pitch];
                }
                for (j = tmp2; j < nsf; j++)
                {
                    e[i][j] = 0;
                }
            }

            for (i = 0; i < nsf; i++)
            {
                exc[es + i] = gain[0] * e[2][i] + gain[1] * e[1][i] + gain[2]
                              * e[0][i];
            }

            return(pitch);
        }
        /// <summary>
        /// Decode the given input bits.
        /// </summary>
        /// <returns>1 if a terminator was found, 0 if not.</returns>
        public virtual int Decode(Bits bits, float[] xout)
        {
            int i, sub, wideband, ret;

            float[] low_pi_gain, low_exc, low_innov;

            /* Decode the low-band */
            ret = lowdec.Decode(bits, x0d);
            if (ret != 0)
            {
                return(ret);
            }
            bool dtx = lowdec.Dtx;

            if (bits == null)
            {
                DecodeLost(xout, dtx);
                return(0);
            }
            /* Check "wideband bit" */
            wideband = bits.Peek();
            if (wideband != 0)
            {
                /* Regular wideband frame, read the submode */
                wideband  = bits.Unpack(1);
                submodeID = bits.Unpack(3);
            }
            else
            {
                /* was a narrowband frame, set "null submode" */
                submodeID = 0;
            }

            for (i = 0; i < frameSize; i++)
            {
                excBuf[i] = 0;
            }

            /* If null mode (no transmission), just set a couple things to zero */
            if (submodes[submodeID] == null)
            {
                if (dtx)
                {
                    DecodeLost(xout, true);
                    return(0);
                }
                for (i = 0; i < frameSize; i++)
                {
                    excBuf[i] = NSpeex.NbCodec.VERY_SMALL;
                }

                first = 1;
                /* Final signal synthesis from excitation */
                NSpeex.Filters.Iir_mem2(excBuf, excIdx, interp_qlpc, high, 0,
                                        frameSize, lpcSize, mem_sp);
                filters.Fir_mem_up(x0d, NSpeex.Codebook_Constants.h0, y0,
                                   fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g0_mem);
                filters.Fir_mem_up(high, NSpeex.Codebook_Constants.h1, y1,
                                   fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g1_mem);

                for (i = 0; i < fullFrameSize; i++)
                {
                    xout[i] = 2 * (y0[i] - y1[i]);
                }
                return(0);
            }
            low_pi_gain = lowdec.PiGain;
            low_exc     = lowdec.Exc;
            low_innov   = lowdec.Innov;
            submodes[submodeID].LsqQuant.Unquant(qlsp, lpcSize, bits);

            if (first != 0)
            {
                for (i = 0; i < lpcSize; i++)
                {
                    old_qlsp[i] = qlsp[i];
                }
            }

            for (sub = 0; sub < nbSubframes; sub++)
            {
                float tmp, filter_ratio, el = 0.0f, rl = 0.0f, rh = 0.0f;
                int   subIdx = subframeSize * sub;

                /* LSP interpolation */
                tmp = (1.0f + sub) / nbSubframes;
                for (i = 0; i < lpcSize; i++)
                {
                    interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i];
                }

                NSpeex.Lsp.Enforce_margin(interp_qlsp, lpcSize, .05f);

                /* LSPs to x-domain */
                for (i = 0; i < lpcSize; i++)
                {
                    interp_qlsp[i] = (float)System.Math.Cos(interp_qlsp[i]);
                }

                /* LSP to LPC */
                m_lsp.Lsp2lpc(interp_qlsp, interp_qlpc, lpcSize);

                if (enhanced)
                {
                    float k1, k2, k3;
                    k1 = submodes[submodeID].LpcEnhK1;
                    k2 = submodes[submodeID].LpcEnhK2;
                    k3 = k1 - k2;
                    NSpeex.Filters.Bw_lpc(k1, interp_qlpc, awk1, lpcSize);
                    NSpeex.Filters.Bw_lpc(k2, interp_qlpc, awk2, lpcSize);
                    NSpeex.Filters.Bw_lpc(k3, interp_qlpc, awk3, lpcSize);
                }

                /*
                 * Calculate reponse ratio between low & high filter in band middle
                 * (4000 Hz)
                 */
                tmp          = 1;
                pi_gain[sub] = 0;
                for (i = 0; i <= lpcSize; i++)
                {
                    rh           += tmp * interp_qlpc[i];
                    tmp           = -tmp;
                    pi_gain[sub] += interp_qlpc[i];
                }
                rl           = low_pi_gain[sub];
                rl           = 1 / (Math.Abs(rl) + .01f);
                rh           = 1 / (Math.Abs(rh) + .01f);
                filter_ratio = Math.Abs(.01f + rh)
                               / (.01f + Math.Abs(rl));

                /* reset excitation buffer */
                for (i = subIdx; i < subIdx + subframeSize; i++)
                {
                    excBuf[i] = 0;
                }

                if (submodes[submodeID].Innovation == null)
                {
                    float g;
                    int   quant;

                    quant = bits.Unpack(5);
                    g     = (float)Math.Exp(((double)quant - 10) / 8.0d);
                    g    /= filter_ratio;

                    /* High-band excitation using the low-band excitation and a gain */
                    for (i = subIdx; i < subIdx + subframeSize; i++)
                    {
                        excBuf[i] = foldingGain * g * low_innov[i];
                    }
                }
                else
                {
                    float gc, scale;
                    int   qgc = bits.Unpack(4);

                    for (i = subIdx; i < subIdx + subframeSize; i++)
                    {
                        el += low_exc[i] * low_exc[i];
                    }

                    gc    = (float)Math.Exp((1 / 3.7f) * qgc - 2);
                    scale = gc * (float)Math.Sqrt(1 + el) / filter_ratio;
                    submodes[submodeID].Innovation.Unquantify(excBuf, subIdx,
                                                              subframeSize, bits);

                    for (i = subIdx; i < subIdx + subframeSize; i++)
                    {
                        excBuf[i] *= scale;
                    }

                    if (submodes[submodeID].DoubleCodebook != 0)
                    {
                        for (i = 0; i < subframeSize; i++)
                        {
                            innov2[i] = 0;
                        }
                        submodes[submodeID].Innovation.Unquantify(innov2, 0,
                                                                  subframeSize, bits);
                        for (i = 0; i < subframeSize; i++)
                        {
                            innov2[i] *= scale * (1 / 2.5f);
                        }
                        for (i = 0; i < subframeSize; i++)
                        {
                            excBuf[subIdx + i] += innov2[i];
                        }
                    }
                }

                for (i = subIdx; i < subIdx + subframeSize; i++)
                {
                    high[i] = excBuf[i];
                }

                if (enhanced)
                {
                    /* Use enhanced LPC filter */
                    NSpeex.Filters.Filter_mem2(high, subIdx, awk2, awk1,
                                               subframeSize, lpcSize, mem_sp, lpcSize);
                    NSpeex.Filters.Filter_mem2(high, subIdx, awk3, interp_qlpc,
                                               subframeSize, lpcSize, mem_sp, 0);
                }
                else
                {
                    /* Use regular filter */
                    for (i = 0; i < lpcSize; i++)
                    {
                        mem_sp[lpcSize + i] = 0;
                    }
                    NSpeex.Filters.Iir_mem2(high, subIdx, interp_qlpc, high, subIdx,
                                            subframeSize, lpcSize, mem_sp);
                }
            }

            filters.Fir_mem_up(x0d, NSpeex.Codebook_Constants.h0, y0, fullFrameSize,
                               NSpeex.SbCodec.QMF_ORDER, g0_mem);
            filters.Fir_mem_up(high, NSpeex.Codebook_Constants.h1, y1,
                               fullFrameSize, NSpeex.SbCodec.QMF_ORDER, g1_mem);

            for (i = 0; i < fullFrameSize; i++)
            {
                xout[i] = 2 * (y0[i] - y1[i]);
            }

            for (i = 0; i < lpcSize; i++)
            {
                old_qlsp[i] = qlsp[i];
            }

            first = 0;
            return(0);
        }
Esempio n. 8
0
        public void UserInbandRequest(Bits bits)
        {
            int num = bits.Unpack(4);

            bits.Advance(5 + 8 * num);
        }
Esempio n. 9
0
        public void SpeexInbandRequest(Bits bits)
        {
            switch (bits.Unpack(4))
            {
            case 0:
                bits.Advance(1);
                break;

            case 1:
                bits.Advance(1);
                break;

            case 2:
                bits.Advance(4);
                break;

            case 3:
                bits.Advance(4);
                break;

            case 4:
                bits.Advance(4);
                break;

            case 5:
                bits.Advance(4);
                break;

            case 6:
                bits.Advance(4);
                break;

            case 7:
                bits.Advance(4);
                break;

            case 8:
                bits.Advance(8);
                break;

            case 9:
                this.stereo.Init(bits);
                break;

            case 10:
                bits.Advance(16);
                break;

            case 11:
                bits.Advance(16);
                break;

            case 12:
                bits.Advance(32);
                break;

            case 13:
                bits.Advance(32);
                break;

            case 14:
                bits.Advance(64);
                break;

            case 15:
                bits.Advance(64);
                break;
            }
        }
Esempio n. 10
0
        public virtual int Decode(Bits bits, float[] xout)
        {
            int num = this.lowdec.Decode(bits, this.x0d);

            if (num != 0)
            {
                return(num);
            }
            bool dtx = this.lowdec.Dtx;

            if (bits == null)
            {
                this.DecodeLost(xout, dtx);
                return(0);
            }
            int num2 = bits.Peek();

            if (num2 != 0)
            {
                num2           = bits.Unpack(1);
                this.submodeID = bits.Unpack(3);
            }
            else
            {
                this.submodeID = 0;
            }
            for (int i = 0; i < this.frameSize; i++)
            {
                this.excBuf[i] = 0f;
            }
            if (this.submodes[this.submodeID] != null)
            {
                float[] piGain = this.lowdec.PiGain;
                float[] exc    = this.lowdec.Exc;
                float[] innov  = this.lowdec.Innov;
                this.submodes[this.submodeID].LsqQuant.Unquant(this.qlsp, this.lpcSize, bits);
                if (this.first != 0)
                {
                    for (int i = 0; i < this.lpcSize; i++)
                    {
                        this.old_qlsp[i] = this.qlsp[i];
                    }
                }
                for (int j = 0; j < this.nbSubframes; j++)
                {
                    float num3 = 0f;
                    float num4 = 0f;
                    int   num5 = this.subframeSize * j;
                    float num6 = (1f + (float)j) / (float)this.nbSubframes;
                    for (int i = 0; i < this.lpcSize; i++)
                    {
                        this.interp_qlsp[i] = (1f - num6) * this.old_qlsp[i] + num6 * this.qlsp[i];
                    }
                    Lsp.Enforce_margin(this.interp_qlsp, this.lpcSize, 0.05f);
                    for (int i = 0; i < this.lpcSize; i++)
                    {
                        this.interp_qlsp[i] = (float)Math.Cos((double)this.interp_qlsp[i]);
                    }
                    this.m_lsp.Lsp2lpc(this.interp_qlsp, this.interp_qlpc, this.lpcSize);
                    if (this.enhanced)
                    {
                        float lpcEnhK  = this.submodes[this.submodeID].LpcEnhK1;
                        float lpcEnhK2 = this.submodes[this.submodeID].LpcEnhK2;
                        float gamma    = lpcEnhK - lpcEnhK2;
                        Filters.Bw_lpc(lpcEnhK, this.interp_qlpc, this.awk1, this.lpcSize);
                        Filters.Bw_lpc(lpcEnhK2, this.interp_qlpc, this.awk2, this.lpcSize);
                        Filters.Bw_lpc(gamma, this.interp_qlpc, this.awk3, this.lpcSize);
                    }
                    num6            = 1f;
                    this.pi_gain[j] = 0f;
                    for (int i = 0; i <= this.lpcSize; i++)
                    {
                        num4            += num6 * this.interp_qlpc[i];
                        num6             = -num6;
                        this.pi_gain[j] += this.interp_qlpc[i];
                    }
                    float value = piGain[j];
                    value = 1f / (Math.Abs(value) + 0.01f);
                    num4  = 1f / (Math.Abs(num4) + 0.01f);
                    float num7 = Math.Abs(0.01f + num4) / (0.01f + Math.Abs(value));
                    for (int i = num5; i < num5 + this.subframeSize; i++)
                    {
                        this.excBuf[i] = 0f;
                    }
                    if (this.submodes[this.submodeID].Innovation == null)
                    {
                        int   num8 = bits.Unpack(5);
                        float num9 = (float)Math.Exp(((double)num8 - 10.0) / 8.0);
                        num9 /= num7;
                        for (int i = num5; i < num5 + this.subframeSize; i++)
                        {
                            this.excBuf[i] = this.foldingGain * num9 * innov[i];
                        }
                    }
                    else
                    {
                        int num10 = bits.Unpack(4);
                        for (int i = num5; i < num5 + this.subframeSize; i++)
                        {
                            num3 += exc[i] * exc[i];
                        }
                        float num11 = (float)Math.Exp((double)(0.270270258f * (float)num10 - 2f));
                        float num12 = num11 * (float)Math.Sqrt((double)(1f + num3)) / num7;
                        this.submodes[this.submodeID].Innovation.Unquantify(this.excBuf, num5, this.subframeSize, bits);
                        for (int i = num5; i < num5 + this.subframeSize; i++)
                        {
                            this.excBuf[i] *= num12;
                        }
                        if (this.submodes[this.submodeID].DoubleCodebook != 0)
                        {
                            for (int i = 0; i < this.subframeSize; i++)
                            {
                                this.innov2[i] = 0f;
                            }
                            this.submodes[this.submodeID].Innovation.Unquantify(this.innov2, 0, this.subframeSize, bits);
                            for (int i = 0; i < this.subframeSize; i++)
                            {
                                this.innov2[i] *= num12 * 0.4f;
                            }
                            for (int i = 0; i < this.subframeSize; i++)
                            {
                                this.excBuf[num5 + i] += this.innov2[i];
                            }
                        }
                    }
                    for (int i = num5; i < num5 + this.subframeSize; i++)
                    {
                        this.high[i] = this.excBuf[i];
                    }
                    if (this.enhanced)
                    {
                        Filters.Filter_mem2(this.high, num5, this.awk2, this.awk1, this.subframeSize, this.lpcSize, this.mem_sp, this.lpcSize);
                        Filters.Filter_mem2(this.high, num5, this.awk3, this.interp_qlpc, this.subframeSize, this.lpcSize, this.mem_sp, 0);
                    }
                    else
                    {
                        for (int i = 0; i < this.lpcSize; i++)
                        {
                            this.mem_sp[this.lpcSize + i] = 0f;
                        }
                        Filters.Iir_mem2(this.high, num5, this.interp_qlpc, this.high, num5, this.subframeSize, this.lpcSize, this.mem_sp);
                    }
                }
                this.filters.Fir_mem_up(this.x0d, Codebook_Constants.h0, this.y0, this.fullFrameSize, 64, this.g0_mem);
                this.filters.Fir_mem_up(this.high, Codebook_Constants.h1, this.y1, this.fullFrameSize, 64, this.g1_mem);
                for (int i = 0; i < this.fullFrameSize; i++)
                {
                    xout[i] = 2f * (this.y0[i] - this.y1[i]);
                }
                for (int i = 0; i < this.lpcSize; i++)
                {
                    this.old_qlsp[i] = this.qlsp[i];
                }
                this.first = 0;
                return(0);
            }
            if (dtx)
            {
                this.DecodeLost(xout, true);
                return(0);
            }
            for (int i = 0; i < this.frameSize; i++)
            {
                this.excBuf[i] = 0f;
            }
            this.first = 1;
            Filters.Iir_mem2(this.excBuf, this.excIdx, this.interp_qlpc, this.high, 0, this.frameSize, this.lpcSize, this.mem_sp);
            this.filters.Fir_mem_up(this.x0d, Codebook_Constants.h0, this.y0, this.fullFrameSize, 64, this.g0_mem);
            this.filters.Fir_mem_up(this.high, Codebook_Constants.h1, this.y1, this.fullFrameSize, 64, this.g1_mem);
            for (int i = 0; i < this.fullFrameSize; i++)
            {
                xout[i] = 2f * (this.y0[i] - this.y1[i]);
            }
            return(0);
        }
Esempio n. 11
0
        public sealed override int Unquant(float[] exc, int es, int start, float pitch_coef, int nsf, float[] gain_val, Bits bits, int count_lost, int subframe_offset, float last_pitch_gain)
        {
            int num = bits.Unpack(this.pitch_bits);

            num += start;
            int num2 = bits.Unpack(this.gain_bits);

            this.gain[0] = 0.015625f * (float)this.gain_cdbk[num2 * 3] + 0.5f;
            this.gain[1] = 0.015625f * (float)this.gain_cdbk[num2 * 3 + 1] + 0.5f;
            this.gain[2] = 0.015625f * (float)this.gain_cdbk[num2 * 3 + 2] + 0.5f;
            if (count_lost != 0 && num > subframe_offset)
            {
                float num3 = Math.Abs(this.gain[1]);
                float num4 = (count_lost >= 4) ? (0.4f * last_pitch_gain) : last_pitch_gain;
                if (num4 > 0.95f)
                {
                    num4 = 0.95f;
                }
                if (this.gain[0] > 0f)
                {
                    num3 += this.gain[0];
                }
                else
                {
                    num3 -= 0.5f * this.gain[0];
                }
                if (this.gain[2] > 0f)
                {
                    num3 += this.gain[2];
                }
                else
                {
                    num3 -= 0.5f * this.gain[0];
                }
                if (num3 > num4)
                {
                    float num5 = num4 / num3;
                    for (int i = 0; i < 3; i++)
                    {
                        this.gain[i] *= num5;
                    }
                }
            }
            gain_val[0] = this.gain[0];
            gain_val[1] = this.gain[1];
            gain_val[2] = this.gain[2];
            for (int i = 0; i < 3; i++)
            {
                int num6 = num + 1 - i;
                int num7 = nsf;
                if (num7 > num6)
                {
                    num7 = num6;
                }
                int num8 = nsf;
                if (num8 > num6 + num)
                {
                    num8 = num6 + num;
                }
                for (int j = 0; j < num7; j++)
                {
                    this.e[i][j] = exc[es + j - num6];
                }
                for (int j = num7; j < num8; j++)
                {
                    this.e[i][j] = exc[es + j - num6 - num];
                }
                for (int j = num8; j < nsf; j++)
                {
                    this.e[i][j] = 0f;
                }
            }
            for (int i = 0; i < nsf; i++)
            {
                exc[es + i] = this.gain[0] * this.e[2][i] + this.gain[1] * this.e[1][i] + this.gain[2] * this.e[0][i];
            }
            return(num);
        }
Esempio n. 12
0
        public virtual int Decode(Bits bits, float[] xout)
        {
            int num = 0;

            float[] array = new float[3];
            float   num2  = 0f;
            int     num3  = 40;
            float   num4  = 0f;
            float   num5  = 0f;

            if (bits == null && this.dtx_enabled != 0)
            {
                this.submodeID = 0;
            }
            else
            {
                if (bits == null)
                {
                    this.DecodeLost(xout);
                    return(0);
                }
                while (bits.BitsRemaining() >= 5)
                {
                    int num6;
                    if (bits.Unpack(1) != 0)
                    {
                        num6 = bits.Unpack(3);
                        int num7 = SbCodec.SB_FRAME_SIZE[num6];
                        if (num7 < 0)
                        {
                            throw new InvalidFormatException("Invalid sideband mode encountered (1st sideband): " + num6);
                        }
                        num7 -= 4;
                        bits.Advance(num7);
                        if (bits.Unpack(1) != 0)
                        {
                            num6 = bits.Unpack(3);
                            num7 = SbCodec.SB_FRAME_SIZE[num6];
                            if (num7 < 0)
                            {
                                throw new InvalidFormatException("Invalid sideband mode encountered. (2nd sideband): " + num6);
                            }
                            num7 -= 4;
                            bits.Advance(num7);
                            if (bits.Unpack(1) != 0)
                            {
                                throw new InvalidFormatException("More than two sideband layers found");
                            }
                        }
                    }
                    if (bits.BitsRemaining() < 4)
                    {
                        return(1);
                    }
                    num6 = bits.Unpack(4);
                    if (num6 == 15)
                    {
                        return(1);
                    }
                    if (num6 == 14)
                    {
                        this.inband.SpeexInbandRequest(bits);
                    }
                    else if (num6 == 13)
                    {
                        this.inband.UserInbandRequest(bits);
                    }
                    else if (num6 > 8)
                    {
                        throw new InvalidFormatException("Invalid mode encountered: " + num6);
                    }
                    if (num6 <= 8)
                    {
                        this.submodeID = num6;
                        goto IL_199;
                    }
                }
                return(-1);
            }
IL_199:
            Array.Copy(this.frmBuf, this.frameSize, this.frmBuf, 0, this.bufSize - this.frameSize);
            Array.Copy(this.excBuf, this.frameSize, this.excBuf, 0, this.bufSize - this.frameSize);
            if (this.submodes[this.submodeID] == null)
            {
                Filters.Bw_lpc(0.93f, this.interp_qlpc, this.lpc, 10);
                float num8 = 0f;
                for (int i = 0; i < this.frameSize; i++)
                {
                    num8 += this.innov[i] * this.innov[i];
                }
                num8 = (float)Math.Sqrt((double)(num8 / (float)this.frameSize));
                for (int i = this.excIdx; i < this.excIdx + this.frameSize; i++)
                {
                    this.excBuf[i] = (float)((double)(3f * num8) * (this.random.NextDouble() - 0.5));
                }
                this.first = 1;
                Filters.Iir_mem2(this.excBuf, this.excIdx, this.lpc, this.frmBuf, this.frmIdx, this.frameSize, this.lpcSize, this.mem_sp);
                xout[0] = this.frmBuf[this.frmIdx] + this.preemph * this.pre_mem;
                for (int i = 1; i < this.frameSize; i++)
                {
                    xout[i] = this.frmBuf[this.frmIdx + i] + this.preemph * xout[i - 1];
                }
                this.pre_mem    = xout[this.frameSize - 1];
                this.count_lost = 0;
                return(0);
            }
            this.submodes[this.submodeID].LsqQuant.Unquant(this.qlsp, this.lpcSize, bits);
            if (this.count_lost != 0)
            {
                float num9 = 0f;
                for (int i = 0; i < this.lpcSize; i++)
                {
                    num9 += Math.Abs(this.old_qlsp[i] - this.qlsp[i]);
                }
                float num10 = (float)(0.6 * Math.Exp(-0.2 * (double)num9));
                for (int i = 0; i < 2 * this.lpcSize; i++)
                {
                    this.mem_sp[i] *= num10;
                }
            }
            if (this.first != 0 || this.count_lost != 0)
            {
                for (int i = 0; i < this.lpcSize; i++)
                {
                    this.old_qlsp[i] = this.qlsp[i];
                }
            }
            if (this.submodes[this.submodeID].LbrPitch != -1)
            {
                num = this.min_pitch + bits.Unpack(7);
            }
            if (this.submodes[this.submodeID].ForcedPitchGain != 0)
            {
                int num11 = bits.Unpack(4);
                num2 = 0.066667f * (float)num11;
            }
            int   num12 = bits.Unpack(5);
            float num13 = (float)Math.Exp((double)num12 / 3.5);

            if (this.submodeID == 1)
            {
                int num14 = bits.Unpack(4);
                if (num14 == 15)
                {
                    this.dtx_enabled = 1;
                }
                else
                {
                    this.dtx_enabled = 0;
                }
            }
            if (this.submodeID > 1)
            {
                this.dtx_enabled = 0;
            }
            for (int j = 0; j < this.nbSubframes; j++)
            {
                int   num15 = this.subframeSize * j;
                int   num16 = this.frmIdx + num15;
                int   num17 = this.excIdx + num15;
                float num18 = (1f + (float)j) / (float)this.nbSubframes;
                for (int i = 0; i < this.lpcSize; i++)
                {
                    this.interp_qlsp[i] = (1f - num18) * this.old_qlsp[i] + num18 * this.qlsp[i];
                }
                Lsp.Enforce_margin(this.interp_qlsp, this.lpcSize, 0.002f);
                for (int i = 0; i < this.lpcSize; i++)
                {
                    this.interp_qlsp[i] = (float)Math.Cos((double)this.interp_qlsp[i]);
                }
                this.m_lsp.Lsp2lpc(this.interp_qlsp, this.interp_qlpc, this.lpcSize);
                if (this.enhanced)
                {
                    float num19    = 0.9f;
                    float lpcEnhK  = this.submodes[this.submodeID].LpcEnhK1;
                    float lpcEnhK2 = this.submodes[this.submodeID].LpcEnhK2;
                    float gamma    = (1f - (1f - num19 * lpcEnhK) / (1f - num19 * lpcEnhK2)) / num19;
                    Filters.Bw_lpc(lpcEnhK, this.interp_qlpc, this.awk1, this.lpcSize);
                    Filters.Bw_lpc(lpcEnhK2, this.interp_qlpc, this.awk2, this.lpcSize);
                    Filters.Bw_lpc(gamma, this.interp_qlpc, this.awk3, this.lpcSize);
                }
                num18           = 1f;
                this.pi_gain[j] = 0f;
                for (int i = 0; i <= this.lpcSize; i++)
                {
                    this.pi_gain[j] += num18 * this.interp_qlpc[i];
                    num18            = -num18;
                }
                for (int i = 0; i < this.subframeSize; i++)
                {
                    this.excBuf[num17 + i] = 0f;
                }
                int num20;
                if (this.submodes[this.submodeID].LbrPitch != -1)
                {
                    int lbrPitch = this.submodes[this.submodeID].LbrPitch;
                    if (lbrPitch != 0)
                    {
                        num20 = num - lbrPitch + 1;
                        if (num20 < this.min_pitch)
                        {
                            num20 = this.min_pitch;
                        }
                        int num21 = num + lbrPitch;
                        if (num21 > this.max_pitch)
                        {
                            num21 = this.max_pitch;
                        }
                    }
                    else
                    {
                        num20 = num;
                    }
                }
                else
                {
                    num20 = this.min_pitch;
                    int num21 = this.max_pitch;
                }
                int num22 = this.submodes[this.submodeID].Ltp.Unquant(this.excBuf, num17, num20, num2, this.subframeSize, array, bits, this.count_lost, num15, this.last_pitch_gain);
                if (this.count_lost != 0 && num13 < this.last_ol_gain)
                {
                    float num23 = num13 / (this.last_ol_gain + 1f);
                    for (int i = 0; i < this.subframeSize; i++)
                    {
                        this.excBuf[this.excIdx + i] *= num23;
                    }
                }
                num18 = Math.Abs(array[0] + array[1] + array[2]);
                num18 = Math.Abs(array[1]);
                if (array[0] > 0f)
                {
                    num18 += array[0];
                }
                else
                {
                    num18 -= 0.5f * array[0];
                }
                if (array[2] > 0f)
                {
                    num18 += array[2];
                }
                else
                {
                    num18 -= 0.5f * array[0];
                }
                num5 += num18;
                if (num18 > num4)
                {
                    num3 = num22;
                    num4 = num18;
                }
                int num24 = j * this.subframeSize;
                for (int i = num24; i < num24 + this.subframeSize; i++)
                {
                    this.innov[i] = 0f;
                }
                float num26;
                if (this.submodes[this.submodeID].HaveSubframeGain == 3)
                {
                    int num25 = bits.Unpack(3);
                    num26 = (float)((double)num13 * Math.Exp((double)NbCodec.exc_gain_quant_scal3[num25]));
                }
                else if (this.submodes[this.submodeID].HaveSubframeGain == 1)
                {
                    int num25 = bits.Unpack(1);
                    num26 = (float)((double)num13 * Math.Exp((double)NbCodec.exc_gain_quant_scal1[num25]));
                }
                else
                {
                    num26 = num13;
                }
                if (this.submodes[this.submodeID].Innovation != null)
                {
                    this.submodes[this.submodeID].Innovation.Unquantify(this.innov, num24, this.subframeSize, bits);
                }
                for (int i = num24; i < num24 + this.subframeSize; i++)
                {
                    this.innov[i] *= num26;
                }
                if (this.submodeID == 1)
                {
                    float num27 = num2;
                    for (int i = 0; i < this.subframeSize; i++)
                    {
                        this.excBuf[num17 + i] = 0f;
                    }
                    while (this.voc_offset < this.subframeSize)
                    {
                        if (this.voc_offset >= 0)
                        {
                            this.excBuf[num17 + this.voc_offset] = (float)Math.Sqrt((double)(1f * (float)num));
                        }
                        this.voc_offset += num;
                    }
                    this.voc_offset -= this.subframeSize;
                    num27            = 0.5f + 2f * (num27 - 0.6f);
                    if (num27 < 0f)
                    {
                        num27 = 0f;
                    }
                    if (num27 > 1f)
                    {
                        num27 = 1f;
                    }
                    for (int i = 0; i < this.subframeSize; i++)
                    {
                        float voc_m = this.excBuf[num17 + i];
                        this.excBuf[num17 + i]  = 0.8f * num27 * this.excBuf[num17 + i] * num13 + 0.6f * num27 * this.voc_m1 * num13 + 0.5f * num27 * this.innov[num24 + i] - 0.5f * num27 * this.voc_m2 + (1f - num27) * this.innov[num24 + i];
                        this.voc_m1             = voc_m;
                        this.voc_m2             = this.innov[num24 + i];
                        this.voc_mean           = 0.95f * this.voc_mean + 0.05f * this.excBuf[num17 + i];
                        this.excBuf[num17 + i] -= this.voc_mean;
                    }
                }
                else
                {
                    for (int i = 0; i < this.subframeSize; i++)
                    {
                        this.excBuf[num17 + i] += this.innov[num24 + i];
                    }
                }
                if (this.submodes[this.submodeID].DoubleCodebook != 0)
                {
                    for (int i = 0; i < this.subframeSize; i++)
                    {
                        this.innov2[i] = 0f;
                    }
                    this.submodes[this.submodeID].Innovation.Unquantify(this.innov2, 0, this.subframeSize, bits);
                    for (int i = 0; i < this.subframeSize; i++)
                    {
                        this.innov2[i] *= num26 * 0.454545438f;
                    }
                    for (int i = 0; i < this.subframeSize; i++)
                    {
                        this.excBuf[num17 + i] += this.innov2[i];
                    }
                }
                for (int i = 0; i < this.subframeSize; i++)
                {
                    this.frmBuf[num16 + i] = this.excBuf[num17 + i];
                }
                if (this.enhanced && this.submodes[this.submodeID].CombGain > 0f)
                {
                    this.filters.Comb_filter(this.excBuf, num17, this.frmBuf, num16, this.subframeSize, num22, array, this.submodes[this.submodeID].CombGain);
                }
                if (this.enhanced)
                {
                    Filters.Filter_mem2(this.frmBuf, num16, this.awk2, this.awk1, this.subframeSize, this.lpcSize, this.mem_sp, this.lpcSize);
                    Filters.Filter_mem2(this.frmBuf, num16, this.awk3, this.interp_qlpc, this.subframeSize, this.lpcSize, this.mem_sp, 0);
                }
                else
                {
                    for (int i = 0; i < this.lpcSize; i++)
                    {
                        this.mem_sp[this.lpcSize + i] = 0f;
                    }
                    Filters.Iir_mem2(this.frmBuf, num16, this.interp_qlpc, this.frmBuf, num16, this.subframeSize, this.lpcSize, this.mem_sp);
                }
            }
            xout[0] = this.frmBuf[this.frmIdx] + this.preemph * this.pre_mem;
            for (int i = 1; i < this.frameSize; i++)
            {
                xout[i] = this.frmBuf[this.frmIdx + i] + this.preemph * xout[i - 1];
            }
            this.pre_mem = xout[this.frameSize - 1];
            for (int i = 0; i < this.lpcSize; i++)
            {
                this.old_qlsp[i] = this.qlsp[i];
            }
            this.first           = 0;
            this.count_lost      = 0;
            this.last_pitch      = num3;
            this.last_pitch_gain = 0.25f * num5;
            this.pitch_gain_buf[this.pitch_gain_buf_idx++] = this.last_pitch_gain;
            if (this.pitch_gain_buf_idx > 2)
            {
                this.pitch_gain_buf_idx = 0;
            }
            this.last_ol_gain = num13;
            return(0);
        }
        /// <summary>
        /// Decode the given input bits.
        /// </summary>
        /// <returns>1 if a terminator was found, 0 if not.</returns>
        /// <exception cref="InvalidFormatException">If there is an error detected in the data stream.</exception>
        public virtual int Decode(Bits bits, float[] xout)
        {
            int i, sub, pitch, ol_pitch = 0, m;

            float[] pitch_gain = new float[3];
            float   ol_gain = 0.0f, ol_pitch_coef = 0.0f;
            int     best_pitch      = 40;
            float   best_pitch_gain = 0;
            float   pitch_average   = 0;

            if (bits == null && dtx_enabled != 0)
            {
                submodeID = 0;
            }
            else
            {
                /*
                 * If bits is NULL, consider the packet to be lost (what could we do
                 * anyway)
                 */
                if (bits == null)
                {
                    DecodeLost(xout);
                    return(0);
                }

                /*
                 * Search for next narrowband block (handle requests, skip wideband
                 * blocks)
                 */
                do
                {
                    if (bits.BitsRemaining() < 5)
                    {
                        return(-1);
                    }

                    if (bits.Unpack(1) != 0)
                    {                     /*
                                           * Skip wideband block (for
                                           * compatibility)
                                           */
                        // Wideband
                        /* Get the sub-mode that was used */
                        m = bits.Unpack(NSpeex.SbCodec.SB_SUBMODE_BITS);
                        int advance = NSpeex.SbCodec.SB_FRAME_SIZE[m];
                        if (advance < 0)
                        {
                            throw new InvalidFormatException(
                                      "Invalid sideband mode encountered (1st sideband): "
                                      + m);
                            // return -2;
                        }
                        advance -= (NSpeex.SbCodec.SB_SUBMODE_BITS + 1);
                        bits.Advance(advance);
                        if (bits.Unpack(1) != 0)
                        {                         /*
                                                   * Skip ultra-wideband block
                                                   * (for compatibility)
                                                   */
                            /* Get the sub-mode that was used */
                            m       = bits.Unpack(NSpeex.SbCodec.SB_SUBMODE_BITS);
                            advance = NSpeex.SbCodec.SB_FRAME_SIZE[m];
                            if (advance < 0)
                            {
                                throw new InvalidFormatException(
                                          "Invalid sideband mode encountered. (2nd sideband): "
                                          + m);
                                // return -2;
                            }
                            advance -= (NSpeex.SbCodec.SB_SUBMODE_BITS + 1);
                            bits.Advance(advance);
                            if (bits.Unpack(1) != 0)
                            {                             /* Sanity check */
                                throw new InvalidFormatException(
                                          "More than two sideband layers found");
                                // return -2;
                            }
                        }
                        // */
                    }

                    if (bits.BitsRemaining() < 4)
                    {
                        return(1);
                    }

                    /* Get the sub-mode that was used */
                    m = bits.Unpack(NSpeex.NbCodec.NB_SUBMODE_BITS);
                    if (m == 15)
                    {                     /* We found a terminator */
                        return(1);
                    }
                    else if (m == 14)
                    {                     /* Speex in-band request */
                        inband.SpeexInbandRequest(bits);
                    }
                    else if (m == 13)
                    {                     /* User in-band request */
                        inband.UserInbandRequest(bits);
                    }
                    else if (m > 8)
                    {                     /* Invalid mode */
                        throw new InvalidFormatException(
                                  "Invalid mode encountered: " + m);
                        // return -2;
                    }
                } while (m > 8);
                submodeID = m;
            }

            /* Shift all buffers by one frame */
            System.Array.Copy(frmBuf, frameSize, frmBuf, 0, bufSize
                              - frameSize);
            System.Array.Copy(excBuf, frameSize, excBuf, 0, bufSize
                              - frameSize);

            /* If null mode (no transmission), just set a couple things to zero */
            if (submodes[submodeID] == null)
            {
                NSpeex.Filters.Bw_lpc(.93f, interp_qlpc, lpc, 10);

                float innov_gain = 0;
                for (i = 0; i < frameSize; i++)
                {
                    innov_gain += innov[i] * innov[i];
                }
                innov_gain = (float)Math.Sqrt(innov_gain / frameSize);
                for (i = excIdx; i < excIdx + frameSize; i++)
                {
                    excBuf[i] = (float)(3 * innov_gain * (random.NextDouble() - .5f));
                }
                first = 1;

                /* Final signal synthesis from excitation */
                NSpeex.Filters.Iir_mem2(excBuf, excIdx, lpc, frmBuf, frmIdx,
                                        frameSize, lpcSize, mem_sp);

                xout[0] = frmBuf[frmIdx] + preemph * pre_mem;
                for (i = 1; i < frameSize; i++)
                {
                    xout[i] = frmBuf[frmIdx + i] + preemph * xout[i - 1];
                }
                pre_mem    = xout[frameSize - 1];
                count_lost = 0;
                return(0);
            }

            /* Unquantize LSPs */
            submodes[submodeID].LsqQuant.Unquant(qlsp, lpcSize, bits);

            /* Damp memory if a frame was lost and the LSP changed too much */
            if (count_lost != 0)
            {
                float lsp_dist = 0, fact;
                for (i = 0; i < lpcSize; i++)
                {
                    lsp_dist += Math.Abs(old_qlsp[i] - qlsp[i]);
                }
                fact = (float)(.6d * Math.Exp(-.2d * lsp_dist));
                for (i = 0; i < 2 * lpcSize; i++)
                {
                    mem_sp[i] *= fact;
                }
            }

            /* Handle first frame and lost-packet case */
            if (first != 0 || count_lost != 0)
            {
                for (i = 0; i < lpcSize; i++)
                {
                    old_qlsp[i] = qlsp[i];
                }
            }

            /* Get open-loop pitch estimation for low bit-rate pitch coding */
            if (submodes[submodeID].LbrPitch != -1)
            {
                ol_pitch = min_pitch + bits.Unpack(7);
            }

            if (submodes[submodeID].ForcedPitchGain != 0)
            {
                int quant = bits.Unpack(4);
                ol_pitch_coef = 0.066667f * quant;
            }

            /* Get global excitation gain */
            int qe = bits.Unpack(5);

            ol_gain = (float)Math.Exp(qe / 3.5d);

            /* unpacks unused dtx bits */
            if (submodeID == 1)
            {
                int extra = bits.Unpack(4);
                if (extra == 15)
                {
                    dtx_enabled = 1;
                }
                else
                {
                    dtx_enabled = 0;
                }
            }
            if (submodeID > 1)
            {
                dtx_enabled = 0;
            }

            /* Loop on subframes */
            for (sub = 0; sub < nbSubframes; sub++)
            {
                int   offset, spIdx, extIdx;
                float tmp;
                /* Offset relative to start of frame */
                offset = subframeSize * sub;
                /* Original signal */
                spIdx = frmIdx + offset;
                /* Excitation */
                extIdx = excIdx + offset;

                /* LSP interpolation (quantized and unquantized) */
                tmp = (1.0f + sub) / nbSubframes;
                for (i = 0; i < lpcSize; i++)
                {
                    interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i];
                }

                /* Make sure the LSP's are stable */
                NSpeex.Lsp.Enforce_margin(interp_qlsp, lpcSize, .002f);

                /* Compute interpolated LPCs (unquantized) */
                for (i = 0; i < lpcSize; i++)
                {
                    interp_qlsp[i] = (float)System.Math.Cos(interp_qlsp[i]);
                }
                m_lsp.Lsp2lpc(interp_qlsp, interp_qlpc, lpcSize);

                /* Compute enhanced synthesis filter */
                if (enhanced)
                {
                    float r = .9f;
                    float k1, k2, k3;

                    k1 = submodes[submodeID].LpcEnhK1;
                    k2 = submodes[submodeID].LpcEnhK2;
                    k3 = (1 - (1 - r * k1) / (1 - r * k2)) / r;
                    NSpeex.Filters.Bw_lpc(k1, interp_qlpc, awk1, lpcSize);
                    NSpeex.Filters.Bw_lpc(k2, interp_qlpc, awk2, lpcSize);
                    NSpeex.Filters.Bw_lpc(k3, interp_qlpc, awk3, lpcSize);
                }

                /* Compute analysis filter at w=pi */
                tmp          = 1;
                pi_gain[sub] = 0;
                for (i = 0; i <= lpcSize; i++)
                {
                    pi_gain[sub] += tmp * interp_qlpc[i];
                    tmp           = -tmp;
                }

                /* Reset excitation */
                for (i = 0; i < subframeSize; i++)
                {
                    excBuf[extIdx + i] = 0;
                }

                /* Adaptive codebook contribution */
                int pit_min, pit_max;

                /* Handle pitch constraints if any */
                if (submodes[submodeID].LbrPitch != -1)
                {
                    int margin = submodes[submodeID].LbrPitch;
                    if (margin != 0)
                    {
                        pit_min = ol_pitch - margin + 1;
                        if (pit_min < min_pitch)
                        {
                            pit_min = min_pitch;
                        }
                        pit_max = ol_pitch + margin;
                        if (pit_max > max_pitch)
                        {
                            pit_max = max_pitch;
                        }
                    }
                    else
                    {
                        pit_min = pit_max = ol_pitch;
                    }
                }
                else
                {
                    pit_min = min_pitch;
                    pit_max = max_pitch;
                }

                /* Pitch synthesis */
                pitch = submodes[submodeID].Ltp.Unquant(excBuf, extIdx, pit_min,
                                                        ol_pitch_coef, subframeSize, pitch_gain, bits, count_lost,
                                                        offset, last_pitch_gain);

                /* If we had lost frames, check energy of last received frame */
                if (count_lost != 0 && ol_gain < last_ol_gain)
                {
                    float fact_0 = ol_gain / (last_ol_gain + 1);
                    for (i = 0; i < subframeSize; i++)
                    {
                        excBuf[excIdx + i] *= fact_0;
                    }
                }

                tmp = Math.Abs(pitch_gain[0] + pitch_gain[1]
                               + pitch_gain[2]);
                tmp = Math.Abs(pitch_gain[1]);
                if (pitch_gain[0] > 0)
                {
                    tmp += pitch_gain[0];
                }
                else
                {
                    tmp -= .5f * pitch_gain[0];
                }
                if (pitch_gain[2] > 0)
                {
                    tmp += pitch_gain[2];
                }
                else
                {
                    tmp -= .5f * pitch_gain[0];
                }

                pitch_average += tmp;
                if (tmp > best_pitch_gain)
                {
                    best_pitch      = pitch;
                    best_pitch_gain = tmp;
                }

                /* Unquantize the innovation */
                int   q_energy, ivi = sub * subframeSize;
                float ener;

                for (i = ivi; i < ivi + subframeSize; i++)
                {
                    innov[i] = 0.0f;
                }

                /* Decode sub-frame gain correction */
                if (submodes[submodeID].HaveSubframeGain == 3)
                {
                    q_energy = bits.Unpack(3);
                    ener     = (float)(ol_gain * Math.Exp(NSpeex.NbCodec.exc_gain_quant_scal3[q_energy]));
                }
                else if (submodes[submodeID].HaveSubframeGain == 1)
                {
                    q_energy = bits.Unpack(1);
                    ener     = (float)(ol_gain * Math.Exp(NSpeex.NbCodec.exc_gain_quant_scal1[q_energy]));
                }
                else
                {
                    ener = ol_gain;
                }

                if (submodes[submodeID].Innovation != null)
                {
                    /* Fixed codebook contribution */
                    submodes[submodeID].Innovation.Unquantify(innov, ivi,
                                                              subframeSize, bits);
                }

                /* De-normalize innovation and update excitation */
                for (i = ivi; i < ivi + subframeSize; i++)
                {
                    innov[i] *= ener;
                }

                /* Vocoder mode */
                if (submodeID == 1)
                {
                    float g = ol_pitch_coef;

                    for (i = 0; i < subframeSize; i++)
                    {
                        excBuf[extIdx + i] = 0;
                    }
                    while (voc_offset < subframeSize)
                    {
                        if (voc_offset >= 0)
                        {
                            excBuf[extIdx + voc_offset] = (float)Math.Sqrt(1.0f * ol_pitch);
                        }
                        voc_offset += ol_pitch;
                    }
                    voc_offset -= subframeSize;

                    g = .5f + 2 * (g - .6f);
                    if (g < 0)
                    {
                        g = 0;
                    }
                    if (g > 1)
                    {
                        g = 1;
                    }
                    for (i = 0; i < subframeSize; i++)
                    {
                        float itmp = excBuf[extIdx + i];
                        excBuf[extIdx + i] = .8f * g * excBuf[extIdx + i] * ol_gain
                                             + .6f * g * voc_m1 * ol_gain + .5f * g
                                             * innov[ivi + i] - .5f * g * voc_m2 + (1 - g)
                                             * innov[ivi + i];
                        voc_m1              = itmp;
                        voc_m2              = innov[ivi + i];
                        voc_mean            = .95f * voc_mean + .05f * excBuf[extIdx + i];
                        excBuf[extIdx + i] -= voc_mean;
                    }
                }
                else
                {
                    for (i = 0; i < subframeSize; i++)
                    {
                        excBuf[extIdx + i] += innov[ivi + i];
                    }
                }

                /* Decode second codebook (only for some modes) */
                if (submodes[submodeID].DoubleCodebook != 0)
                {
                    for (i = 0; i < subframeSize; i++)
                    {
                        innov2[i] = 0;
                    }
                    submodes[submodeID].Innovation.Unquantify(innov2, 0, subframeSize,
                                                              bits);
                    for (i = 0; i < subframeSize; i++)
                    {
                        innov2[i] *= ener * (1 / 2.2f);
                    }
                    for (i = 0; i < subframeSize; i++)
                    {
                        excBuf[extIdx + i] += innov2[i];
                    }
                }

                for (i = 0; i < subframeSize; i++)
                {
                    frmBuf[spIdx + i] = excBuf[extIdx + i];
                }

                /* Signal synthesis */
                if (enhanced && submodes[submodeID].CombGain > 0)
                {
                    filters.Comb_filter(excBuf, extIdx, frmBuf, spIdx,
                                        subframeSize, pitch, pitch_gain,
                                        submodes[submodeID].CombGain);
                }

                if (enhanced)
                {
                    /* Use enhanced LPC filter */
                    NSpeex.Filters.Filter_mem2(frmBuf, spIdx, awk2, awk1,
                                               subframeSize, lpcSize, mem_sp, lpcSize);
                    NSpeex.Filters.Filter_mem2(frmBuf, spIdx, awk3, interp_qlpc,
                                               subframeSize, lpcSize, mem_sp, 0);
                }
                else
                {
                    /* Use regular filter */
                    for (i = 0; i < lpcSize; i++)
                    {
                        mem_sp[lpcSize + i] = 0;
                    }
                    NSpeex.Filters.Iir_mem2(frmBuf, spIdx, interp_qlpc, frmBuf,
                                            spIdx, subframeSize, lpcSize, mem_sp);
                }
            }

            /* Copy output signal */
            xout[0] = frmBuf[frmIdx] + preemph * pre_mem;
            for (i = 1; i < frameSize; i++)
            {
                xout[i] = frmBuf[frmIdx + i] + preemph * xout[i - 1];
            }
            pre_mem = xout[frameSize - 1];

            /* Store the LSPs for interpolation in the next frame */
            for (i = 0; i < lpcSize; i++)
            {
                old_qlsp[i] = qlsp[i];
            }

            /* The next frame will not be the first (Duh!) */
            first           = 0;
            count_lost      = 0;
            last_pitch      = best_pitch;
            last_pitch_gain = .25f * pitch_average;
            pitch_gain_buf[pitch_gain_buf_idx++] = last_pitch_gain;
            if (pitch_gain_buf_idx > 2)             /* rollover */
            {
                pitch_gain_buf_idx = 0;
            }
            last_ol_gain = ol_gain;

            return(0);
        }