示例#1
0
        /* Finds LPC vector from correlations, and converts to NLSF */
        internal static void silk_find_LPC(
            SilkChannelEncoder psEncC,                  /* I/O  Encoder state                                                               */
            short[] NLSF_Q15,                           /* O    NLSFs                                                                       */
            short[] x,                                  /* I    Input signal                                                                */
            int minInvGain_Q30                          /* I    Inverse of max prediction gain                                              */
            )
        {
            int k, subfr_length;

            int[]         a_Q16 = new int[SilkConstants.MAX_LPC_ORDER];
            int           isInterpLower, shift;
            int           res_nrg0, res_nrg1;
            int           rshift0, rshift1;
            BoxedValueInt scratch_box1 = new BoxedValueInt();
            BoxedValueInt scratch_box2 = new BoxedValueInt();

            /* Used only for LSF interpolation */
            int[] a_tmp_Q16 = new int[SilkConstants.MAX_LPC_ORDER];
            int   res_nrg_interp, res_nrg, res_tmp_nrg;
            int   res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q;

            short[] a_tmp_Q12 = new short[SilkConstants.MAX_LPC_ORDER];
            short[] NLSF0_Q15 = new short[SilkConstants.MAX_LPC_ORDER];

            subfr_length = psEncC.subfr_length + psEncC.predictLPCOrder;

            /* Default: no interpolation */
            psEncC.indices.NLSFInterpCoef_Q2 = 4;

            /* Burg AR analysis for the full frame */
            BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_Q16, x, 0, minInvGain_Q30, subfr_length, psEncC.nb_subfr, psEncC.predictLPCOrder);
            res_nrg   = scratch_box1.Val;
            res_nrg_Q = scratch_box2.Val;

            if (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR)
            {
                short[] LPC_res;

                /* Optimal solution for last 10 ms */
                BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_tmp_Q16, x, (2 * subfr_length), minInvGain_Q30, subfr_length, 2, psEncC.predictLPCOrder);
                res_tmp_nrg   = scratch_box1.Val;
                res_tmp_nrg_Q = scratch_box2.Val;

                /* subtract residual energy here, as that's easier than adding it to the    */
                /* residual energy of the first 10 ms in each iteration of the search below */
                shift = res_tmp_nrg_Q - res_nrg_Q;
                if (shift >= 0)
                {
                    if (shift < 32)
                    {
                        res_nrg = res_nrg - Inlines.silk_RSHIFT(res_tmp_nrg, shift);
                    }
                }
                else
                {
                    Inlines.OpusAssert(shift > -32);
                    res_nrg   = Inlines.silk_RSHIFT(res_nrg, -shift) - res_tmp_nrg;
                    res_nrg_Q = res_tmp_nrg_Q;
                }

                /* Convert to NLSFs */
                NLSF.silk_A2NLSF(NLSF_Q15, a_tmp_Q16, psEncC.predictLPCOrder);

                LPC_res = new short[2 * subfr_length];

                /* Search over interpolation indices to find the one with lowest residual energy */
                for (k = 3; k >= 0; k--)
                {
                    /* Interpolate NLSFs for first half */
                    Inlines.silk_interpolate(NLSF0_Q15, psEncC.prev_NLSFq_Q15, NLSF_Q15, k, psEncC.predictLPCOrder);

                    /* Convert to LPC for residual energy evaluation */
                    NLSF.silk_NLSF2A(a_tmp_Q12, NLSF0_Q15, psEncC.predictLPCOrder);

                    /* Calculate residual energy with NLSF interpolation */
                    Filters.silk_LPC_analysis_filter(LPC_res, 0, x, 0, a_tmp_Q12, 0, 2 * subfr_length, psEncC.predictLPCOrder);

                    SumSqrShift.silk_sum_sqr_shift(out res_nrg0, out rshift0, LPC_res, psEncC.predictLPCOrder, subfr_length - psEncC.predictLPCOrder);

                    SumSqrShift.silk_sum_sqr_shift(out res_nrg1, out rshift1, LPC_res, psEncC.predictLPCOrder + subfr_length, subfr_length - psEncC.predictLPCOrder);

                    /* Add subframe energies from first half frame */
                    shift = rshift0 - rshift1;
                    if (shift >= 0)
                    {
                        res_nrg1         = Inlines.silk_RSHIFT(res_nrg1, shift);
                        res_nrg_interp_Q = -rshift0;
                    }
                    else
                    {
                        res_nrg0         = Inlines.silk_RSHIFT(res_nrg0, -shift);
                        res_nrg_interp_Q = -rshift1;
                    }
                    res_nrg_interp = Inlines.silk_ADD32(res_nrg0, res_nrg1);

                    /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */
                    shift = res_nrg_interp_Q - res_nrg_Q;
                    if (shift >= 0)
                    {
                        if (Inlines.silk_RSHIFT(res_nrg_interp, shift) < res_nrg)
                        {
                            isInterpLower = (true ? 1 : 0);
                        }
                        else
                        {
                            isInterpLower = (false ? 1 : 0);
                        }
                    }
                    else
                    {
                        if (-shift < 32)
                        {
                            if (res_nrg_interp < Inlines.silk_RSHIFT(res_nrg, -shift))
                            {
                                isInterpLower = (true ? 1 : 0);
                            }
                            else
                            {
                                isInterpLower = (false ? 1 : 0);
                            }
                        }
                        else
                        {
                            isInterpLower = (false ? 1 : 0);
                        }
                    }

                    /* Determine whether current interpolated NLSFs are best so far */
                    if (isInterpLower == (true ? 1 : 0))
                    {
                        /* Interpolation has lower residual energy */
                        res_nrg   = res_nrg_interp;
                        res_nrg_Q = res_nrg_interp_Q;
                        psEncC.indices.NLSFInterpCoef_Q2 = (sbyte)k;
                    }
                }
            }

            if (psEncC.indices.NLSFInterpCoef_Q2 == 4)
            {
                /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
                NLSF.silk_A2NLSF(NLSF_Q15, a_Q16, psEncC.predictLPCOrder);
            }

            Inlines.OpusAssert(psEncC.indices.NLSFInterpCoef_Q2 == 4 || (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR));
        }
示例#2
0
        /// <summary>
        /// Updates CNG estimate, and applies the CNG when packet was lost
        /// </summary>
        /// <param name="psDec">I/O  Decoder state</param>
        /// <param name="psDecCtrl">I/O  Decoder control</param>
        /// <param name="frame">I/O  Signal</param>
        /// <param name="length">I    Length of residual</param>
        internal static void silk_CNG(
            SilkChannelDecoder psDec,
            SilkDecoderControl psDecCtrl,
            short[] frame,
            int frame_ptr,
            int length)
        {
            int i, subfr;
            int sum_Q6, max_Gain_Q16, gain_Q16;

            short[]  A_Q12 = new short[psDec.LPC_order];
            CNGState psCNG = psDec.sCNG;

            if (psDec.fs_kHz != psCNG.fs_kHz)
            {
                /* Reset state */
                silk_CNG_Reset(psDec);

                psCNG.fs_kHz = psDec.fs_kHz;
            }

            if (psDec.lossCnt == 0 && psDec.prevSignalType == SilkConstants.TYPE_NO_VOICE_ACTIVITY)
            {
                /* Update CNG parameters */

                /* Smoothing of LSF's  */
                for (i = 0; i < psDec.LPC_order; i++)
                {
                    psCNG.CNG_smth_NLSF_Q15[i] += (short)(Inlines.silk_SMULWB((int)psDec.prevNLSF_Q15[i] - (int)psCNG.CNG_smth_NLSF_Q15[i], SilkConstants.CNG_NLSF_SMTH_Q16));
                }

                /* Find the subframe with the highest gain */
                max_Gain_Q16 = 0;
                subfr        = 0;
                for (i = 0; i < psDec.nb_subfr; i++)
                {
                    if (psDecCtrl.Gains_Q16[i] > max_Gain_Q16)
                    {
                        max_Gain_Q16 = psDecCtrl.Gains_Q16[i];
                        subfr        = i;
                    }
                }

                /* Update CNG excitation buffer with excitation from this subframe */
                Arrays.MemMoveInt(psCNG.CNG_exc_buf_Q14, 0, psDec.subfr_length, (psDec.nb_subfr - 1) * psDec.subfr_length);

                /* Smooth gains */
                for (i = 0; i < psDec.nb_subfr; i++)
                {
                    psCNG.CNG_smth_Gain_Q16 += Inlines.silk_SMULWB(psDecCtrl.Gains_Q16[i] - psCNG.CNG_smth_Gain_Q16, SilkConstants.CNG_GAIN_SMTH_Q16);
                }
            }

            /* Add CNG when packet is lost or during DTX */
            if (psDec.lossCnt != 0)
            {
                int[] CNG_sig_Q10 = new int[length + SilkConstants.MAX_LPC_ORDER];

                /* Generate CNG excitation */
                gain_Q16 = Inlines.silk_SMULWW(psDec.sPLC.randScale_Q14, psDec.sPLC.prevGain_Q16[1]);
                if (gain_Q16 >= (1 << 21) || psCNG.CNG_smth_Gain_Q16 > (1 << 23))
                {
                    gain_Q16 = Inlines.silk_SMULTT(gain_Q16, gain_Q16);
                    gain_Q16 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULTT(psCNG.CNG_smth_Gain_Q16, psCNG.CNG_smth_Gain_Q16), gain_Q16, 5);
                    gain_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(gain_Q16), 16);
                }
                else
                {
                    gain_Q16 = Inlines.silk_SMULWW(gain_Q16, gain_Q16);
                    gain_Q16 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULWW(psCNG.CNG_smth_Gain_Q16, psCNG.CNG_smth_Gain_Q16), gain_Q16, 5);
                    gain_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(gain_Q16), 8);
                }
                silk_CNG_exc(CNG_sig_Q10, SilkConstants.MAX_LPC_ORDER, psCNG.CNG_exc_buf_Q14, gain_Q16, length, ref psCNG.rand_seed);

                /* Convert CNG NLSF to filter representation */
                NLSF.silk_NLSF2A(A_Q12, psCNG.CNG_smth_NLSF_Q15, psDec.LPC_order);

                /* Generate CNG signal, by synthesis filtering */
                Array.Copy(psCNG.CNG_synth_state, CNG_sig_Q10, SilkConstants.MAX_LPC_ORDER);

                for (i = 0; i < length; i++)
                {
                    int lpci = SilkConstants.MAX_LPC_ORDER + i;
                    Inlines.OpusAssert(psDec.LPC_order == 10 || psDec.LPC_order == 16);
                    /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
                    sum_Q6 = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 1], A_Q12[0]);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 2], A_Q12[1]);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 3], A_Q12[2]);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 4], A_Q12[3]);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 5], A_Q12[4]);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 6], A_Q12[5]);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 7], A_Q12[6]);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 8], A_Q12[7]);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 9], A_Q12[8]);
                    sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 10], A_Q12[9]);

                    if (psDec.LPC_order == 16)
                    {
                        sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 11], A_Q12[10]);
                        sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 12], A_Q12[11]);
                        sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 13], A_Q12[12]);
                        sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 14], A_Q12[13]);
                        sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 15], A_Q12[14]);
                        sum_Q6 = Inlines.silk_SMLAWB(sum_Q6, CNG_sig_Q10[lpci - 16], A_Q12[15]);
                    }

                    /* Update states */
                    CNG_sig_Q10[lpci] = Inlines.silk_ADD_LSHIFT(CNG_sig_Q10[lpci], sum_Q6, 4);

                    frame[frame_ptr + i] = Inlines.silk_ADD_SAT16(frame[frame_ptr + i], (short)(Inlines.silk_RSHIFT_ROUND(CNG_sig_Q10[lpci], 10)));
                }

                Array.Copy(CNG_sig_Q10, length, psCNG.CNG_synth_state, 0, SilkConstants.MAX_LPC_ORDER);
            }
            else
            {
                Arrays.MemSetInt(psCNG.CNG_synth_state, 0, psDec.LPC_order);
            }
        }
示例#3
0
        /* Decode parameters from payload */
        internal static void silk_decode_parameters(
            SilkChannelDecoder psDec,           /* I/O  State                                       */
            SilkDecoderControl psDecCtrl,       /* I/O  Decoder control                             */
            int condCoding                      /* I    The type of conditional coding to use       */
            )
        {
            int i, k, Ix;

            short[]   pNLSF_Q15  = new short[psDec.LPC_order];
            short[]   pNLSF0_Q15 = new short[psDec.LPC_order];
            sbyte[][] cbk_ptr_Q7;

            /* Dequant Gains */
            BoxedValueSbyte boxedLastGainIndex = new BoxedValueSbyte(psDec.LastGainIndex);

            GainQuantization.silk_gains_dequant(psDecCtrl.Gains_Q16, psDec.indices.GainsIndices,
                                                boxedLastGainIndex, condCoding == SilkConstants.CODE_CONDITIONALLY ? 1 : 0, psDec.nb_subfr);
            psDec.LastGainIndex = boxedLastGainIndex.Val;

            /****************/
            /* Decode NLSFs */
            /****************/
            NLSF.silk_NLSF_decode(pNLSF_Q15, psDec.indices.NLSFIndices, psDec.psNLSF_CB);

            /* Convert NLSF parameters to AR prediction filter coefficients */
            NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[1], pNLSF_Q15, psDec.LPC_order);

            /* If just reset, e.g., because internal Fs changed, do not allow interpolation */
            /* improves the case of packet loss in the first frame after a switch           */
            if (psDec.first_frame_after_reset == 1)
            {
                psDec.indices.NLSFInterpCoef_Q2 = 4;
            }

            if (psDec.indices.NLSFInterpCoef_Q2 < 4)
            {
                /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */
                /* the previous NLSF1, and the current NLSF1                                   */
                for (i = 0; i < psDec.LPC_order; i++)
                {
                    pNLSF0_Q15[i] = (short)(psDec.prevNLSF_Q15[i] + Inlines.silk_RSHIFT(Inlines.silk_MUL(psDec.indices.NLSFInterpCoef_Q2,
                                                                                                         pNLSF_Q15[i] - psDec.prevNLSF_Q15[i]), 2));
                }

                /* Convert NLSF parameters to AR prediction filter coefficients */
                NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[0], pNLSF0_Q15, psDec.LPC_order);
            }
            else
            {
                /* Copy LPC coefficients for first half from second half */
                Array.Copy(psDecCtrl.PredCoef_Q12[1], psDecCtrl.PredCoef_Q12[0], psDec.LPC_order);
            }

            Array.Copy(pNLSF_Q15, psDec.prevNLSF_Q15, psDec.LPC_order);

            /* After a packet loss do BWE of LPC coefs */
            if (psDec.lossCnt != 0)
            {
                BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[0], psDec.LPC_order, SilkConstants.BWE_AFTER_LOSS_Q16);
                BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[1], psDec.LPC_order, SilkConstants.BWE_AFTER_LOSS_Q16);
            }

            if (psDec.indices.signalType == SilkConstants.TYPE_VOICED)
            {
                /*********************/
                /* Decode pitch lags */
                /*********************/

                /* Decode pitch values */
                DecodePitch.silk_decode_pitch(psDec.indices.lagIndex, psDec.indices.contourIndex, psDecCtrl.pitchL, psDec.fs_kHz, psDec.nb_subfr);

                /* Decode Codebook Index */
                cbk_ptr_Q7 = Tables.silk_LTP_vq_ptrs_Q7[psDec.indices.PERIndex]; /* set pointer to start of codebook */

                for (k = 0; k < psDec.nb_subfr; k++)
                {
                    Ix = psDec.indices.LTPIndex[k];
                    for (i = 0; i < SilkConstants.LTP_ORDER; i++)
                    {
                        psDecCtrl.LTPCoef_Q14[k * SilkConstants.LTP_ORDER + i] = (short)(Inlines.silk_LSHIFT(cbk_ptr_Q7[Ix][i], 7));
                    }
                }

                /**********************/
                /* Decode LTP scaling */
                /**********************/
                Ix = psDec.indices.LTP_scaleIndex;
                psDecCtrl.LTP_scale_Q14 = Tables.silk_LTPScales_table_Q14[Ix];
            }
            else
            {
                Arrays.MemSetInt(psDecCtrl.pitchL, 0, psDec.nb_subfr);
                Arrays.MemSetShort(psDecCtrl.LTPCoef_Q14, 0, SilkConstants.LTP_ORDER * psDec.nb_subfr);
                psDec.indices.PERIndex  = 0;
                psDecCtrl.LTP_scale_Q14 = 0;
            }
        }