示例#1
0
        /// <summary>
        /// Encode the given input signal.
        /// </summary>
        /// <param name="bits">Speex bits buffer.</param>
        /// <param name="vin">the raw mono audio frame to encode</param>
        /// <returns>1 if successful.</returns>
        public int Encode(Bits bits, float[] vin)
        {
            int i;

            float[] mem, innov, syn_resp;
            float[] low_pi_gain, low_exc, low_innov;
            int     dtx;

            /* Compute the two sub-bands by filtering with h0 and h1*/
            Filters.qmf_decomp(vin, h0, x0d, x1d, fullFrameSize, QMF_ORDER, h0_mem);
            /* Encode the narrowband part*/
            lowenc.Encode(bits, x0d);

            /* High-band buffering / sync with low band */
            for (i = 0; i < windowSize - frameSize; i++)
            {
                high[i] = high[frameSize + i];
            }
            for (i = 0; i < frameSize; i++)
            {
                high[windowSize - frameSize + i] = x1d[i];
            }

            Array.Copy(excBuf, frameSize, excBuf, 0, bufSize - frameSize);

            low_pi_gain = lowenc.PitchGain;
            low_exc     = lowenc.Excitation;
            low_innov   = lowenc.Innovation;


            int low_mode = lowenc.Mode;

            if (low_mode == 0)
            {
                dtx = 1;
            }
            else
            {
                dtx = 0;
            }

            /* Start encoding the high-band */
            for (i = 0; i < windowSize; i++)
            {
                buf[i] = high[i] * window[i];
            }

            /* Compute auto-correlation */
            Lpc.autocorr(buf, autocorr, lpcSize + 1, windowSize);

            autocorr[0] += 1;         /* prevents NANs */
            autocorr[0] *= lpc_floor; /* Noise floor in auto-correlation domain */
            /* Lag windowing: equivalent to filtering in the power-spectrum domain */
            for (i = 0; i < lpcSize + 1; i++)
            {
                autocorr[i] *= lagWindow[i];
            }

            /* Levinson-Durbin */
            Lpc.wld(lpc, autocorr, rc, lpcSize); // tmperr
            Array.Copy(lpc, 0, lpc, 1, lpcSize);
            lpc[0] = 1;
            /* LPC to LSPs (x-domain) transform */
            int roots = Lsp.lpc2lsp(lpc, lpcSize, lsp, 15, 0.2f);

            if (roots != lpcSize)
            {
                roots = Lsp.lpc2lsp(lpc, lpcSize, lsp, 11, 0.02f);
                if (roots != lpcSize)
                {
                    /*If we can't find all LSP's, do some damage control and use a flat filter*/
                    for (i = 0; i < lpcSize; i++)
                    {
                        lsp[i] = (float)Math.Cos(Math.PI * ((float)(i + 1)) / (lpcSize + 1));
                    }
                }
            }
            /* x-domain to angle domain*/
            for (i = 0; i < lpcSize; i++)
            {
                lsp[i] = (float)Math.Acos(lsp[i]);
            }

            float lsp_dist = 0;

            for (i = 0; i < lpcSize; i++)
            {
                lsp_dist += (old_lsp[i] - lsp[i]) * (old_lsp[i] - lsp[i]);
            }
            /*VBR stuff*/
            if ((vbr_enabled != 0 || vad_enabled != 0) && dtx == 0)
            {
                float e_low = 0, e_high = 0;
                float ratio;
                if (abr_enabled != 0)
                {
                    float qual_change = 0;
                    if (abr_drift2 * abr_drift > 0)
                    {
                        /* Only adapt if long-term and short-term drift are the same sign */
                        qual_change = -.00001f * abr_drift / (1 + abr_count);
                        if (qual_change > .1f)
                        {
                            qual_change = .1f;
                        }
                        if (qual_change < -.1f)
                        {
                            qual_change = -.1f;
                        }
                    }
                    vbr_quality += qual_change;
                    if (vbr_quality > 10)
                    {
                        vbr_quality = 10;
                    }
                    if (vbr_quality < 0)
                    {
                        vbr_quality = 0;
                    }
                }
                for (i = 0; i < frameSize; i++)
                {
                    e_low  += x0d[i] * x0d[i];
                    e_high += high[i] * high[i];
                }
                ratio            = (float)Math.Log((1 + e_high) / (1 + e_low));
                relative_quality = lowenc.RelativeQuality;

                if (ratio < -4)
                {
                    ratio = -4;
                }
                if (ratio > 2)
                {
                    ratio = 2;
                }
                /*if (ratio>-2)*/
                if (vbr_enabled != 0)
                {
                    int modeid;
                    modeid            = nb_modes - 1;
                    relative_quality += 1.0f * (ratio + 2f);
                    if (relative_quality < -1)
                    {
                        relative_quality = -1;
                    }
                    while (modeid != 0)
                    {
                        int   v1;
                        float thresh;
                        v1 = (int)Math.Floor(vbr_quality);
                        if (v1 == 10)
                        {
                            thresh = NSpeex.Vbr.hb_thresh[modeid][v1];
                        }
                        else
                        {
                            thresh = (vbr_quality - v1) * NSpeex.Vbr.hb_thresh[modeid][v1 + 1] + (1 + v1 - vbr_quality) * NSpeex.Vbr.hb_thresh[modeid][v1];
                        }
                        if (relative_quality >= thresh)
                        {
                            break;
                        }
                        modeid--;
                    }
                    Mode = modeid;
                    if (abr_enabled != 0)
                    {
                        int bitrate = BitRate;
                        abr_drift += (bitrate - abr_enabled);
                        abr_drift2 = .95f * abr_drift2 + .05f * (bitrate - abr_enabled);
                        abr_count += 1.0f;
                    }
                }
                else
                {
                    /* VAD only */
                    int modeid;
                    if (relative_quality < 2.0)
                    {
                        modeid = 1;
                    }
                    else
                    {
                        modeid = submodeSelect;
                    }
                    /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/
                    submodeID = modeid;
                }
            }
            bits.Pack(1, 1);
            if (dtx != 0)
            {
                bits.Pack(0, SB_SUBMODE_BITS);
            }
            else
            {
                bits.Pack(submodeID, SB_SUBMODE_BITS);
            }
            /* If null mode (no transmission), just set a couple things to zero*/
            if (dtx != 0 || submodes[submodeID] == null)
            {
                for (i = 0; i < frameSize; i++)
                {
                    excBuf[excIdx + i] = swBuf[i] = VERY_SMALL;
                }

                for (i = 0; i < lpcSize; i++)
                {
                    mem_sw[i] = 0;
                }
                first = 1;

                /* Final signal synthesis from excitation */
                Filters.iir_mem2(excBuf, excIdx, interp_qlpc, high, 0, subframeSize, lpcSize, mem_sp);

                /* Reconstruct the original */
                filters.fir_mem_up(x0d, h0, y0, fullFrameSize, QMF_ORDER, g0_mem);
                filters.fir_mem_up(high, h1, y1, fullFrameSize, QMF_ORDER, g1_mem);

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

                if (dtx != 0)
                {
                    return(0);
                }
                else
                {
                    return(1);
                }
            }
            /* LSP quantization */
            submodes[submodeID].lsqQuant.quant(lsp, qlsp, lpcSize, bits);

            if (first != 0)
            {
                for (i = 0; i < lpcSize; i++)
                {
                    old_lsp[i] = lsp[i];
                }
                for (i = 0; i < lpcSize; i++)
                {
                    old_qlsp[i] = qlsp[i];
                }
            }
            mem      = new float[lpcSize];
            syn_resp = new float[subframeSize];
            innov    = new float[subframeSize];
            for (int sub = 0; sub < nbSubframes; sub++)
            {
                float tmp, filter_ratio;
                int   exc, sp, sw, resp;
                int   offset;
                float rl, rh, eh = 0, el = 0;
                int   fold;

                offset = subframeSize * sub;
                sp     = offset;
                exc    = excIdx + offset;
                resp   = offset;
                sw     = offset;
                /* LSP interpolation (quantized and unquantized) */
                tmp = (1.0f + sub) / nbSubframes;
                for (i = 0; i < lpcSize; i++)
                {
                    interp_lsp[i] = (1 - tmp) * old_lsp[i] + tmp * lsp[i];
                }
                for (i = 0; i < lpcSize; i++)
                {
                    interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i];
                }

                Lsp.enforce_margin(interp_lsp, lpcSize, .05f);
                Lsp.enforce_margin(interp_qlsp, lpcSize, .05f);
                /* Compute interpolated LPCs (quantized and unquantized) */
                for (i = 0; i < lpcSize; i++)
                {
                    interp_lsp[i] = (float)Math.Cos(interp_lsp[i]);
                }
                for (i = 0; i < lpcSize; i++)
                {
                    interp_qlsp[i] = (float)Math.Cos(interp_qlsp[i]);
                }

                m_lsp.lsp2lpc(interp_lsp, interp_lpc, lpcSize);
                m_lsp.lsp2lpc(interp_qlsp, interp_qlpc, lpcSize);

                Filters.bw_lpc(gamma1, interp_lpc, bw_lpc1, lpcSize);
                Filters.bw_lpc(gamma2, interp_lpc, bw_lpc2, lpcSize);

                /* Compute mid-band (4000 Hz for wideband) response of low-band and high-band
                 * filters */
                rl           = rh = 0;
                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);
                /* Compute ratio, will help predict the gain */
                filter_ratio = Math.Abs(.01f + rh) / (.01f + Math.Abs(rl));

                fold = filter_ratio < 5 ? 1 : 0;
                /*printf ("filter_ratio %f\n", filter_ratio);*/
                fold = 0;
                /* Compute "real excitation" */
                Filters.fir_mem2(high, sp, interp_qlpc, excBuf, exc, subframeSize, lpcSize, mem_sp2);
                /* Compute energy of low-band and high-band excitation */
                for (i = 0; i < subframeSize; i++)
                {
                    eh += excBuf[exc + i] * excBuf[exc + i];
                }
                if (submodes[submodeID].innovation == null)
                {
                    float g;
                    /*speex_bits_pack(bits, 1, 1);*/
                    for (i = 0; i < subframeSize; i++)
                    {
                        el += low_innov[offset + i] * low_innov[offset + i];
                    }

                    /* Gain to use if we want to use the low-band excitation for high-band */
                    g = eh / (.01f + el);
                    g = (float)Math.Sqrt(g);

                    g *= filter_ratio;
                    int quant = (int)Math.Floor(.5 + 10 + 8.0 * Math.Log((g + .0001)));
                    /*speex_warning_int("tata", quant);*/
                    if (quant < 0)
                    {
                        quant = 0;
                    }
                    if (quant > 31)
                    {
                        quant = 31;
                    }
                    bits.Pack(quant, 5);
                    g  = (float)(.1 * Math.Exp(quant / 9.4));
                    g /= filter_ratio;
                }
                else
                {
                    float gc, scale, scale_1;

                    for (i = 0; i < subframeSize; i++)
                    {
                        el += low_exc[offset + i] * low_exc[offset + i];
                    }
                    gc = (float)(Math.Sqrt(1 + eh) * filter_ratio / Math.Sqrt((1 + el) * subframeSize));
                    {
                        int qgc = (int)Math.Floor(.5 + 3.7 * (Math.Log(gc) + 2));
                        if (qgc < 0)
                        {
                            qgc = 0;
                        }
                        if (qgc > 15)
                        {
                            qgc = 15;
                        }
                        bits.Pack(qgc, 4);
                        gc = (float)Math.Exp((1 / 3.7) * qgc - 2);
                    }
                    scale   = gc * (float)Math.Sqrt(1 + el) / filter_ratio;
                    scale_1 = 1 / scale;

                    for (i = 0; i < subframeSize; i++)
                    {
                        excBuf[exc + i] = 0;
                    }
                    excBuf[exc] = 1;
                    Filters.syn_percep_zero(excBuf, exc, interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, subframeSize, lpcSize);

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

                    /* Compute zero response (ringing) of A(z/g1) / ( A(z/g2) * Aq(z) ) */
                    for (i = 0; i < lpcSize; i++)
                    {
                        mem[i] = mem_sp[i];
                    }
                    Filters.iir_mem2(excBuf, exc, interp_qlpc, excBuf, exc, subframeSize, lpcSize, mem);
                    for (i = 0; i < lpcSize; i++)
                    {
                        mem[i] = mem_sw[i];
                    }
                    Filters.filter_mem2(excBuf, exc, bw_lpc1, bw_lpc2, res, resp, subframeSize, lpcSize, mem, 0);

                    /* Compute weighted signal */
                    for (i = 0; i < lpcSize; i++)
                    {
                        mem[i] = mem_sw[i];
                    }
                    Filters.filter_mem2(high, sp, bw_lpc1, bw_lpc2, swBuf, sw, subframeSize, lpcSize, mem, 0);

                    /* Compute target signal */
                    for (i = 0; i < subframeSize; i++)
                    {
                        target[i] = swBuf[sw + i] - res[resp + i];
                    }

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

                    for (i = 0; i < subframeSize; i++)
                    {
                        target[i] *= scale_1;
                    }

                    /* Reset excitation */
                    for (i = 0; i < subframeSize; i++)
                    {
                        innov[i] = 0;
                    }
                    /*print_vec(target, st->subframeSize, "\ntarget");*/
                    submodes[submodeID].innovation.Quant(target, interp_qlpc, bw_lpc1, bw_lpc2,
                                                         lpcSize, subframeSize, innov, 0, syn_resp,
                                                         bits, (complexity + 1) >> 1);
                    /*print_vec(target, st->subframeSize, "after");*/

                    for (i = 0; i < subframeSize; i++)
                    {
                        excBuf[exc + i] += innov[i] * scale;
                    }
                    if (submodes[submodeID].double_codebook != 0)
                    {
                        float[] innov2 = new float[subframeSize];
                        for (i = 0; i < subframeSize; i++)
                        {
                            innov2[i] = 0;
                        }
                        for (i = 0; i < subframeSize; i++)
                        {
                            target[i] *= 2.5f;
                        }
                        submodes[submodeID].innovation.Quant(target, interp_qlpc, bw_lpc1, bw_lpc2,
                                                             lpcSize, subframeSize, innov2, 0, syn_resp,
                                                             bits, (complexity + 1) >> 1);
                        for (i = 0; i < subframeSize; i++)
                        {
                            innov2[i] *= scale * (1f / 2.5f);
                        }
                        for (i = 0; i < subframeSize; i++)
                        {
                            excBuf[exc + i] += innov2[i];
                        }
                    }
                }
                /*Keep the previous memory*/
                for (i = 0; i < lpcSize; i++)
                {
                    mem[i] = mem_sp[i];
                }
                /* Final signal synthesis from excitation */
                Filters.iir_mem2(excBuf, exc, interp_qlpc, high, sp, subframeSize, lpcSize, mem_sp);

                /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */
                Filters.filter_mem2(high, sp, bw_lpc1, bw_lpc2, swBuf, sw, subframeSize, lpcSize, mem_sw, 0);
            }
            //#ifndef RELEASE
            /* Reconstruct the original */
            filters.fir_mem_up(x0d, h0, y0, fullFrameSize, QMF_ORDER, g0_mem);
            filters.fir_mem_up(high, h1, y1, fullFrameSize, QMF_ORDER, g1_mem);

            for (i = 0; i < fullFrameSize; i++)
            {
                vin[i] = 2 * (y0[i] - y1[i]);
            }
            //#endif
            for (i = 0; i < lpcSize; i++)
            {
                old_lsp[i] = lsp[i];
            }
            for (i = 0; i < lpcSize; i++)
            {
                old_qlsp[i] = qlsp[i];
            }
            first = 0;
            return(1);
        }
示例#2
0
        /// <summary>
        /// Decode the given input bits.
        /// </summary>
        /// <param name="bits">Speex bits buffer.</param>
        /// <param name="vout">the decoded mono audio frame.</param>
        /// <returns>
        /// 1 if a terminator was found, 0 if not.
        /// </returns>
        public int Decode(Bits bits, float[] vout)
        {
            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(vout, 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 (submodes[submodeID] == null)
            {
                if (dtx)
                {
                    decodeLost(vout, true);
                    return(0);
                }
                for (i = 0; i < frameSize; i++)
                {
                    excBuf[i] = VERY_SMALL;
                }

                first = 1;
                Filters.iir_mem2(excBuf, excIdx, interp_qlpc, high, 0, frameSize,
                                 lpcSize, mem_sp);
                filters.fir_mem_up(x0d, Codebook.h0, y0, fullFrameSize, QMF_ORDER, g0_mem);
                filters.fir_mem_up(high, Codebook.h1, y1, fullFrameSize, QMF_ORDER, g1_mem);
                for (i = 0; i < fullFrameSize; i++)
                {
                    vout[i] = 2 * (y0[i] - y1[i]);
                }
                return(0);
            }
            low_pi_gain = lowdec.PitchGain;
            low_exc     = lowdec.Excitation;
            low_innov   = lowdec.Innovation;
            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];
                }
                Lsp.enforce_margin(interp_qlsp, lpcSize, .05f);
                /* LSPs to x-domain */
                for (i = 0; i < lpcSize; i++)
                {
                    interp_qlsp[i] = (float)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].lpc_enh_k1;
                    k2 = submodes[submodeID].lpc_enh_k2;
                    k3 = k1 - k2;
                    Filters.bw_lpc(k1, interp_qlpc, awk1, lpcSize);
                    Filters.bw_lpc(k2, interp_qlpc, awk2, lpcSize);
                    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.0);
                    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.UnQuant(excBuf, subIdx, subframeSize, bits);

                    for (i = subIdx; i < subIdx + subframeSize; i++)
                    {
                        excBuf[i] *= scale;
                    }
                    if (submodes[submodeID].double_codebook != 0)
                    {
                        for (i = 0; i < subframeSize; i++)
                        {
                            innov2[i] = 0;
                        }
                        submodes[submodeID].innovation.UnQuant(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 */
                    Filters.filter_mem2(high, subIdx, awk2, awk1, subframeSize,
                                        lpcSize, mem_sp, lpcSize);
                    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;
                    }
                    Filters.iir_mem2(high, subIdx, interp_qlpc, high, subIdx,
                                     subframeSize, lpcSize, mem_sp);
                }
            }
            filters.fir_mem_up(x0d, Codebook.h0, y0, fullFrameSize, QMF_ORDER, g0_mem);
            filters.fir_mem_up(high, Codebook.h1, y1, fullFrameSize, QMF_ORDER, g1_mem);

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

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

            first = 0;
            return(0);
        }
示例#3
0
        public int Encode(Bits bits, float[] vin)
        {
            int i;

            float[] res, target, mem;
            float[] syn_resp;
            float[] orig;
            /* Copy new data in input buffer */
            System.Array.Copy(frmBuf, frameSize, frmBuf, 0, bufSize - frameSize);
            frmBuf[bufSize - frameSize] = vin[0] - preemph * pre_mem;
            for (i = 1; i < frameSize; i++)
            {
                frmBuf[bufSize - frameSize + i] = vin[i] - preemph * vin[i - 1];
            }
            pre_mem = vin[frameSize - 1];

            /* Move signals 1 frame towards the past */
            System.Array.Copy(exc2Buf, frameSize, exc2Buf, 0, bufSize - frameSize);
            System.Array.Copy(excBuf, frameSize, excBuf, 0, bufSize - frameSize);
            System.Array.Copy(swBuf, frameSize, swBuf, 0, bufSize - frameSize);

            /* Window for analysis */
            for (i = 0; i < windowSize; i++)
            {
                buf2[i] = frmBuf[i + frmIdx] * window[i];
            }

            /* Compute auto-correlation */
            Lpc.autocorr(buf2, autocorr, lpcSize + 1, windowSize);

            autocorr[0] += 10;        /* prevents NANs */
            autocorr[0] *= lpc_floor; /* Noise floor in auto-correlation domain */

            /* Lag windowing: equivalent to filtering in the power-spectrum domain */
            for (i = 0; i < lpcSize + 1; i++)
            {
                autocorr[i] *= lagWindow[i];
            }

            /* Levinson-Durbin */
            Lpc.wld(lpc, autocorr, rc, lpcSize); // tmperr
            System.Array.Copy(lpc, 0, lpc, 1, lpcSize);
            lpc[0] = 1;

            /* LPC to LSPs (x-domain) transform */
            int roots = Lsp.lpc2lsp(lpc, lpcSize, lsp, 15, 0.2f);

            /* Check if we found all the roots */
            if (roots == lpcSize)
            {
                /* LSP x-domain to angle domain*/
                for (i = 0; i < lpcSize; i++)
                {
                    lsp[i] = (float)Math.Acos(lsp[i]);
                }
            }
            else
            {
                /* Search again if we can afford it */
                if (complexity > 1)
                {
                    roots = Lsp.lpc2lsp(lpc, lpcSize, lsp, 11, 0.05f);
                }
                if (roots == lpcSize)
                {
                    /* LSP x-domain to angle domain*/
                    for (i = 0; i < lpcSize; i++)
                    {
                        lsp[i] = (float)Math.Acos(lsp[i]);
                    }
                }
                else
                {
                    /*If we can't find all LSP's, do some damage control and use previous filter*/
                    for (i = 0; i < lpcSize; i++)
                    {
                        lsp[i] = old_lsp[i];
                    }
                }
            }

            float lsp_dist = 0;

            for (i = 0; i < lpcSize; i++)
            {
                lsp_dist += (old_lsp[i] - lsp[i]) * (old_lsp[i] - lsp[i]);
            }

            /* Whole frame analysis (open-loop estimation of pitch and excitation gain) */
            float ol_gain;
            int   ol_pitch;
            float ol_pitch_coef;

            {
                if (first != 0)
                {
                    for (i = 0; i < lpcSize; i++)
                    {
                        interp_lsp[i] = lsp[i];
                    }
                }
                else
                {
                    for (i = 0; i < lpcSize; i++)
                    {
                        interp_lsp[i] = .375f * old_lsp[i] + .625f * lsp[i];
                    }
                }

                Lsp.enforce_margin(interp_lsp, lpcSize, .002f);

                /* Compute interpolated LPCs (unquantized) for whole frame*/
                for (i = 0; i < lpcSize; i++)
                {
                    interp_lsp[i] = (float)Math.Cos(interp_lsp[i]);
                }
                m_lsp.lsp2lpc(interp_lsp, interp_lpc, lpcSize);

                /*Open-loop pitch*/
                if (submodes[submodeID] == null ||
                    vbr_enabled != 0 || vad_enabled != 0 ||
                    submodes[submodeID].forced_pitch_gain != 0 ||
                    submodes[submodeID].lbr_pitch != -1)
                {
                    int[]   nol_pitch      = new int[6];
                    float[] nol_pitch_coef = new float[6];

                    Filters.bw_lpc(gamma1, interp_lpc, bw_lpc1, lpcSize);
                    Filters.bw_lpc(gamma2, interp_lpc, bw_lpc2, lpcSize);

                    Filters.filter_mem2(frmBuf, frmIdx, bw_lpc1, bw_lpc2, swBuf, swIdx,
                                        frameSize, lpcSize, mem_sw_whole, 0);

                    Ltp.open_loop_nbest_pitch(swBuf, swIdx, min_pitch, max_pitch, frameSize,
                                              nol_pitch, nol_pitch_coef, 6);
                    ol_pitch      = nol_pitch[0];
                    ol_pitch_coef = nol_pitch_coef[0];
                    /*Try to remove pitch multiples*/
                    for (i = 1; i < 6; i++)
                    {
                        if ((nol_pitch_coef[i] > .85 * ol_pitch_coef) &&
                            (Math.Abs(nol_pitch[i] - ol_pitch / 2.0) <= 1 ||
                             Math.Abs(nol_pitch[i] - ol_pitch / 3.0) <= 1 ||
                             Math.Abs(nol_pitch[i] - ol_pitch / 4.0) <= 1 ||
                             Math.Abs(nol_pitch[i] - ol_pitch / 5.0) <= 1))
                        {
                            /*ol_pitch_coef=nol_pitch_coef[i];*/
                            ol_pitch = nol_pitch[i];
                        }
                    }

                    /*if (ol_pitch>50)
                     * ol_pitch/=2;*/
                    /*ol_pitch_coef = sqrt(ol_pitch_coef);*/
                }
                else
                {
                    ol_pitch      = 0;
                    ol_pitch_coef = 0;
                }
                /*Compute "real" excitation*/
                Filters.fir_mem2(frmBuf, frmIdx, interp_lpc, excBuf, excIdx, frameSize, lpcSize, mem_exc);

                /* Compute open-loop excitation gain */
                ol_gain = 0;
                for (i = 0; i < frameSize; i++)
                {
                    ol_gain += excBuf[excIdx + i] * excBuf[excIdx + i];
                }

                ol_gain = (float)Math.Sqrt(1 + ol_gain / frameSize);
            }

            /*VBR stuff*/
            if (vbr != null && (vbr_enabled != 0 || vad_enabled != 0))
            {
                if (abr_enabled != 0)
                {
                    float qual_change = 0;
                    if (abr_drift2 * abr_drift > 0)
                    {
                        /* Only adapt if long-term and short-term drift are the same sign */
                        qual_change = -.00001f * abr_drift / (1 + abr_count);
                        if (qual_change > .05f)
                        {
                            qual_change = .05f;
                        }
                        if (qual_change < -.05f)
                        {
                            qual_change = -.05f;
                        }
                    }
                    vbr_quality += qual_change;
                    if (vbr_quality > 10)
                    {
                        vbr_quality = 10;
                    }
                    if (vbr_quality < 0)
                    {
                        vbr_quality = 0;
                    }
                }
                relative_quality = vbr.analysis(vin, frameSize, ol_pitch, ol_pitch_coef);
                /*if (delta_qual<0)*/
                /*  delta_qual*=.1*(3+st->vbr_quality);*/
                if (vbr_enabled != 0)
                {
                    int   mode;
                    int   choice   = 0;
                    float min_diff = 100;
                    mode = 8;
                    while (mode > 0)
                    {
                        int   v1;
                        float thresh;
                        v1 = (int)Math.Floor(vbr_quality);
                        if (v1 == 10)
                        {
                            thresh = NSpeex.Vbr.nb_thresh[mode][v1];
                        }
                        else
                        {
                            thresh = (vbr_quality - v1) * NSpeex.Vbr.nb_thresh[mode][v1 + 1] +
                                     (1 + v1 - vbr_quality) * NSpeex.Vbr.nb_thresh[mode][v1];
                        }
                        if (relative_quality > thresh &&
                            relative_quality - thresh < min_diff)
                        {
                            choice   = mode;
                            min_diff = relative_quality - thresh;
                        }
                        mode--;
                    }
                    mode = choice;
                    if (mode == 0)
                    {
                        if (dtx_count == 0 || lsp_dist > .05 || dtx_enabled == 0 || dtx_count > 20)
                        {
                            mode      = 1;
                            dtx_count = 1;
                        }
                        else
                        {
                            mode = 0;
                            dtx_count++;
                        }
                    }
                    else
                    {
                        dtx_count = 0;
                    }


                    Mode = mode;

                    if (abr_enabled != 0)
                    {
                        int bitrate;
                        bitrate    = BitRate;
                        abr_drift += (bitrate - abr_enabled);
                        abr_drift2 = .95f * abr_drift2 + .05f * (bitrate - abr_enabled);
                        abr_count += 1.0f;
                    }
                }
                else
                {
                    /*VAD only case*/
                    int mode;
                    if (relative_quality < 2)
                    {
                        if (dtx_count == 0 || lsp_dist > .05 || dtx_enabled == 0 || dtx_count > 20)
                        {
                            dtx_count = 1;
                            mode      = 1;
                        }
                        else
                        {
                            mode = 0;
                            dtx_count++;
                        }
                    }
                    else
                    {
                        dtx_count = 0;
                        mode      = submodeSelect;
                    }
                    /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/
                    submodeID = mode;
                }
            }
            else
            {
                relative_quality = -1;
            }

            /* First, transmit a zero for narrowband */
            bits.Pack(0, 1);

            /* Transmit the sub-mode we use for this frame */
            bits.Pack(submodeID, NB_SUBMODE_BITS);

            /* If null mode (no transmission), just set a couple things to zero*/
            if (submodes[submodeID] == null)
            {
                for (i = 0; i < frameSize; i++)
                {
                    excBuf[excIdx + i] = exc2Buf[exc2Idx + i] = swBuf[swIdx + i] = VERY_SMALL;
                }

                for (i = 0; i < lpcSize; i++)
                {
                    mem_sw[i] = 0;
                }
                first         = 1;
                bounded_pitch = 1;

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

                vin[0] = frmBuf[frmIdx] + preemph * pre_mem2;
                for (i = 1; i < frameSize; i++)
                {
                    vin[i] = frmBuf[frmIdx = i] + preemph * vin[i - 1];
                }
                pre_mem2 = vin[frameSize - 1];

                return(0);
            }

            /* LSP Quantization */
            if (first != 0)
            {
                for (i = 0; i < lpcSize; i++)
                {
                    old_lsp[i] = lsp[i];
                }
            }

            /*Quantize LSPs*/
            //#if 1 /*0 for unquantized*/
            submodes[submodeID].lsqQuant.quant(lsp, qlsp, lpcSize, bits);
            //#else
            //     for (i=0;i<lpcSize;i++)
            //       qlsp[i]=lsp[i];
            //#endif

            /*If we use low bit-rate pitch mode, transmit open-loop pitch*/
            if (submodes[submodeID].lbr_pitch != -1)
            {
                bits.Pack(ol_pitch - min_pitch, 7);
            }

            if (submodes[submodeID].forced_pitch_gain != 0)
            {
                int quant;
                quant = (int)Math.Floor(.5 + 15 * ol_pitch_coef);
                if (quant > 15)
                {
                    quant = 15;
                }
                if (quant < 0)
                {
                    quant = 0;
                }
                bits.Pack(quant, 4);
                ol_pitch_coef = (float)0.066667 * quant;
            }

            /*Quantize and transmit open-loop excitation gain*/
            {
                int qe = (int)(Math.Floor(0.5 + 3.5 * Math.Log(ol_gain)));
                if (qe < 0)
                {
                    qe = 0;
                }
                if (qe > 31)
                {
                    qe = 31;
                }
                ol_gain = (float)Math.Exp(qe / 3.5);
                bits.Pack(qe, 5);
            }

            /* Special case for first frame */
            if (first != 0)
            {
                for (i = 0; i < lpcSize; i++)
                {
                    old_qlsp[i] = qlsp[i];
                }
            }

            /* Filter response */
            res = new float[subframeSize];
            /* Target signal */
            target   = new float[subframeSize];
            syn_resp = new float[subframeSize];
            mem      = new float[lpcSize];
            orig     = new float[frameSize];
            for (i = 0; i < frameSize; i++)
            {
                orig[i] = frmBuf[frmIdx + i];
            }

            /* Loop on sub-frames */
            for (int sub = 0; sub < nbSubframes; sub++)
            {
                float tmp;
                int   offset;
                int   sp, sw, exc, exc2;
                int   pitchval;

                /* Offset relative to start of frame */
                offset = subframeSize * sub;
                /* Original signal */
                sp = frmIdx + offset;
                /* Excitation */
                exc = excIdx + offset;
                /* Weighted signal */
                sw = swIdx + offset;

                exc2 = exc2Idx + offset;

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

                /* Make sure the filters are stable */
                Lsp.enforce_margin(interp_lsp, lpcSize, .002f);
                Lsp.enforce_margin(interp_qlsp, lpcSize, .002f);

                /* Compute interpolated LPCs (quantized and unquantized) */
                for (i = 0; i < lpcSize; i++)
                {
                    interp_lsp[i] = (float)Math.Cos(interp_lsp[i]);
                }
                m_lsp.lsp2lpc(interp_lsp, interp_lpc, lpcSize);

                for (i = 0; i < lpcSize; i++)
                {
                    interp_qlsp[i] = (float)Math.Cos(interp_qlsp[i]);
                }
                m_lsp.lsp2lpc(interp_qlsp, interp_qlpc, lpcSize);

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

                /* Compute bandwidth-expanded (unquantized) LPCs for perceptual weighting */
                Filters.bw_lpc(gamma1, interp_lpc, bw_lpc1, lpcSize);
                if (gamma2 >= 0)
                {
                    Filters.bw_lpc(gamma2, interp_lpc, bw_lpc2, lpcSize);
                }
                else
                {
                    bw_lpc2[0] = 1;
                    bw_lpc2[1] = -preemph;
                    for (i = 2; i <= lpcSize; i++)
                    {
                        bw_lpc2[i] = 0;
                    }
                }

                /* Compute impulse response of A(z/g1) / ( A(z)*A(z/g2) )*/
                for (i = 0; i < subframeSize; i++)
                {
                    excBuf[exc + i] = 0;
                }
                excBuf[exc] = 1;
                Filters.syn_percep_zero(excBuf, exc, interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, subframeSize, lpcSize);

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

                /* Compute zero response of A(z/g1) / ( A(z/g2) * A(z) ) */
                for (i = 0; i < lpcSize; i++)
                {
                    mem[i] = mem_sp[i];
                }
                Filters.iir_mem2(excBuf, exc, interp_qlpc, excBuf, exc, subframeSize, lpcSize, mem);

                for (i = 0; i < lpcSize; i++)
                {
                    mem[i] = mem_sw[i];
                }
                Filters.filter_mem2(excBuf, exc, bw_lpc1, bw_lpc2, res, 0, subframeSize, lpcSize, mem, 0);

                /* Compute weighted signal */
                for (i = 0; i < lpcSize; i++)
                {
                    mem[i] = mem_sw[i];
                }
                Filters.filter_mem2(frmBuf, sp, bw_lpc1, bw_lpc2, swBuf, sw, subframeSize, lpcSize, mem, 0);

                /* Compute target signal */
                for (i = 0; i < subframeSize; i++)
                {
                    target[i] = swBuf[sw + i] - res[i];
                }

                for (i = 0; i < subframeSize; i++)
                {
                    excBuf[exc + i] = exc2Buf[exc2 + i] = 0;
                }

                /* If we have a long-term predictor (otherwise, something's wrong) */
                //    if (submodes[submodeID].ltp.quant)
                //    {
                int pit_min, pit_max;
                /* Long-term prediction */
                if (submodes[submodeID].lbr_pitch != -1)
                {
                    /* Low bit-rate pitch handling */
                    int margin;
                    margin = submodes[submodeID].lbr_pitch;
                    if (margin != 0)
                    {
                        if (ol_pitch < min_pitch + margin - 1)
                        {
                            ol_pitch = min_pitch + margin - 1;
                        }
                        if (ol_pitch > max_pitch - margin)
                        {
                            ol_pitch = max_pitch - margin;
                        }
                        pit_min = ol_pitch - margin + 1;
                        pit_max = ol_pitch + margin;
                    }
                    else
                    {
                        pit_min = pit_max = ol_pitch;
                    }
                }
                else
                {
                    pit_min = min_pitch;
                    pit_max = max_pitch;
                }

                /* Force pitch to use only the current frame if needed */
                if (bounded_pitch != 0 && pit_max > offset)
                {
                    pit_max = offset;
                }

                /* Perform pitch search */
                pitchval = submodes[submodeID].ltp.Quant(target, swBuf, sw, interp_qlpc, bw_lpc1, bw_lpc2,
                                                         excBuf, exc, pit_min, pit_max, ol_pitch_coef, lpcSize,
                                                         subframeSize, bits, exc2Buf, exc2, syn_resp, complexity);

                pitch[sub] = pitchval;

                //    } else {
                //      speex_error ("No pitch prediction, what's wrong");
                //    }

                /* Update target for adaptive codebook contribution */
                Filters.syn_percep_zero(excBuf, exc, interp_qlpc, bw_lpc1, bw_lpc2, res, subframeSize, lpcSize);
                for (i = 0; i < subframeSize; i++)
                {
                    target[i] -= res[i];
                }

                /* Quantization of innovation */
                {
                    int   innovptr;
                    float ener = 0, ener_1;

                    innovptr = sub * subframeSize;
                    for (i = 0; i < subframeSize; i++)
                    {
                        innov[innovptr + i] = 0;
                    }

                    Filters.residue_percep_zero(target, 0, interp_qlpc, bw_lpc1, bw_lpc2, buf2, subframeSize, lpcSize);
                    for (i = 0; i < subframeSize; i++)
                    {
                        ener += buf2[i] * buf2[i];
                    }
                    ener = (float)Math.Sqrt(.1f + ener / subframeSize);

                    /*for (i=0;i<subframeSize;i++)
                     * System.out.print(buf2[i]/ener + "\t");
                     */

                    ener /= ol_gain;

                    /* Calculate gain correction for the sub-frame (if any) */
                    if (submodes[submodeID].have_subframe_gain != 0)
                    {
                        int qe;
                        ener = (float)Math.Log(ener);
                        if (submodes[submodeID].have_subframe_gain == 3)
                        {
                            qe = VQ.index(ener, exc_gain_quant_scal3, 8);
                            bits.Pack(qe, 3);
                            ener = exc_gain_quant_scal3[qe];
                        }
                        else
                        {
                            qe = VQ.index(ener, exc_gain_quant_scal1, 2);
                            bits.Pack(qe, 1);
                            ener = exc_gain_quant_scal1[qe];
                        }
                        ener = (float)Math.Exp(ener);
                    }
                    else
                    {
                        ener = 1;
                    }

                    ener *= ol_gain;

                    /*System.out.println(ener + " " + ol_gain);*/

                    ener_1 = 1 / ener;

                    /* Normalize innovation */
                    for (i = 0; i < subframeSize; i++)
                    {
                        target[i] *= ener_1;
                    }

                    /* Quantize innovation */
                    //      if (submodes[submodeID].innovation != null)
                    //      {
                    /* Codebook search */
                    submodes[submodeID].innovation.Quant(target, interp_qlpc, bw_lpc1, bw_lpc2,
                                                         lpcSize, subframeSize, innov,
                                                         innovptr, syn_resp, bits, complexity);

                    /* De-normalize innovation and update excitation */
                    for (i = 0; i < subframeSize; i++)
                    {
                        innov[innovptr + i] *= ener;
                    }
                    for (i = 0; i < subframeSize; i++)
                    {
                        excBuf[exc + i] += innov[innovptr + i];
                    }
                    //      } else {
                    //        speex_error("No fixed codebook");
                    //      }

                    /* In some (rare) modes, we do a second search (more bits) to reduce noise even more */
                    if (submodes[submodeID].double_codebook != 0)
                    {
                        float[] innov2 = new float[subframeSize];
                        //          for (i=0;i<subframeSize;i++)
                        //            innov2[i]=0;
                        for (i = 0; i < subframeSize; i++)
                        {
                            target[i] *= 2.2f;
                        }
                        submodes[submodeID].innovation.Quant(target, interp_qlpc, bw_lpc1, bw_lpc2,
                                                             lpcSize, subframeSize, innov2, 0,
                                                             syn_resp, bits, complexity);
                        for (i = 0; i < subframeSize; i++)
                        {
                            innov2[i] *= ener * (1f / 2.2f);
                        }
                        for (i = 0; i < subframeSize; i++)
                        {
                            excBuf[exc + i] += innov2[i];
                        }
                    }

                    for (i = 0; i < subframeSize; i++)
                    {
                        target[i] *= ener;
                    }
                }

                /*Keep the previous memory*/
                for (i = 0; i < lpcSize; i++)
                {
                    mem[i] = mem_sp[i];
                }
                /* Final signal synthesis from excitation */
                Filters.iir_mem2(excBuf, exc, interp_qlpc, frmBuf, sp, subframeSize, lpcSize, mem_sp);

                /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */
                Filters.filter_mem2(frmBuf, sp, bw_lpc1, bw_lpc2, swBuf, sw, subframeSize, lpcSize, mem_sw, 0);
                for (i = 0; i < subframeSize; i++)
                {
                    exc2Buf[exc2 + i] = excBuf[exc + i];
                }
            }

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

            if (submodeID == 1)
            {
                if (dtx_count != 0)
                {
                    bits.Pack(15, 4);
                }
                else
                {
                    bits.Pack(0, 4);
                }
            }

            /* The next frame will not be the first (Duh!) */
            first = 0;

            {
                float ener = 0, err = 0;
                float snr;
                for (i = 0; i < frameSize; i++)
                {
                    ener += frmBuf[frmIdx + i] * frmBuf[frmIdx + i];
                    err  += (frmBuf[frmIdx + i] - orig[i]) * (frmBuf[frmIdx + i] - orig[i]);
                }
                snr = (float)(10 * Math.Log((ener + 1) / (err + 1)));
                /*System.out.println("Frame result: SNR="+snr+" E="+ener+" Err="+err+"\r\n");*/
            }

            /* Replace input by synthesized speech */
            vin[0] = frmBuf[frmIdx] + preemph * pre_mem2;
            for (i = 1; i < frameSize; i++)
            {
                vin[i] = frmBuf[frmIdx + i] + preemph * vin[i - 1];
            }
            pre_mem2 = vin[frameSize - 1];

            if (submodes[submodeID].innovation is NoiseSearch || submodeID == 0)
            {
                bounded_pitch = 1;
            }
            else
            {
                bounded_pitch = 0;
            }

            return(1);
        }
示例#4
0
        /// <summary>
        /// Decode the given input bits.
        /// </summary>
        /// <param name="bits">Speex bits buffer.</param>
        /// <param name="vout">the decoded mono audio frame.</param>
        /// <returns>1 if a terminator was found, 0 if not.</returns>
        public int Decode(Bits bits, float[] vout)
        {
            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 == null)
                {
                    decodeLost(vout);
                    return(0);
                }
                do
                {
                    if (bits.UnPack(1) != 0)
                    {
                        m = bits.UnPack(SbCodec.SB_SUBMODE_BITS);
                        int advance = SbCodec.SB_FRAME_SIZE[m];
                        if (advance < 0)
                        {
                            throw new Exception("Invalid sideband mode encountered (1st sideband): " + m);
                        }
                        advance -= (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(SbCodec.SB_SUBMODE_BITS);
                            advance = SbCodec.SB_FRAME_SIZE[m];
                            if (advance < 0)
                            {
                                throw new Exception("Invalid sideband mode encountered. (2nd sideband): " + m);
                                //return -2;
                            }
                            advance -= (SbCodec.SB_SUBMODE_BITS + 1);
                            bits.Advance(advance);
                            if (bits.UnPack(1) != 0)
                            { /* Sanity check */
                                throw new Exception("More than two sideband layers found");
                                //return -2;
                            }
                        }
                    }

                    m = bits.UnPack(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 Exception("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 (submodes[submodeID] == null)
            {
                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] = 3 * innov_gain * ((float)random.NextDouble() - .5f);
                }
                first = 1;
                /* Final signal synthesis from excitation */
                Filters.iir_mem2(excBuf, excIdx, lpc, frmBuf, frmIdx, frameSize, lpcSize, mem_sp);
                vout[0] = frmBuf[frmIdx] + preemph * pre_mem;
                for (i = 1; i < frameSize; i++)
                {
                    vout[i] = frmBuf[frmIdx + i] + preemph * vout[i - 1];
                }
                pre_mem    = vout[frameSize - 1];
                count_lost = 0;
                return(0);
            }
            /* Unquantize LSPs */
            submodes[submodeID].lsqQuant.unquant(qlsp, lpcSize, bits);
            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)(.6 * Math.Exp(-.2 * 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].lbr_pitch != -1)
            {
                ol_pitch = min_pitch + bits.UnPack(7);
            }

            if (submodes[submodeID].forced_pitch_gain != 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.5);

            /* 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 */
                Lsp.enforce_margin(interp_qlsp, lpcSize, .002f);

                /* Compute interpolated LPCs (unquantized) */
                for (i = 0; i < lpcSize; i++)
                {
                    interp_qlsp[i] = (float)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].lpc_enh_k1;
                    k2 = submodes[submodeID].lpc_enh_k2;
                    k3 = (1 - (1 - r * k1) / (1 - r * k2)) / r;
                    Filters.bw_lpc(k1, interp_qlpc, awk1, lpcSize);
                    Filters.bw_lpc(k2, interp_qlpc, awk2, lpcSize);
                    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].lbr_pitch != -1)
                {
                    int margin = submodes[submodeID].lbr_pitch;
                    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 = ol_gain / (last_ol_gain + 1);
                    for (i = 0; i < subframeSize; i++)
                    {
                        excBuf[excIdx + i] *= fact;
                    }
                }
                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].have_subframe_gain == 3)
                {
                    q_energy = bits.UnPack(3);
                    ener     = (float)(ol_gain * Math.Exp(exc_gain_quant_scal3[q_energy]));
                }
                else if (submodes[submodeID].have_subframe_gain == 1)
                {
                    q_energy = bits.UnPack(1);
                    ener     = (float)(ol_gain * Math.Exp(exc_gain_quant_scal1[q_energy]));
                }
                else
                {
                    ener = ol_gain;
                }
                if (submodes[submodeID].innovation != null)
                {
                    /* Fixed codebook contribution */
                    submodes[submodeID].innovation.UnQuant(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].double_codebook != 0)
                {
                    for (i = 0; i < subframeSize; i++)
                    {
                        innov2[i] = 0;
                    }
                    submodes[submodeID].innovation.UnQuant(innov2, 0, subframeSize, bits);
                    for (i = 0; i < subframeSize; i++)
                    {
                        innov2[i] *= ener * (1f / 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].comb_gain > 0)
                {
                    filters.comb_filter(excBuf, extIdx, frmBuf, spIdx, subframeSize,
                                        pitch, pitch_gain, submodes[submodeID].comb_gain);
                }
                if (enhanced)
                {
                    /* Use enhanced LPC filter */
                    Filters.filter_mem2(frmBuf, spIdx, awk2, awk1, subframeSize, lpcSize, mem_sp, lpcSize);
                    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;
                    }
                    Filters.iir_mem2(frmBuf, spIdx, interp_qlpc, frmBuf, spIdx, subframeSize, lpcSize, mem_sp);
                }
            }
            /*Copy output signal*/
            vout[0] = frmBuf[frmIdx] + preemph * pre_mem;
            for (i = 1; i < frameSize; i++)
            {
                vout[i] = frmBuf[frmIdx + i] + preemph * vout[i - 1];
            }
            pre_mem = vout[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);
        }