/* 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;
            }
        }
Example #2
0
        /* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum     */
        /* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
        internal static void limit_warped_coefs(
            int[] coefs_syn_Q24,
            int[] coefs_ana_Q24,
            int lambda_Q16,
            int limit_Q24,
            int order
            )
        {
            int i, iter, ind = 0;
            int tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16;
            int nom_Q16, den_Q24;

            /* Convert to monic coefficients */
            lambda_Q16 = -lambda_Q16;
            for (i = order - 1; i > 0; i--)
            {
                coefs_syn_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16);
                coefs_ana_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16);
            }
            lambda_Q16   = -lambda_Q16;
            nom_Q16      = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 16)*/, -(int)lambda_Q16, lambda_Q16);
            den_Q24      = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (24)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 24)*/, coefs_syn_Q24[0], lambda_Q16);
            gain_syn_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
            den_Q24      = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (24)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 24)*/, coefs_ana_Q24[0], lambda_Q16);
            gain_ana_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
            for (i = 0; i < order; i++)
            {
                coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]);
                coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]);
            }

            for (iter = 0; iter < 10; iter++)
            {
                /* Find maximum absolute value */
                maxabs_Q24 = -1;
                for (i = 0; i < order; i++)
                {
                    tmp = Inlines.silk_max(Inlines.silk_abs_int32(coefs_syn_Q24[i]), Inlines.silk_abs_int32(coefs_ana_Q24[i]));
                    if (tmp > maxabs_Q24)
                    {
                        maxabs_Q24 = tmp;
                        ind        = i;
                    }
                }
                if (maxabs_Q24 <= limit_Q24)
                {
                    /* Coefficients are within range - done */
                    return;
                }

                /* Convert back to true warped coefficients */
                for (i = 1; i < order; i++)
                {
                    coefs_syn_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16);
                    coefs_ana_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16);
                }
                gain_syn_Q16 = Inlines.silk_INVERSE32_varQ(gain_syn_Q16, 32);
                gain_ana_Q16 = Inlines.silk_INVERSE32_varQ(gain_ana_Q16, 32);
                for (i = 0; i < order; i++)
                {
                    coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]);
                    coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]);
                }

                /* Apply bandwidth expansion */
                chirp_Q16 = ((int)((0.99f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(0.99f, 16)*/ - Inlines.silk_DIV32_varQ(
                    Inlines.silk_SMULWB(maxabs_Q24 - limit_Q24, Inlines.silk_SMLABB(((int)((0.8f) * ((long)1 << (10)) + 0.5)) /*Inlines.SILK_CONST(0.8f, 10)*/, ((int)((0.1f) * ((long)1 << (10)) + 0.5)) /*Inlines.SILK_CONST(0.1f, 10)*/, iter)),
                    Inlines.silk_MUL(maxabs_Q24, ind + 1), 22);
                BWExpander.silk_bwexpander_32(coefs_syn_Q24, order, chirp_Q16);
                BWExpander.silk_bwexpander_32(coefs_ana_Q24, order, chirp_Q16);

                /* Convert to monic warped coefficients */
                lambda_Q16 = -lambda_Q16;
                for (i = order - 1; i > 0; i--)
                {
                    coefs_syn_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[i - 1], coefs_syn_Q24[i], lambda_Q16);
                    coefs_ana_Q24[i - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[i - 1], coefs_ana_Q24[i], lambda_Q16);
                }
                lambda_Q16   = -lambda_Q16;
                nom_Q16      = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 16)*/, -(int)lambda_Q16, lambda_Q16);
                den_Q24      = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (24)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 24)*/, coefs_syn_Q24[0], lambda_Q16);
                gain_syn_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
                den_Q24      = Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (24)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 24)*/, coefs_ana_Q24[0], lambda_Q16);
                gain_ana_Q16 = Inlines.silk_DIV32_varQ(nom_Q16, den_Q24, 24);
                for (i = 0; i < order; i++)
                {
                    coefs_syn_Q24[i] = Inlines.silk_SMULWW(gain_syn_Q16, coefs_syn_Q24[i]);
                    coefs_ana_Q24[i] = Inlines.silk_SMULWW(gain_ana_Q16, coefs_ana_Q24[i]);
                }
            }
            Inlines.OpusAssert(false);
        }
Example #3
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;
            }
        }
Example #4
0
        /**************************************************************/
        /* Compute noise shaping coefficients and initial gain values */
        /**************************************************************/
        internal static void silk_noise_shape_analysis(
            SilkChannelEncoder psEnc,                      /* I/O  Encoder state FIX                                                           */
            SilkEncoderControl psEncCtrl,                  /* I/O  Encoder control FIX                                                         */
            short[] pitch_res,                             /* I    LPC residual from pitch analysis                                            */
            int pitch_res_ptr,
            short[] x,                                     /* I    Input signal [ frame_length + la_shape ]                                    */
            int x_ptr
            )
        {
            SilkShapeState psShapeSt = psEnc.sShape;
            int            k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0;
            int            SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32;
            int            nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
            int            delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;

            int[]   auto_corr     = new int[SilkConstants.MAX_SHAPE_LPC_ORDER + 1];
            int[]   refl_coef_Q16 = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
            int[]   AR1_Q24       = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
            int[]   AR2_Q24       = new int[SilkConstants.MAX_SHAPE_LPC_ORDER];
            short[] x_windowed;
            int     pitch_res_ptr2;
            int     x_ptr2;

            /* Point to start of first LPC analysis block */
            x_ptr2 = x_ptr - psEnc.la_shape;

            /****************/
            /* GAIN CONTROL */
            /****************/
            SNR_adj_dB_Q7 = psEnc.SNR_dB_Q7;

            /* Input quality is the average of the quality in the lowest two VAD bands */
            psEncCtrl.input_quality_Q14 = (int)Inlines.silk_RSHIFT((int)psEnc.input_quality_bands_Q15[0]
                                                                   + psEnc.input_quality_bands_Q15[1], 2);

            /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
            psEncCtrl.coding_quality_Q14 = Inlines.silk_RSHIFT(Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT_ROUND(SNR_adj_dB_Q7 -
                                                                                                               ((int)((20.0f) * ((long)1 << (7)) + 0.5)) /*Inlines.SILK_CONST(20.0f, 7)*/, 4)), 1);

            /* Reduce coding SNR during low speech activity */
            if (psEnc.useCBR == 0)
            {
                b_Q8          = ((int)((1.0f) * ((long)1 << (8)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 8)*/ - psEnc.speech_activity_Q8;
                b_Q8          = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(b_Q8, 8), b_Q8);
                SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7,
                                                    Inlines.silk_SMULBB(((int)((0 - TuningParameters.BG_SNR_DECR_dB) * ((long)1 << (7)) + 0.5)) /*Inlines.SILK_CONST(0 - TuningParameters.BG_SNR_DECR_dB, 7)*/ >> (4 + 1), b_Q8), /* Q11*/
                                                    Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 14)*/ + psEncCtrl.input_quality_Q14, psEncCtrl.coding_quality_Q14));                 /* Q12*/
            }

            if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
            {
                /* Reduce gains for periodic signals */
                SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7, ((int)((TuningParameters.HARM_SNR_INCR_dB) * ((long)1 << (8)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.HARM_SNR_INCR_dB, 8)*/, psEnc.LTPCorr_Q15);
            }
            else
            {
                /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
                SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7,
                                                    Inlines.silk_SMLAWB(((int)((6.0f) * ((long)1 << (9)) + 0.5)) /*Inlines.SILK_CONST(6.0f, 9)*/, -((int)((0.4f) * ((long)1 << (18)) + 0.5)) /*Inlines.SILK_CONST(0.4f, 18)*/, psEnc.SNR_dB_Q7),
                                                    ((int)((1.0f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 14)*/ - psEncCtrl.input_quality_Q14);
            }

            /*************************/
            /* SPARSENESS PROCESSING */
            /*************************/
            /* Set quantizer offset */
            if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
            {
                /* Initially set to 0; may be overruled in process_gains(..) */
                psEnc.indices.quantOffsetType = 0;
                psEncCtrl.sparseness_Q8       = 0;
            }
            else
            {
                /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
                nSamples            = Inlines.silk_LSHIFT(psEnc.fs_kHz, 1);
                energy_variation_Q7 = 0;
                log_energy_prev_Q7  = 0;
                pitch_res_ptr2      = pitch_res_ptr;
                for (k = 0; k < Inlines.silk_SMULBB(SilkConstants.SUB_FRAME_LENGTH_MS, psEnc.nb_subfr) / 2; k++)
                {
                    SumSqrShift.silk_sum_sqr_shift(out nrg, out scale, pitch_res, pitch_res_ptr2, nSamples);
                    nrg += Inlines.silk_RSHIFT(nSamples, scale);           /* Q(-scale)*/

                    log_energy_Q7 = Inlines.silk_lin2log(nrg);
                    if (k > 0)
                    {
                        energy_variation_Q7 += Inlines.silk_abs(log_energy_Q7 - log_energy_prev_Q7);
                    }
                    log_energy_prev_Q7 = log_energy_Q7;
                    pitch_res_ptr2    += nSamples;
                }

                psEncCtrl.sparseness_Q8 = Inlines.silk_RSHIFT(Sigmoid.silk_sigm_Q15(Inlines.silk_SMULWB(energy_variation_Q7 -
                                                                                                        ((int)((5.0f) * ((long)1 << (7)) + 0.5)) /*Inlines.SILK_CONST(5.0f, 7)*/, ((int)((0.1f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(0.1f, 16)*/)), 7);

                /* Set quantization offset depending on sparseness measure */
                if (psEncCtrl.sparseness_Q8 > ((int)((TuningParameters.SPARSENESS_THRESHOLD_QNT_OFFSET) * ((long)1 << (8)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.SPARSENESS_THRESHOLD_QNT_OFFSET, 8)*/)
                {
                    psEnc.indices.quantOffsetType = 0;
                }
                else
                {
                    psEnc.indices.quantOffsetType = 1;
                }

                /* Increase coding SNR for sparse signals */
                SNR_adj_dB_Q7 = Inlines.silk_SMLAWB(SNR_adj_dB_Q7, ((int)((TuningParameters.SPARSE_SNR_INCR_dB) * ((long)1 << (15)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.SPARSE_SNR_INCR_dB, 15)*/, psEncCtrl.sparseness_Q8 - ((int)((0.5f) * ((long)1 << (8)) + 0.5)) /*Inlines.SILK_CONST(0.5f, 8)*/);
            }

            /*******************************/
            /* Control bandwidth expansion */
            /*******************************/
            /* More BWE for signals with high prediction gain */
            strength_Q16 = Inlines.silk_SMULWB(psEncCtrl.predGain_Q16, ((int)((TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION, 16)*/);
            BWExp1_Q16   = BWExp2_Q16 = Inlines.silk_DIV32_varQ(((int)((TuningParameters.BANDWIDTH_EXPANSION) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.BANDWIDTH_EXPANSION, 16)*/,
                                                                Inlines.silk_SMLAWW(((int)((1.0f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 16)*/, strength_Q16, strength_Q16), 16);
            delta_Q16 = Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 16)*/ - Inlines.silk_SMULBB(3, psEncCtrl.coding_quality_Q14),
                                            ((int)((TuningParameters.LOW_RATE_BANDWIDTH_EXPANSION_DELTA) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16)*/);
            BWExp1_Q16 = Inlines.silk_SUB32(BWExp1_Q16, delta_Q16);
            BWExp2_Q16 = Inlines.silk_ADD32(BWExp2_Q16, delta_Q16);
            /* BWExp1 will be applied after BWExp2, so make it relative */
            BWExp1_Q16 = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(BWExp1_Q16, 14), Inlines.silk_RSHIFT(BWExp2_Q16, 2));

            if (psEnc.warping_Q16 > 0)
            {
                /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
                warping_Q16 = Inlines.silk_SMLAWB(psEnc.warping_Q16, (int)psEncCtrl.coding_quality_Q14, ((int)((0.01f) * ((long)1 << (18)) + 0.5)) /*Inlines.SILK_CONST(0.01f, 18)*/);
            }
            else
            {
                warping_Q16 = 0;
            }

            /********************************************/
            /* Compute noise shaping AR coefs and gains */
            /********************************************/
            x_windowed = new short[psEnc.shapeWinLength];
            for (k = 0; k < psEnc.nb_subfr; k++)
            {
                /* Apply window: sine slope followed by flat part followed by cosine slope */
                int shift, slope_part, flat_part;
                flat_part  = psEnc.fs_kHz * 3;
                slope_part = Inlines.silk_RSHIFT(psEnc.shapeWinLength - flat_part, 1);

                ApplySineWindow.silk_apply_sine_window(x_windowed, 0, x, x_ptr2, 1, slope_part);
                shift = slope_part;
                Array.Copy(x, x_ptr2 + shift, x_windowed, shift, flat_part);
                shift += flat_part;
                ApplySineWindow.silk_apply_sine_window(x_windowed, shift, x, x_ptr2 + shift, 2, slope_part);

                /* Update pointer: next LPC analysis block */
                x_ptr2 += psEnc.subfr_length;
                BoxedValueInt scale_boxed = new BoxedValueInt(scale);
                if (psEnc.warping_Q16 > 0)
                {
                    /* Calculate warped auto correlation */
                    Autocorrelation.silk_warped_autocorrelation(auto_corr, scale_boxed, x_windowed, warping_Q16, psEnc.shapeWinLength, psEnc.shapingLPCOrder);
                }
                else
                {
                    /* Calculate regular auto correlation */
                    Autocorrelation.silk_autocorr(auto_corr, scale_boxed, x_windowed, psEnc.shapeWinLength, psEnc.shapingLPCOrder + 1);
                }
                scale = scale_boxed.Val;

                /* Add white noise, as a fraction of energy */
                auto_corr[0] = Inlines.silk_ADD32(auto_corr[0], Inlines.silk_max_32(Inlines.silk_SMULWB(Inlines.silk_RSHIFT(auto_corr[0], 4),
                                                                                                        ((int)((TuningParameters.SHAPE_WHITE_NOISE_FRACTION) * ((long)1 << (20)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.SHAPE_WHITE_NOISE_FRACTION, 20)*/), 1));

                /* Calculate the reflection coefficients using schur */
                nrg = Schur.silk_schur64(refl_coef_Q16, auto_corr, psEnc.shapingLPCOrder);
                Inlines.OpusAssert(nrg >= 0);

                /* Convert reflection coefficients to prediction coefficients */
                K2A.silk_k2a_Q16(AR2_Q24, refl_coef_Q16, psEnc.shapingLPCOrder);

                Qnrg = -scale;          /* range: -12...30*/
                Inlines.OpusAssert(Qnrg >= -12);
                Inlines.OpusAssert(Qnrg <= 30);

                /* Make sure that Qnrg is an even number */
                if ((Qnrg & 1) != 0)
                {
                    Qnrg -= 1;
                    nrg >>= 1;
                }

                tmp32  = Inlines.silk_SQRT_APPROX(nrg);
                Qnrg >>= 1;             /* range: -6...15*/

                psEncCtrl.Gains_Q16[k] = Inlines.silk_LSHIFT_SAT32(tmp32, 16 - Qnrg);

                if (psEnc.warping_Q16 > 0)
                {
                    /* Adjust gain for warping */
                    gain_mult_Q16 = warped_gain(AR2_Q24, warping_Q16, psEnc.shapingLPCOrder);
                    Inlines.OpusAssert(psEncCtrl.Gains_Q16[k] >= 0);
                    if (Inlines.silk_SMULWW(Inlines.silk_RSHIFT_ROUND(psEncCtrl.Gains_Q16[k], 1), gain_mult_Q16) >= (int.MaxValue >> 1))
                    {
                        psEncCtrl.Gains_Q16[k] = int.MaxValue;
                    }
                    else
                    {
                        psEncCtrl.Gains_Q16[k] = Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[k], gain_mult_Q16);
                    }
                }

                /* Bandwidth expansion for synthesis filter shaping */
                BWExpander.silk_bwexpander_32(AR2_Q24, psEnc.shapingLPCOrder, BWExp2_Q16);

                /* Compute noise shaping filter coefficients */
                Array.Copy(AR2_Q24, AR1_Q24, psEnc.shapingLPCOrder);

                /* Bandwidth expansion for analysis filter shaping */
                Inlines.OpusAssert(BWExp1_Q16 <= ((int)((1.0f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 16)*/);
                BWExpander.silk_bwexpander_32(AR1_Q24, psEnc.shapingLPCOrder, BWExp1_Q16);

                /* Ratio of prediction gains, in energy domain */
                pre_nrg_Q30 = LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(AR2_Q24, psEnc.shapingLPCOrder);
                nrg         = LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(AR1_Q24, psEnc.shapingLPCOrder);

                /*psEncCtrl.GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/
                pre_nrg_Q30 = Inlines.silk_LSHIFT32(Inlines.silk_SMULWB(pre_nrg_Q30, ((int)((0.7f) * ((long)1 << (15)) + 0.5)) /*Inlines.SILK_CONST(0.7f, 15)*/), 1);
                psEncCtrl.GainsPre_Q14[k] = (int)((int)((0.3f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(0.3f, 14)*/ + Inlines.silk_DIV32_varQ(pre_nrg_Q30, nrg, 14);

                /* Convert to monic warped prediction coefficients and limit absolute values */
                limit_warped_coefs(AR2_Q24, AR1_Q24, warping_Q16, ((int)((3.999f) * ((long)1 << (24)) + 0.5)) /*Inlines.SILK_CONST(3.999f, 24)*/, psEnc.shapingLPCOrder);

                /* Convert from Q24 to Q13 and store in int16 */
                for (i = 0; i < psEnc.shapingLPCOrder; i++)
                {
                    psEncCtrl.AR1_Q13[k * SilkConstants.MAX_SHAPE_LPC_ORDER + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(AR1_Q24[i], 11));
                    psEncCtrl.AR2_Q13[k * SilkConstants.MAX_SHAPE_LPC_ORDER + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(AR2_Q24[i], 11));
                }
            }

            /*****************/
            /* Gain tweaking */
            /*****************/
            /* Increase gains during low speech activity and put lower limit on gains */
            gain_mult_Q16 = Inlines.silk_log2lin(-Inlines.silk_SMLAWB(-((int)((16.0f) * ((long)1 << (7)) + 0.5)) /*Inlines.SILK_CONST(16.0f, 7)*/, SNR_adj_dB_Q7, ((int)((0.16f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(0.16f, 16)*/));
            gain_add_Q16  = Inlines.silk_log2lin(Inlines.silk_SMLAWB(((int)((16.0f) * ((long)1 << (7)) + 0.5)) /*Inlines.SILK_CONST(16.0f, 7)*/, ((int)((SilkConstants.MIN_QGAIN_DB) * ((long)1 << (7)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.MIN_QGAIN_DB, 7)*/, ((int)((0.16f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(0.16f, 16)*/));
            Inlines.OpusAssert(gain_mult_Q16 > 0);
            for (k = 0; k < psEnc.nb_subfr; k++)
            {
                psEncCtrl.Gains_Q16[k] = Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[k], gain_mult_Q16);
                Inlines.OpusAssert(psEncCtrl.Gains_Q16[k] >= 0);
                psEncCtrl.Gains_Q16[k] = Inlines.silk_ADD_POS_SAT32(psEncCtrl.Gains_Q16[k], gain_add_Q16);
            }

            gain_mult_Q16 = ((int)((1.0f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 16)*/ + Inlines.silk_RSHIFT_ROUND(Inlines.silk_MLA(((int)((TuningParameters.INPUT_TILT) * ((long)1 << (26)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.INPUT_TILT, 26)*/,
                                                                                                                                                    psEncCtrl.coding_quality_Q14, ((int)((TuningParameters.HIGH_RATE_INPUT_TILT) * ((long)1 << (12)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.HIGH_RATE_INPUT_TILT, 12)*/), 10);
            for (k = 0; k < psEnc.nb_subfr; k++)
            {
                psEncCtrl.GainsPre_Q14[k] = Inlines.silk_SMULWB(gain_mult_Q16, psEncCtrl.GainsPre_Q14[k]);
            }

            /************************************************/
            /* Control low-frequency shaping and noise tilt */
            /************************************************/
            /* Less low frequency shaping for noisy inputs */
            strength_Q16 = Inlines.silk_MUL(((int)((TuningParameters.LOW_FREQ_SHAPING) * ((long)1 << (4)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.LOW_FREQ_SHAPING, 4)*/, Inlines.silk_SMLAWB(((int)((1.0f) * ((long)1 << (12)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 12)*/,
                                                                                                                                                                                                    ((int)((TuningParameters.LOW_QUALITY_LOW_FREQ_SHAPING_DECR) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13)*/, psEnc.input_quality_bands_Q15[0] - ((int)((1.0f) * ((long)1 << (15)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 15)*/));
            strength_Q16 = Inlines.silk_RSHIFT(Inlines.silk_MUL(strength_Q16, psEnc.speech_activity_Q8), 8);
            if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
            {
                /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
                /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
                int fs_kHz_inv = Inlines.silk_DIV32_16(((int)((0.2f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(0.2f, 14)*/, psEnc.fs_kHz);
                for (k = 0; k < psEnc.nb_subfr; k++)
                {
                    b_Q14 = fs_kHz_inv + Inlines.silk_DIV32_16(((int)((3.0f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(3.0f, 14)*/, psEncCtrl.pitchL[k]);
                    /* Pack two coefficients in one int32 */
                    psEncCtrl.LF_shp_Q14[k]  = Inlines.silk_LSHIFT(((int)((1.0f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 14)*/ - b_Q14 - Inlines.silk_SMULWB(strength_Q16, b_Q14), 16);
                    psEncCtrl.LF_shp_Q14[k] |= (b_Q14 - ((int)((1.0f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 14)*/) & 0xFFFF;                                                                                                              // opus bug: again, cast to ushort was done here where bitwise masking was intended
                }
                Inlines.OpusAssert(((int)((TuningParameters.HARM_HP_NOISE_COEF) * ((long)1 << (24)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.HARM_HP_NOISE_COEF, 24)*/ < ((int)((0.5f) * ((long)1 << (24)) + 0.5)) /*Inlines.SILK_CONST(0.5f, 24)*/); /* Guarantees that second argument to SMULWB() is within range of an short*/
                Tilt_Q16 = -((int)((TuningParameters.HP_NOISE_COEF) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.HP_NOISE_COEF, 16)*/ -
                           Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 16)*/ - ((int)((TuningParameters.HP_NOISE_COEF) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.HP_NOISE_COEF, 16)*/,
                                               Inlines.silk_SMULWB(((int)((TuningParameters.HARM_HP_NOISE_COEF) * ((long)1 << (24)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.HARM_HP_NOISE_COEF, 24)*/, psEnc.speech_activity_Q8));
            }
            else
            {
                b_Q14 = Inlines.silk_DIV32_16(21299, psEnc.fs_kHz); /* 1.3_Q0 = 21299_Q14*/
                /* Pack two coefficients in one int32 */
                psEncCtrl.LF_shp_Q14[0] = Inlines.silk_LSHIFT(((int)((1.0f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 14)*/ - b_Q14 -
                                                              Inlines.silk_SMULWB(strength_Q16, Inlines.silk_SMULWB(((int)((0.6f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(0.6f, 16)*/, b_Q14)), 16);
                psEncCtrl.LF_shp_Q14[0] |= (b_Q14 - ((int)((1.0f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 14)*/) & 0xFFFF; // opus bug: cast to ushort is better expressed as a bitwise operator, otherwise runtime analysis might flag it as an overflow error
                for (k = 1; k < psEnc.nb_subfr; k++)
                {
                    psEncCtrl.LF_shp_Q14[k] = psEncCtrl.LF_shp_Q14[0];
                }
                Tilt_Q16 = -((int)((TuningParameters.HP_NOISE_COEF) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.HP_NOISE_COEF, 16)*/;
            }

            /****************************/
            /* HARMONIC SHAPING CONTROL */
            /****************************/
            /* Control boosting of harmonic frequencies */
            HarmBoost_Q16 = Inlines.silk_SMULWB(Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (17)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 17)*/ - Inlines.silk_LSHIFT(psEncCtrl.coding_quality_Q14, 3),
                                                                    psEnc.LTPCorr_Q15), ((int)((TuningParameters.LOW_RATE_HARMONIC_BOOST) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.LOW_RATE_HARMONIC_BOOST, 16)*/);

            /* More harmonic boost for noisy input signals */
            HarmBoost_Q16 = Inlines.silk_SMLAWB(HarmBoost_Q16,
                                                ((int)((1.0f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 16)*/ - Inlines.silk_LSHIFT(psEncCtrl.input_quality_Q14, 2), ((int)((TuningParameters.LOW_INPUT_QUALITY_HARMONIC_BOOST) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.LOW_INPUT_QUALITY_HARMONIC_BOOST, 16)*/);

            if (SilkConstants.USE_HARM_SHAPING != 0 && psEnc.indices.signalType == SilkConstants.TYPE_VOICED)
            {
                /* More harmonic noise shaping for high bitrates or noisy input */
                HarmShapeGain_Q16 = Inlines.silk_SMLAWB(((int)((TuningParameters.HARMONIC_SHAPING) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.HARMONIC_SHAPING, 16)*/,
                                                        ((int)((1.0f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 16)*/ - Inlines.silk_SMULWB(((int)((1.0f) * ((long)1 << (18)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 18)*/ - Inlines.silk_LSHIFT(psEncCtrl.coding_quality_Q14, 4),
                                                                                                                                                         psEncCtrl.input_quality_Q14), ((int)((TuningParameters.HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16)*/);

                /* Less harmonic noise shaping for less periodic signals */
                HarmShapeGain_Q16 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(HarmShapeGain_Q16, 1),
                                                        Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT(psEnc.LTPCorr_Q15, 15)));
            }
            else
            {
                HarmShapeGain_Q16 = 0;
            }

            /*************************/
            /* Smooth over subframes */
            /*************************/
            for (k = 0; k < SilkConstants.MAX_NB_SUBFR; k++)
            {
                psShapeSt.HarmBoost_smth_Q16 =
                    Inlines.silk_SMLAWB(psShapeSt.HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt.HarmBoost_smth_Q16, ((int)((TuningParameters.SUBFR_SMTH_COEF) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.SUBFR_SMTH_COEF, 16)*/);
                psShapeSt.HarmShapeGain_smth_Q16 =
                    Inlines.silk_SMLAWB(psShapeSt.HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt.HarmShapeGain_smth_Q16, ((int)((TuningParameters.SUBFR_SMTH_COEF) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.SUBFR_SMTH_COEF, 16)*/);
                psShapeSt.Tilt_smth_Q16 =
                    Inlines.silk_SMLAWB(psShapeSt.Tilt_smth_Q16, Tilt_Q16 - psShapeSt.Tilt_smth_Q16, ((int)((TuningParameters.SUBFR_SMTH_COEF) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.SUBFR_SMTH_COEF, 16)*/);

                psEncCtrl.HarmBoost_Q14[k]     = (int)Inlines.silk_RSHIFT_ROUND(psShapeSt.HarmBoost_smth_Q16, 2);
                psEncCtrl.HarmShapeGain_Q14[k] = (int)Inlines.silk_RSHIFT_ROUND(psShapeSt.HarmShapeGain_smth_Q16, 2);
                psEncCtrl.Tilt_Q14[k]          = (int)Inlines.silk_RSHIFT_ROUND(psShapeSt.Tilt_smth_Q16, 2);
            }
        }
Example #5
0
        /* Find pitch lags */
        internal static void silk_find_pitch_lags(
            SilkChannelEncoder psEnc,                     /* I/O  encoder state                                                               */
            SilkEncoderControl psEncCtrl,                 /* I/O  encoder control                                                             */
            short[] res,                                  /* O    residual                                                                    */
            short[] x,                                    /* I    Speech signal                                                               */
            int x_ptr
            )
        {
            int buf_len, i, scale;
            int thrhld_Q13, res_nrg;
            int x_buf, x_buf_ptr;

            short[] Wsig;
            int     Wsig_ptr;

            int[]   auto_corr = new int[SilkConstants.MAX_FIND_PITCH_LPC_ORDER + 1];
            short[] rc_Q15    = new short[SilkConstants.MAX_FIND_PITCH_LPC_ORDER];
            int[]   A_Q24     = new int[SilkConstants.MAX_FIND_PITCH_LPC_ORDER];
            short[] A_Q12     = new short[SilkConstants.MAX_FIND_PITCH_LPC_ORDER];


            /******************************************/
            /* Set up buffer lengths etc based on Fs  */
            /******************************************/
            buf_len = psEnc.la_pitch + psEnc.frame_length + psEnc.ltp_mem_length;

            /* Safety check */
            Inlines.OpusAssert(buf_len >= psEnc.pitch_LPC_win_length);

            x_buf = x_ptr - psEnc.ltp_mem_length;

            /*************************************/
            /* Estimate LPC AR coefficients      */
            /*************************************/

            /* Calculate windowed signal */

            Wsig = new short[psEnc.pitch_LPC_win_length];

            /* First LA_LTP samples */
            x_buf_ptr = x_buf + buf_len - psEnc.pitch_LPC_win_length;
            Wsig_ptr  = 0;
            ApplySineWindow.silk_apply_sine_window(Wsig, Wsig_ptr, x, x_buf_ptr, 1, psEnc.la_pitch);

            /* Middle un - windowed samples */
            Wsig_ptr  += psEnc.la_pitch;
            x_buf_ptr += psEnc.la_pitch;
            Array.Copy(x, x_buf_ptr, Wsig, Wsig_ptr, (psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1)));

            /* Last LA_LTP samples */
            Wsig_ptr  += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1);
            x_buf_ptr += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1);
            ApplySineWindow.silk_apply_sine_window(Wsig, Wsig_ptr, x, x_buf_ptr, 2, psEnc.la_pitch);

            /* Calculate autocorrelation sequence */
            BoxedValueInt boxed_scale = new BoxedValueInt();

            Autocorrelation.silk_autocorr(auto_corr, boxed_scale, Wsig, psEnc.pitch_LPC_win_length, psEnc.pitchEstimationLPCOrder + 1);
            scale = boxed_scale.Val;

            /* Add white noise, as fraction of energy */
            auto_corr[0] = Inlines.silk_SMLAWB(auto_corr[0], auto_corr[0], ((int)((TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.FIND_PITCH_WHITE_NOISE_FRACTION, 16)*/) + 1;

            /* Calculate the reflection coefficients using schur */
            res_nrg = Schur.silk_schur(rc_Q15, auto_corr, psEnc.pitchEstimationLPCOrder);

            /* Prediction gain */
            psEncCtrl.predGain_Q16 = Inlines.silk_DIV32_varQ(auto_corr[0], Inlines.silk_max_int(res_nrg, 1), 16);

            /* Convert reflection coefficients to prediction coefficients */
            K2A.silk_k2a(A_Q24, rc_Q15, psEnc.pitchEstimationLPCOrder);

            /* Convert From 32 bit Q24 to 16 bit Q12 coefs */
            for (i = 0; i < psEnc.pitchEstimationLPCOrder; i++)
            {
                A_Q12[i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(A_Q24[i], 12));
            }

            /* Do BWE */
            BWExpander.silk_bwexpander(A_Q12, psEnc.pitchEstimationLPCOrder, ((int)((TuningParameters.FIND_PITCH_BANDWIDTH_EXPANSION) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.FIND_PITCH_BANDWIDTH_EXPANSION, 16)*/);

            /*****************************************/
            /* LPC analysis filtering                */
            /*****************************************/
            Filters.silk_LPC_analysis_filter(res, 0, x, x_buf, A_Q12, 0, buf_len, psEnc.pitchEstimationLPCOrder);

            if (psEnc.indices.signalType != SilkConstants.TYPE_NO_VOICE_ACTIVITY && psEnc.first_frame_after_reset == 0)
            {
                /* Threshold for pitch estimator */
                thrhld_Q13 = ((int)((0.6f) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(0.6f, 13)*/;
                thrhld_Q13 = Inlines.silk_SMLABB(thrhld_Q13, ((int)((-0.004f) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(-0.004f, 13)*/, psEnc.pitchEstimationLPCOrder);
                thrhld_Q13 = Inlines.silk_SMLAWB(thrhld_Q13, ((int)((-0.1f) * ((long)1 << (21)) + 0.5)) /*Inlines.SILK_CONST(-0.1f, 21)*/, psEnc.speech_activity_Q8);
                thrhld_Q13 = Inlines.silk_SMLABB(thrhld_Q13, ((int)((-0.15f) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(-0.15f, 13)*/, Inlines.silk_RSHIFT(psEnc.prevSignalType, 1));
                thrhld_Q13 = Inlines.silk_SMLAWB(thrhld_Q13, ((int)((-0.1f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(-0.1f, 14)*/, psEnc.input_tilt_Q15);
                thrhld_Q13 = Inlines.silk_SAT16(thrhld_Q13);

                /*****************************************/
                /* Call pitch estimator                  */
                /*****************************************/
                BoxedValueShort boxed_lagIndex     = new BoxedValueShort(psEnc.indices.lagIndex);
                BoxedValueSbyte boxed_contourIndex = new BoxedValueSbyte(psEnc.indices.contourIndex);
                BoxedValueInt   boxed_LTPcorr      = new BoxedValueInt(psEnc.LTPCorr_Q15);
                if (PitchAnalysisCore.silk_pitch_analysis_core(res, psEncCtrl.pitchL, boxed_lagIndex, boxed_contourIndex,
                                                               boxed_LTPcorr, psEnc.prevLag, psEnc.pitchEstimationThreshold_Q16,
                                                               (int)thrhld_Q13, psEnc.fs_kHz, psEnc.pitchEstimationComplexity, psEnc.nb_subfr) == 0)
                {
                    psEnc.indices.signalType = SilkConstants.TYPE_VOICED;
                }
                else
                {
                    psEnc.indices.signalType = SilkConstants.TYPE_UNVOICED;
                }

                psEnc.indices.lagIndex     = boxed_lagIndex.Val;
                psEnc.indices.contourIndex = boxed_contourIndex.Val;
                psEnc.LTPCorr_Q15          = boxed_LTPcorr.Val;
            }
            else
            {
                Arrays.MemSetInt(psEncCtrl.pitchL, 0, SilkConstants.MAX_NB_SUBFR);
                psEnc.indices.lagIndex     = 0;
                psEnc.indices.contourIndex = 0;
                psEnc.LTPCorr_Q15          = 0;
            }
        }