Exemplo n.º 1
0
        internal static void silk_PLC(
            SilkChannelDecoder psDec,     /* I/O Decoder state        */
            SilkDecoderControl psDecCtrl, /* I/O Decoder control      */
            short[] frame,                /* I/O  signal              */
            int frame_ptr,
            int lost                      /* I Loss flag              */
            )
        {
            /* PLC control function */
            if (psDec.fs_kHz != psDec.sPLC.fs_kHz)
            {
                silk_PLC_Reset(psDec);
                psDec.sPLC.fs_kHz = psDec.fs_kHz;
            }

            if (lost != 0)
            {
                /****************************/
                /* Generate Signal          */
                /****************************/
                silk_PLC_conceal(psDec, psDecCtrl, frame, frame_ptr);

                psDec.lossCnt++;
            }
            else
            {
                /****************************/
                /* Update state             */
                /****************************/
                silk_PLC_update(psDec, psDecCtrl);
            }
        }
Exemplo n.º 2
0
        /**********************************************************/
        /* Core decoder. Performs inverse NSQ operation LTP + LPC */
        /**********************************************************/
        internal static void silk_decode_core(
            SilkChannelDecoder psDec,     /* I/O  Decoder state                               */
            SilkDecoderControl psDecCtrl, /* I    Decoder control                             */
            short[] xq,                   /* O    Decoded speech                              */
            int xq_ptr,
            short[] pulses                /* I    Pulse signal [MAX_FRAME_LENGTH]                               */
            )
        {
            int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType;

            short[] A_Q12;
            short[] B_Q14 = psDecCtrl.LTPCoef_Q14;
            int     B_Q14_ptr;
            int     pxq;

            short[] sLTP;
            int[]   sLTP_Q15;
            int     LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10;
            int     pred_lag_ptr;
            int     pexc_Q14;

            int[] pres_Q14;
            int   pres_Q14_ptr;

            int[] res_Q14;
            int[] sLPC_Q14;

            Inlines.OpusAssert(psDec.prev_gain_Q16 != 0);

            sLTP     = new short[psDec.ltp_mem_length];
            sLTP_Q15 = new int[psDec.ltp_mem_length + psDec.frame_length];
            res_Q14  = new int[psDec.subfr_length];
            sLPC_Q14 = new int[psDec.subfr_length + SilkConstants.MAX_LPC_ORDER];

            offset_Q10 = Tables.silk_Quantization_Offsets_Q10[psDec.indices.signalType >> 1][psDec.indices.quantOffsetType];

            if (psDec.indices.NLSFInterpCoef_Q2 < 1 << 2)
            {
                NLSF_interpolation_flag = 1;
            }
            else
            {
                NLSF_interpolation_flag = 0;
            }

            /* Decode excitation */
            rand_seed = psDec.indices.Seed;
            for (i = 0; i < psDec.frame_length; i++)
            {
                rand_seed        = Inlines.silk_RAND(rand_seed);
                psDec.exc_Q14[i] = Inlines.silk_LSHIFT((int)pulses[i], 14);
                if (psDec.exc_Q14[i] > 0)
                {
                    psDec.exc_Q14[i] -= SilkConstants.QUANT_LEVEL_ADJUST_Q10 << 4;
                }
                else
                if (psDec.exc_Q14[i] < 0)
                {
                    psDec.exc_Q14[i] += SilkConstants.QUANT_LEVEL_ADJUST_Q10 << 4;
                }
                psDec.exc_Q14[i] += offset_Q10 << 4;
                if (rand_seed < 0)
                {
                    psDec.exc_Q14[i] = -psDec.exc_Q14[i];
                }

                rand_seed = Inlines.silk_ADD32_ovflw(rand_seed, pulses[i]);
            }

            /* Copy LPC state */
            Array.Copy(psDec.sLPC_Q14_buf, sLPC_Q14, SilkConstants.MAX_LPC_ORDER);

            pexc_Q14     = 0;
            pxq          = xq_ptr;
            sLTP_buf_idx = psDec.ltp_mem_length;
            /* Loop over subframes */
            for (k = 0; k < psDec.nb_subfr; k++)
            {
                pres_Q14     = res_Q14;
                pres_Q14_ptr = 0;
                A_Q12        = psDecCtrl.PredCoef_Q12[k >> 1];
                B_Q14_ptr    = k * SilkConstants.LTP_ORDER;
                signalType   = psDec.indices.signalType;

                Gain_Q10     = Inlines.silk_RSHIFT(psDecCtrl.Gains_Q16[k], 6);
                inv_gain_Q31 = Inlines.silk_INVERSE32_varQ(psDecCtrl.Gains_Q16[k], 47);

                /* Calculate gain adjustment factor */
                if (psDecCtrl.Gains_Q16[k] != psDec.prev_gain_Q16)
                {
                    gain_adj_Q16 = Inlines.silk_DIV32_varQ(psDec.prev_gain_Q16, psDecCtrl.Gains_Q16[k], 16);

                    /* Scale short term state */
                    for (i = 0; i < SilkConstants.MAX_LPC_ORDER; i++)
                    {
                        sLPC_Q14[i] = Inlines.silk_SMULWW(gain_adj_Q16, sLPC_Q14[i]);
                    }
                }
                else
                {
                    gain_adj_Q16 = (int)1 << 16;
                }

                /* Save inv_gain */
                Inlines.OpusAssert(inv_gain_Q31 != 0);
                psDec.prev_gain_Q16 = psDecCtrl.Gains_Q16[k];

                /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */
                if (psDec.lossCnt != 0 && psDec.prevSignalType == SilkConstants.TYPE_VOICED &&
                    psDec.indices.signalType != SilkConstants.TYPE_VOICED && k < SilkConstants.MAX_NB_SUBFR / 2)
                {
                    Arrays.MemSetWithOffset <short>(B_Q14, 0, B_Q14_ptr, SilkConstants.LTP_ORDER);
                    B_Q14[B_Q14_ptr + (SilkConstants.LTP_ORDER / 2)] = (short)(((int)((0.25f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(0.25f, 14)*/);

                    signalType          = SilkConstants.TYPE_VOICED;
                    psDecCtrl.pitchL[k] = psDec.lagPrev;
                }

                if (signalType == SilkConstants.TYPE_VOICED)
                {
                    /* Voiced */
                    lag = psDecCtrl.pitchL[k];

                    /* Re-whitening */
                    if (k == 0 || (k == 2 && (NLSF_interpolation_flag != 0)))
                    {
                        /* Rewhiten with new A coefs */
                        start_idx = psDec.ltp_mem_length - lag - psDec.LPC_order - SilkConstants.LTP_ORDER / 2;
                        Inlines.OpusAssert(start_idx > 0);

                        if (k == 2)
                        {
                            Array.Copy(xq, xq_ptr, psDec.outBuf, psDec.ltp_mem_length, 2 * psDec.subfr_length);
                        }

                        Filters.silk_LPC_analysis_filter(sLTP, start_idx, psDec.outBuf, (start_idx + k * psDec.subfr_length),
                                                         A_Q12, 0, psDec.ltp_mem_length - start_idx, psDec.LPC_order);

                        /* After rewhitening the LTP state is unscaled */
                        if (k == 0)
                        {
                            /* Do LTP downscaling to reduce inter-packet dependency */
                            inv_gain_Q31 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(inv_gain_Q31, psDecCtrl.LTP_scale_Q14), 2);
                        }
                        for (i = 0; i < lag + SilkConstants.LTP_ORDER / 2; i++)
                        {
                            sLTP_Q15[sLTP_buf_idx - i - 1] = Inlines.silk_SMULWB(inv_gain_Q31, sLTP[psDec.ltp_mem_length - i - 1]);
                        }
                    }
                    else
                    {
                        /* Update LTP state when Gain changes */
                        if (gain_adj_Q16 != (int)1 << 16)
                        {
                            for (i = 0; i < lag + SilkConstants.LTP_ORDER / 2; i++)
                            {
                                sLTP_Q15[sLTP_buf_idx - i - 1] = Inlines.silk_SMULWW(gain_adj_Q16, sLTP_Q15[sLTP_buf_idx - i - 1]);
                            }
                        }
                    }
                }

                /* Long-term prediction */
                if (signalType == SilkConstants.TYPE_VOICED)
                {
                    /* Set up pointer */
                    pred_lag_ptr = sLTP_buf_idx - lag + SilkConstants.LTP_ORDER / 2;
                    for (i = 0; i < psDec.subfr_length; i++)
                    {
                        /* Unrolled loop */
                        /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
                        LTP_pred_Q13  = 2;
                        LTP_pred_Q13  = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr], B_Q14[B_Q14_ptr]);
                        LTP_pred_Q13  = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 1], B_Q14[B_Q14_ptr + 1]);
                        LTP_pred_Q13  = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 2], B_Q14[B_Q14_ptr + 2]);
                        LTP_pred_Q13  = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 3], B_Q14[B_Q14_ptr + 3]);
                        LTP_pred_Q13  = Inlines.silk_SMLAWB(LTP_pred_Q13, sLTP_Q15[pred_lag_ptr - 4], B_Q14[B_Q14_ptr + 4]);
                        pred_lag_ptr += 1;

                        /* Generate LPC excitation */
                        pres_Q14[pres_Q14_ptr + i] = Inlines.silk_ADD_LSHIFT32(psDec.exc_Q14[pexc_Q14 + i], LTP_pred_Q13, 1);

                        /* Update states */
                        sLTP_Q15[sLTP_buf_idx] = Inlines.silk_LSHIFT(pres_Q14[pres_Q14_ptr + i], 1);
                        sLTP_buf_idx++;
                    }
                }
                else
                {
                    pres_Q14     = psDec.exc_Q14;
                    pres_Q14_ptr = pexc_Q14;
                }

                for (i = 0; i < psDec.subfr_length; i++)
                {
                    /* Short-term prediction */
                    Inlines.OpusAssert(psDec.LPC_order == 10 || psDec.LPC_order == 16);
                    /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
                    LPC_pred_Q10 = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 1], A_Q12[0]);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 2], A_Q12[1]);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 3], A_Q12[2]);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 4], A_Q12[3]);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 5], A_Q12[4]);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 6], A_Q12[5]);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 7], A_Q12[6]);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 8], A_Q12[7]);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 9], A_Q12[8]);
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 10], A_Q12[9]);
                    if (psDec.LPC_order == 16)
                    {
                        LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 11], A_Q12[10]);
                        LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 12], A_Q12[11]);
                        LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 13], A_Q12[12]);
                        LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 14], A_Q12[13]);
                        LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 15], A_Q12[14]);
                        LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i - 16], A_Q12[15]);
                    }

                    /* Add prediction to LPC excitation */
                    sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i] = Inlines.silk_ADD_LSHIFT32(pres_Q14[pres_Q14_ptr + i], LPC_pred_Q10, 4);

                    /* Scale with gain */
                    xq[pxq + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(sLPC_Q14[SilkConstants.MAX_LPC_ORDER + i], Gain_Q10), 8));
                }

                /* DEBUG_STORE_DATA( dec.pcm, pxq, psDec.subfr_length * sizeof( short ) ) */

                /* Update LPC filter state */
                Array.Copy(sLPC_Q14, psDec.subfr_length, sLPC_Q14, 0, SilkConstants.MAX_LPC_ORDER);
                pexc_Q14 += psDec.subfr_length;
                pxq      += psDec.subfr_length;
            }

            /* Save LPC state */
            Array.Copy(sLPC_Q14, 0, psDec.sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);
        }
Exemplo n.º 3
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);
            }
        }
Exemplo n.º 4
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;
            }
        }
Exemplo n.º 5
0
        /**************************************************/
        /* Update state of PLC                            */
        /**************************************************/
        internal static void silk_PLC_update(
            SilkChannelDecoder psDec,             /* I/O Decoder state        */
            SilkDecoderControl psDecCtrl          /* I/O Decoder control      */
            )
        {
            int       LTP_Gain_Q14, temp_LTP_Gain_Q14;
            int       i, j;
            PLCStruct psPLC = psDec.sPLC; // [porting note] pointer on the stack

            /* Update parameters used in case of packet loss */
            psDec.prevSignalType = psDec.indices.signalType;
            LTP_Gain_Q14         = 0;
            if (psDec.indices.signalType == SilkConstants.TYPE_VOICED)
            {
                /* Find the parameters for the last subframe which contains a pitch pulse */
                for (j = 0; j *psDec.subfr_length < psDecCtrl.pitchL[psDec.nb_subfr - 1]; j++)
                {
                    if (j == psDec.nb_subfr)
                    {
                        break;
                    }
                    temp_LTP_Gain_Q14 = 0;
                    for (i = 0; i < SilkConstants.LTP_ORDER; i++)
                    {
                        temp_LTP_Gain_Q14 += psDecCtrl.LTPCoef_Q14[(psDec.nb_subfr - 1 - j) * SilkConstants.LTP_ORDER + i];
                    }
                    if (temp_LTP_Gain_Q14 > LTP_Gain_Q14)
                    {
                        LTP_Gain_Q14 = temp_LTP_Gain_Q14;

                        Array.Copy(psDecCtrl.LTPCoef_Q14, Inlines.silk_SMULBB(psDec.nb_subfr - 1 - j, SilkConstants.LTP_ORDER), psPLC.LTPCoef_Q14, 0, SilkConstants.LTP_ORDER);

                        psPLC.pitchL_Q8 = Inlines.silk_LSHIFT(psDecCtrl.pitchL[psDec.nb_subfr - 1 - j], 8);
                    }
                }

                Arrays.MemSetShort(psPLC.LTPCoef_Q14, 0, SilkConstants.LTP_ORDER);
                psPLC.LTPCoef_Q14[SilkConstants.LTP_ORDER / 2] = (short)(LTP_Gain_Q14);

                /* Limit LT coefs */
                if (LTP_Gain_Q14 < SilkConstants.V_PITCH_GAIN_START_MIN_Q14)
                {
                    int scale_Q10;
                    int tmp;

                    tmp       = Inlines.silk_LSHIFT(SilkConstants.V_PITCH_GAIN_START_MIN_Q14, 10);
                    scale_Q10 = Inlines.silk_DIV32(tmp, Inlines.silk_max(LTP_Gain_Q14, 1));
                    for (i = 0; i < SilkConstants.LTP_ORDER; i++)
                    {
                        psPLC.LTPCoef_Q14[i] = (short)(Inlines.silk_RSHIFT(Inlines.silk_SMULBB(psPLC.LTPCoef_Q14[i], scale_Q10), 10));
                    }
                }
                else if (LTP_Gain_Q14 > SilkConstants.V_PITCH_GAIN_START_MAX_Q14)
                {
                    int scale_Q14;
                    int tmp;

                    tmp       = Inlines.silk_LSHIFT(SilkConstants.V_PITCH_GAIN_START_MAX_Q14, 14);
                    scale_Q14 = Inlines.silk_DIV32(tmp, Inlines.silk_max(LTP_Gain_Q14, 1));
                    for (i = 0; i < SilkConstants.LTP_ORDER; i++)
                    {
                        psPLC.LTPCoef_Q14[i] = (short)(Inlines.silk_RSHIFT(Inlines.silk_SMULBB(psPLC.LTPCoef_Q14[i], scale_Q14), 14));
                    }
                }
            }
            else
            {
                psPLC.pitchL_Q8 = Inlines.silk_LSHIFT(Inlines.silk_SMULBB(psDec.fs_kHz, 18), 8);
                Arrays.MemSetShort(psPLC.LTPCoef_Q14, 0, SilkConstants.LTP_ORDER);
            }

            /* Save LPC coeficients */
            Array.Copy(psDecCtrl.PredCoef_Q12[1], psPLC.prevLPC_Q12, psDec.LPC_order);
            psPLC.prevLTP_scale_Q14 = (short)(psDecCtrl.LTP_scale_Q14);

            /* Save last two gains */
            Array.Copy(psDecCtrl.Gains_Q16, psDec.nb_subfr - 2, psPLC.prevGain_Q16, 0, 2);

            psPLC.subfr_length = psDec.subfr_length;
            psPLC.nb_subfr     = psDec.nb_subfr;
        }
Exemplo n.º 6
0
        internal static void silk_PLC_conceal(
            SilkChannelDecoder psDec,     /* I/O Decoder state        */
            SilkDecoderControl psDecCtrl, /* I/O Decoder control      */
            short[] frame,                /* O LPC residual signal    */
            int frame_ptr
            )
        {
            int   i, j, k;
            int   lag, idx, sLTP_buf_idx;
            int   rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30;
            int   energy1, energy2, shift1, shift2;
            int   rand_ptr;
            int   pred_lag_ptr;
            int   LPC_pred_Q10, LTP_pred_Q12;
            short rand_scale_Q14;

            short[] B_Q14;
            int     sLPC_Q14_ptr;

            short[]   sLTP     = new short[psDec.ltp_mem_length];
            int[]     sLTP_Q14 = new int[psDec.ltp_mem_length + psDec.frame_length];
            PLCStruct psPLC    = psDec.sPLC;

            int[] prevGain_Q10 = new int[2];

            prevGain_Q10[0] = Inlines.silk_RSHIFT(psPLC.prevGain_Q16[0], 6);
            prevGain_Q10[1] = Inlines.silk_RSHIFT(psPLC.prevGain_Q16[1], 6);

            if (psDec.first_frame_after_reset != 0)
            {
                Arrays.MemSetShort(psPLC.prevLPC_Q12, 0, SilkConstants.MAX_LPC_ORDER);
            }

            silk_PLC_energy(out energy1, out shift1, out energy2, out shift2, psDec.exc_Q14, prevGain_Q10, psDec.subfr_length, psDec.nb_subfr);

            if (Inlines.silk_RSHIFT(energy1, shift2) < Inlines.silk_RSHIFT(energy2, shift1))
            {
                /* First sub-frame has lowest energy */
                rand_ptr = Inlines.silk_max_int(0, (psPLC.nb_subfr - 1) * psPLC.subfr_length - SilkConstants.RAND_BUF_SIZE);
            }
            else
            {
                /* Second sub-frame has lowest energy */
                rand_ptr = Inlines.silk_max_int(0, psPLC.nb_subfr * psPLC.subfr_length - SilkConstants.RAND_BUF_SIZE);
            }

            /* Set up Gain to random noise component */
            B_Q14          = psPLC.LTPCoef_Q14;
            rand_scale_Q14 = psPLC.randScale_Q14;

            /* Set up attenuation gains */
            harm_Gain_Q15 = HARM_ATT_Q15[Inlines.silk_min_int(NB_ATT - 1, psDec.lossCnt)];
            if (psDec.prevSignalType == SilkConstants.TYPE_VOICED)
            {
                rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[Inlines.silk_min_int(NB_ATT - 1, psDec.lossCnt)];
            }
            else
            {
                rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[Inlines.silk_min_int(NB_ATT - 1, psDec.lossCnt)];
            }

            /* LPC concealment. Apply BWE to previous LPC */
            BWExpander.silk_bwexpander(psPLC.prevLPC_Q12, psDec.LPC_order, ((int)((SilkConstants.BWE_COEF) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.BWE_COEF, 16)*/);

            /* First Lost frame */
            if (psDec.lossCnt == 0)
            {
                rand_scale_Q14 = 1 << 14;

                /* Reduce random noise Gain for voiced frames */
                if (psDec.prevSignalType == SilkConstants.TYPE_VOICED)
                {
                    for (i = 0; i < SilkConstants.LTP_ORDER; i++)
                    {
                        rand_scale_Q14 -= B_Q14[i];
                    }
                    rand_scale_Q14 = Inlines.silk_max_16(3277, rand_scale_Q14); /* 0.2 */
                    rand_scale_Q14 = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(rand_scale_Q14, psPLC.prevLTP_scale_Q14), 14);
                }
                else
                {
                    /* Reduce random noise for unvoiced frames with high LPC gain */
                    int invGain_Q30, down_scale_Q30;

                    invGain_Q30 = LPCInversePredGain.silk_LPC_inverse_pred_gain(psPLC.prevLPC_Q12, psDec.LPC_order);

                    down_scale_Q30 = Inlines.silk_min_32(Inlines.silk_RSHIFT((int)1 << 30, SilkConstants.LOG2_INV_LPC_GAIN_HIGH_THRES), invGain_Q30);
                    down_scale_Q30 = Inlines.silk_max_32(Inlines.silk_RSHIFT((int)1 << 30, SilkConstants.LOG2_INV_LPC_GAIN_LOW_THRES), down_scale_Q30);
                    down_scale_Q30 = Inlines.silk_LSHIFT(down_scale_Q30, SilkConstants.LOG2_INV_LPC_GAIN_HIGH_THRES);

                    rand_Gain_Q15 = Inlines.silk_RSHIFT(Inlines.silk_SMULWB(down_scale_Q30, rand_Gain_Q15), 14);
                }
            }

            rand_seed    = psPLC.rand_seed;
            lag          = Inlines.silk_RSHIFT_ROUND(psPLC.pitchL_Q8, 8);
            sLTP_buf_idx = psDec.ltp_mem_length;

            /* Rewhiten LTP state */
            idx = psDec.ltp_mem_length - lag - psDec.LPC_order - SilkConstants.LTP_ORDER / 2;
            Inlines.OpusAssert(idx > 0);
            Filters.silk_LPC_analysis_filter(sLTP, idx, psDec.outBuf, idx, psPLC.prevLPC_Q12, 0, psDec.ltp_mem_length - idx, psDec.LPC_order);
            /* Scale LTP state */
            inv_gain_Q30 = Inlines.silk_INVERSE32_varQ(psPLC.prevGain_Q16[1], 46);
            inv_gain_Q30 = Inlines.silk_min(inv_gain_Q30, int.MaxValue >> 1);
            for (i = idx + psDec.LPC_order; i < psDec.ltp_mem_length; i++)
            {
                sLTP_Q14[i] = Inlines.silk_SMULWB(inv_gain_Q30, sLTP[i]);
            }

            /***************************/
            /* LTP synthesis filtering */
            /***************************/
            for (k = 0; k < psDec.nb_subfr; k++)
            {
                /* Set up pointer */
                pred_lag_ptr = sLTP_buf_idx - lag + SilkConstants.LTP_ORDER / 2;
                for (i = 0; i < psDec.subfr_length; i++)
                {
                    /* Unrolled loop */
                    /* Avoids introducing a bias because Inlines.silk_SMLAWB() always rounds to -inf */
                    LTP_pred_Q12 = 2;
                    LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr], B_Q14[0]);
                    LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 1], B_Q14[1]);
                    LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 2], B_Q14[2]);
                    LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 3], B_Q14[3]);
                    LTP_pred_Q12 = Inlines.silk_SMLAWB(LTP_pred_Q12, sLTP_Q14[pred_lag_ptr - 4], B_Q14[4]);
                    pred_lag_ptr++;

                    /* Generate LPC excitation */
                    rand_seed = Inlines.silk_RAND(rand_seed);
                    idx       = Inlines.silk_RSHIFT(rand_seed, 25) & SilkConstants.RAND_BUF_MASK;
                    sLTP_Q14[sLTP_buf_idx] = Inlines.silk_LSHIFT32(Inlines.silk_SMLAWB(LTP_pred_Q12, psDec.exc_Q14[rand_ptr + idx], rand_scale_Q14), 2);
                    sLTP_buf_idx++;
                }

                /* Gradually reduce LTP gain */
                for (j = 0; j < SilkConstants.LTP_ORDER; j++)
                {
                    B_Q14[j] = (short)(Inlines.silk_RSHIFT(Inlines.silk_SMULBB(harm_Gain_Q15, B_Q14[j]), 15));
                }
                /* Gradually reduce excitation gain */
                rand_scale_Q14 = (short)(Inlines.silk_RSHIFT(Inlines.silk_SMULBB(rand_scale_Q14, rand_Gain_Q15), 15));

                /* Slowly increase pitch lag */
                psPLC.pitchL_Q8 = Inlines.silk_SMLAWB(psPLC.pitchL_Q8, psPLC.pitchL_Q8, SilkConstants.PITCH_DRIFT_FAC_Q16);
                psPLC.pitchL_Q8 = Inlines.silk_min_32(psPLC.pitchL_Q8, Inlines.silk_LSHIFT(Inlines.silk_SMULBB(SilkConstants.MAX_PITCH_LAG_MS, psDec.fs_kHz), 8));
                lag             = Inlines.silk_RSHIFT_ROUND(psPLC.pitchL_Q8, 8);
            }

            /***************************/
            /* LPC synthesis filtering */
            /***************************/
            sLPC_Q14_ptr = psDec.ltp_mem_length - SilkConstants.MAX_LPC_ORDER;

            /* Copy LPC state */
            Array.Copy(psDec.sLPC_Q14_buf, 0, sLTP_Q14, sLPC_Q14_ptr, SilkConstants.MAX_LPC_ORDER);

            Inlines.OpusAssert(psDec.LPC_order >= 10); /* check that unrolling works */
            for (i = 0; i < psDec.frame_length; i++)
            {
                /* partly unrolled */
                int sLPCmaxi = sLPC_Q14_ptr + SilkConstants.MAX_LPC_ORDER + i;
                /* Avoids introducing a bias because Inlines.silk_SMLAWB() always rounds to -inf */
                LPC_pred_Q10 = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 1], psPLC.prevLPC_Q12[0]);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 2], psPLC.prevLPC_Q12[1]);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 3], psPLC.prevLPC_Q12[2]);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 4], psPLC.prevLPC_Q12[3]);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 5], psPLC.prevLPC_Q12[4]);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 6], psPLC.prevLPC_Q12[5]);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 7], psPLC.prevLPC_Q12[6]);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 8], psPLC.prevLPC_Q12[7]);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 9], psPLC.prevLPC_Q12[8]);
                LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - 10], psPLC.prevLPC_Q12[9]);
                for (j = 10; j < psDec.LPC_order; j++)
                {
                    LPC_pred_Q10 = Inlines.silk_SMLAWB(LPC_pred_Q10, sLTP_Q14[sLPCmaxi - j - 1], psPLC.prevLPC_Q12[j]);
                }

                /* Add prediction to LPC excitation */
                sLTP_Q14[sLPCmaxi] = Inlines.silk_ADD_LSHIFT32(sLTP_Q14[sLPCmaxi], LPC_pred_Q10, 4);

                /* Scale with Gain */
                frame[frame_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(sLTP_Q14[sLPCmaxi], prevGain_Q10[1]), 8)));
            }

            /* Save LPC state */
            Array.Copy(sLTP_Q14, sLPC_Q14_ptr + psDec.frame_length, psDec.sLPC_Q14_buf, 0, SilkConstants.MAX_LPC_ORDER);

            /**************************************/
            /* Update states                      */
            /**************************************/
            psPLC.rand_seed     = rand_seed;
            psPLC.randScale_Q14 = rand_scale_Q14;
            for (i = 0; i < SilkConstants.MAX_NB_SUBFR; i++)
            {
                psDecCtrl.pitchL[i] = lag;
            }
        }