/// <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); } }
/* Finds LPC vector from correlations, and converts to NLSF */ internal static void silk_find_LPC( SilkChannelEncoder psEncC, /* I/O Encoder state */ short[] NLSF_Q15, /* O NLSFs */ short[] x, /* I Input signal */ int minInvGain_Q30 /* I Inverse of max prediction gain */ ) { int k, subfr_length; int[] a_Q16 = new int[SilkConstants.MAX_LPC_ORDER]; int isInterpLower, shift; int res_nrg0, res_nrg1; int rshift0, rshift1; BoxedValueInt scratch_box1 = new BoxedValueInt(); BoxedValueInt scratch_box2 = new BoxedValueInt(); /* Used only for LSF interpolation */ int[] a_tmp_Q16 = new int[SilkConstants.MAX_LPC_ORDER]; int res_nrg_interp, res_nrg, res_tmp_nrg; int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; short[] a_tmp_Q12 = new short[SilkConstants.MAX_LPC_ORDER]; short[] NLSF0_Q15 = new short[SilkConstants.MAX_LPC_ORDER]; subfr_length = psEncC.subfr_length + psEncC.predictLPCOrder; /* Default: no interpolation */ psEncC.indices.NLSFInterpCoef_Q2 = 4; /* Burg AR analysis for the full frame */ BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_Q16, x, 0, minInvGain_Q30, subfr_length, psEncC.nb_subfr, psEncC.predictLPCOrder); res_nrg = scratch_box1.Val; res_nrg_Q = scratch_box2.Val; if (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR) { short[] LPC_res; /* Optimal solution for last 10 ms */ BurgModified.silk_burg_modified(scratch_box1, scratch_box2, a_tmp_Q16, x, (2 * subfr_length), minInvGain_Q30, subfr_length, 2, psEncC.predictLPCOrder); res_tmp_nrg = scratch_box1.Val; res_tmp_nrg_Q = scratch_box2.Val; /* subtract residual energy here, as that's easier than adding it to the */ /* residual energy of the first 10 ms in each iteration of the search below */ shift = res_tmp_nrg_Q - res_nrg_Q; if (shift >= 0) { if (shift < 32) { res_nrg = res_nrg - Inlines.silk_RSHIFT(res_tmp_nrg, shift); } } else { Inlines.OpusAssert(shift > -32); res_nrg = Inlines.silk_RSHIFT(res_nrg, -shift) - res_tmp_nrg; res_nrg_Q = res_tmp_nrg_Q; } /* Convert to NLSFs */ NLSF.silk_A2NLSF(NLSF_Q15, a_tmp_Q16, psEncC.predictLPCOrder); LPC_res = new short[2 * subfr_length]; /* Search over interpolation indices to find the one with lowest residual energy */ for (k = 3; k >= 0; k--) { /* Interpolate NLSFs for first half */ Inlines.silk_interpolate(NLSF0_Q15, psEncC.prev_NLSFq_Q15, NLSF_Q15, k, psEncC.predictLPCOrder); /* Convert to LPC for residual energy evaluation */ NLSF.silk_NLSF2A(a_tmp_Q12, NLSF0_Q15, psEncC.predictLPCOrder); /* Calculate residual energy with NLSF interpolation */ Filters.silk_LPC_analysis_filter(LPC_res, 0, x, 0, a_tmp_Q12, 0, 2 * subfr_length, psEncC.predictLPCOrder); SumSqrShift.silk_sum_sqr_shift(out res_nrg0, out rshift0, LPC_res, psEncC.predictLPCOrder, subfr_length - psEncC.predictLPCOrder); SumSqrShift.silk_sum_sqr_shift(out res_nrg1, out rshift1, LPC_res, psEncC.predictLPCOrder + subfr_length, subfr_length - psEncC.predictLPCOrder); /* Add subframe energies from first half frame */ shift = rshift0 - rshift1; if (shift >= 0) { res_nrg1 = Inlines.silk_RSHIFT(res_nrg1, shift); res_nrg_interp_Q = -rshift0; } else { res_nrg0 = Inlines.silk_RSHIFT(res_nrg0, -shift); res_nrg_interp_Q = -rshift1; } res_nrg_interp = Inlines.silk_ADD32(res_nrg0, res_nrg1); /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */ shift = res_nrg_interp_Q - res_nrg_Q; if (shift >= 0) { if (Inlines.silk_RSHIFT(res_nrg_interp, shift) < res_nrg) { isInterpLower = (true ? 1 : 0); } else { isInterpLower = (false ? 1 : 0); } } else { if (-shift < 32) { if (res_nrg_interp < Inlines.silk_RSHIFT(res_nrg, -shift)) { isInterpLower = (true ? 1 : 0); } else { isInterpLower = (false ? 1 : 0); } } else { isInterpLower = (false ? 1 : 0); } } /* Determine whether current interpolated NLSFs are best so far */ if (isInterpLower == (true ? 1 : 0)) { /* Interpolation has lower residual energy */ res_nrg = res_nrg_interp; res_nrg_Q = res_nrg_interp_Q; psEncC.indices.NLSFInterpCoef_Q2 = (sbyte)k; } } } if (psEncC.indices.NLSFInterpCoef_Q2 == 4) { /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ NLSF.silk_A2NLSF(NLSF_Q15, a_Q16, psEncC.predictLPCOrder); } Inlines.OpusAssert(psEncC.indices.NLSFInterpCoef_Q2 == 4 || (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR)); }
/* 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; } }
/// <summary> /// Encode side-information parameters to payload /// </summary> /// <param name="psEncC">I/O Encoder state</param> /// <param name="psRangeEnc">I/O Compressor data structure</param> /// <param name="FrameIndex">I Frame number</param> /// <param name="encode_LBRR">I Flag indicating LBRR data is being encoded</param> /// <param name="condCoding">I The type of conditional coding to use</param> internal static void silk_encode_indices( SilkChannelEncoder psEncC, EntropyCoder psRangeEnc, int FrameIndex, int encode_LBRR, int condCoding) { int i, k, typeOffset; int encode_absolute_lagIndex, delta_lagIndex; short[] ec_ix = new short[SilkConstants.MAX_LPC_ORDER]; byte[] pred_Q8 = new byte[SilkConstants.MAX_LPC_ORDER]; SideInfoIndices psIndices; if (encode_LBRR != 0) { psIndices = psEncC.indices_LBRR[FrameIndex]; } else { psIndices = psEncC.indices; } /*******************************************/ /* Encode signal type and quantizer offset */ /*******************************************/ typeOffset = 2 * psIndices.signalType + psIndices.quantOffsetType; Inlines.OpusAssert(typeOffset >= 0 && typeOffset < 6); Inlines.OpusAssert(encode_LBRR == 0 || typeOffset >= 2); if (encode_LBRR != 0 || typeOffset >= 2) { psRangeEnc.enc_icdf(typeOffset - 2, Tables.silk_type_offset_VAD_iCDF, 8); } else { psRangeEnc.enc_icdf(typeOffset, Tables.silk_type_offset_no_VAD_iCDF, 8); } /****************/ /* Encode gains */ /****************/ /* first subframe */ if (condCoding == SilkConstants.CODE_CONDITIONALLY) { /* conditional coding */ Inlines.OpusAssert(psIndices.GainsIndices[0] >= 0 && psIndices.GainsIndices[0] < SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.MIN_DELTA_GAIN_QUANT + 1); psRangeEnc.enc_icdf(psIndices.GainsIndices[0], Tables.silk_delta_gain_iCDF, 8); } else { /* independent coding, in two stages: MSB bits followed by 3 LSBs */ Inlines.OpusAssert(psIndices.GainsIndices[0] >= 0 && psIndices.GainsIndices[0] < SilkConstants.N_LEVELS_QGAIN); psRangeEnc.enc_icdf(Inlines.silk_RSHIFT(psIndices.GainsIndices[0], 3), Tables.silk_gain_iCDF[psIndices.signalType], 8); psRangeEnc.enc_icdf(psIndices.GainsIndices[0] & 7, Tables.silk_uniform8_iCDF, 8); } /* remaining subframes */ for (i = 1; i < psEncC.nb_subfr; i++) { Inlines.OpusAssert(psIndices.GainsIndices[i] >= 0 && psIndices.GainsIndices[i] < SilkConstants.MAX_DELTA_GAIN_QUANT - SilkConstants.MIN_DELTA_GAIN_QUANT + 1); psRangeEnc.enc_icdf(psIndices.GainsIndices[i], Tables.silk_delta_gain_iCDF, 8); } /****************/ /* Encode NLSFs */ /****************/ psRangeEnc.enc_icdf(psIndices.NLSFIndices[0], psEncC.psNLSF_CB.CB1_iCDF, ((psIndices.signalType >> 1) * psEncC.psNLSF_CB.nVectors), 8); NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psEncC.psNLSF_CB, psIndices.NLSFIndices[0]); Inlines.OpusAssert(psEncC.psNLSF_CB.order == psEncC.predictLPCOrder); for (i = 0; i < psEncC.psNLSF_CB.order; i++) { if (psIndices.NLSFIndices[i + 1] >= SilkConstants.NLSF_QUANT_MAX_AMPLITUDE) { psRangeEnc.enc_icdf(2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, psEncC.psNLSF_CB.ec_iCDF, (ec_ix[i]), 8); psRangeEnc.enc_icdf(psIndices.NLSFIndices[i + 1] - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, Tables.silk_NLSF_EXT_iCDF, 8); } else if (psIndices.NLSFIndices[i + 1] <= 0 - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE) { psRangeEnc.enc_icdf(0, psEncC.psNLSF_CB.ec_iCDF, ec_ix[i], 8); psRangeEnc.enc_icdf(-psIndices.NLSFIndices[i + 1] - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, Tables.silk_NLSF_EXT_iCDF, 8); } else { psRangeEnc.enc_icdf(psIndices.NLSFIndices[i + 1] + SilkConstants.NLSF_QUANT_MAX_AMPLITUDE, psEncC.psNLSF_CB.ec_iCDF, ec_ix[i], 8); } } /* Encode NLSF interpolation factor */ if (psEncC.nb_subfr == SilkConstants.MAX_NB_SUBFR) { Inlines.OpusAssert(psIndices.NLSFInterpCoef_Q2 >= 0 && psIndices.NLSFInterpCoef_Q2 < 5); psRangeEnc.enc_icdf(psIndices.NLSFInterpCoef_Q2, Tables.silk_NLSF_interpolation_factor_iCDF, 8); } if (psIndices.signalType == SilkConstants.TYPE_VOICED) { /*********************/ /* Encode pitch lags */ /*********************/ /* lag index */ encode_absolute_lagIndex = 1; if (condCoding == SilkConstants.CODE_CONDITIONALLY && psEncC.ec_prevSignalType == SilkConstants.TYPE_VOICED) { /* Delta Encoding */ delta_lagIndex = psIndices.lagIndex - psEncC.ec_prevLagIndex; if (delta_lagIndex < -8 || delta_lagIndex > 11) { delta_lagIndex = 0; } else { delta_lagIndex = delta_lagIndex + 9; encode_absolute_lagIndex = 0; /* Only use delta */ } Inlines.OpusAssert(delta_lagIndex >= 0 && delta_lagIndex < 21); psRangeEnc.enc_icdf(delta_lagIndex, Tables.silk_pitch_delta_iCDF, 8); } if (encode_absolute_lagIndex != 0) { /* Absolute encoding */ int pitch_high_bits, pitch_low_bits; pitch_high_bits = Inlines.silk_DIV32_16(psIndices.lagIndex, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1)); pitch_low_bits = psIndices.lagIndex - Inlines.silk_SMULBB(pitch_high_bits, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1)); Inlines.OpusAssert(pitch_low_bits < psEncC.fs_kHz / 2); Inlines.OpusAssert(pitch_high_bits < 32); psRangeEnc.enc_icdf(pitch_high_bits, Tables.silk_pitch_lag_iCDF, 8); psRangeEnc.enc_icdf(pitch_low_bits, psEncC.pitch_lag_low_bits_iCDF, 8); } psEncC.ec_prevLagIndex = psIndices.lagIndex; /* Countour index */ Inlines.OpusAssert(psIndices.contourIndex >= 0); Inlines.OpusAssert((psIndices.contourIndex < 34 && psEncC.fs_kHz > 8 && psEncC.nb_subfr == 4) || (psIndices.contourIndex < 11 && psEncC.fs_kHz == 8 && psEncC.nb_subfr == 4) || (psIndices.contourIndex < 12 && psEncC.fs_kHz > 8 && psEncC.nb_subfr == 2) || (psIndices.contourIndex < 3 && psEncC.fs_kHz == 8 && psEncC.nb_subfr == 2)); psRangeEnc.enc_icdf(psIndices.contourIndex, psEncC.pitch_contour_iCDF, 8); /********************/ /* Encode LTP gains */ /********************/ /* PERIndex value */ Inlines.OpusAssert(psIndices.PERIndex >= 0 && psIndices.PERIndex < 3); psRangeEnc.enc_icdf(psIndices.PERIndex, Tables.silk_LTP_per_index_iCDF, 8); /* Codebook Indices */ for (k = 0; k < psEncC.nb_subfr; k++) { Inlines.OpusAssert(psIndices.LTPIndex[k] >= 0 && psIndices.LTPIndex[k] < (8 << psIndices.PERIndex)); psRangeEnc.enc_icdf(psIndices.LTPIndex[k], Tables.silk_LTP_gain_iCDF_ptrs[psIndices.PERIndex], 8); } /**********************/ /* Encode LTP scaling */ /**********************/ if (condCoding == SilkConstants.CODE_INDEPENDENTLY) { Inlines.OpusAssert(psIndices.LTP_scaleIndex >= 0 && psIndices.LTP_scaleIndex < 3); psRangeEnc.enc_icdf(psIndices.LTP_scaleIndex, Tables.silk_LTPscale_iCDF, 8); } Inlines.OpusAssert(condCoding == 0 || psIndices.LTP_scaleIndex == 0); } psEncC.ec_prevSignalType = psIndices.signalType; /***************/ /* Encode seed */ /***************/ Inlines.OpusAssert(psIndices.Seed >= 0 && psIndices.Seed < 4); psRangeEnc.enc_icdf(psIndices.Seed, Tables.silk_uniform4_iCDF, 8); }
internal static void silk_find_pred_coefs( SilkChannelEncoder psEnc, /* I/O encoder state */ SilkEncoderControl psEncCtrl, /* I/O encoder control */ short[] res_pitch, /* I Residual from pitch analysis */ short[] x, /* I Speech signal */ int x_ptr, int condCoding /* I The type of conditional coding to use */ ) { int i; int[] invGains_Q16 = new int[SilkConstants.MAX_NB_SUBFR]; int[] local_gains = new int[SilkConstants.MAX_NB_SUBFR]; int[] Wght_Q15 = new int[SilkConstants.MAX_NB_SUBFR]; short[] NLSF_Q15 = new short[SilkConstants.MAX_LPC_ORDER]; int x_ptr2; int x_pre_ptr; short[] LPC_in_pre; int tmp, min_gain_Q16, minInvGain_Q30; int[] LTP_corrs_rshift = new int[SilkConstants.MAX_NB_SUBFR]; /* weighting for weighted least squares */ min_gain_Q16 = int.MaxValue >> 6; for (i = 0; i < psEnc.nb_subfr; i++) { min_gain_Q16 = Inlines.silk_min(min_gain_Q16, psEncCtrl.Gains_Q16[i]); } for (i = 0; i < psEnc.nb_subfr; i++) { /* Divide to Q16 */ Inlines.OpusAssert(psEncCtrl.Gains_Q16[i] > 0); /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */ invGains_Q16[i] = Inlines.silk_DIV32_varQ(min_gain_Q16, psEncCtrl.Gains_Q16[i], 16 - 2); /* Ensure Wght_Q15 a minimum value 1 */ invGains_Q16[i] = Inlines.silk_max(invGains_Q16[i], 363); /* Square the inverted gains */ Inlines.OpusAssert(invGains_Q16[i] == Inlines.silk_SAT16(invGains_Q16[i])); tmp = Inlines.silk_SMULWB(invGains_Q16[i], invGains_Q16[i]); Wght_Q15[i] = Inlines.silk_RSHIFT(tmp, 1); /* Invert the inverted and normalized gains */ local_gains[i] = Inlines.silk_DIV32(((int)1 << 16), invGains_Q16[i]); } LPC_in_pre = new short[psEnc.nb_subfr * psEnc.predictLPCOrder + psEnc.frame_length]; if (psEnc.indices.signalType == SilkConstants.TYPE_VOICED) { int[] WLTP; /**********/ /* VOICED */ /**********/ Inlines.OpusAssert(psEnc.ltp_mem_length - psEnc.predictLPCOrder >= psEncCtrl.pitchL[0] + SilkConstants.LTP_ORDER / 2); WLTP = new int[psEnc.nb_subfr * SilkConstants.LTP_ORDER * SilkConstants.LTP_ORDER]; /* LTP analysis */ BoxedValueInt boxed_codgain = new BoxedValueInt(psEncCtrl.LTPredCodGain_Q7); FindLTP.silk_find_LTP(psEncCtrl.LTPCoef_Q14, WLTP, boxed_codgain, res_pitch, psEncCtrl.pitchL, Wght_Q15, psEnc.subfr_length, psEnc.nb_subfr, psEnc.ltp_mem_length, LTP_corrs_rshift); psEncCtrl.LTPredCodGain_Q7 = boxed_codgain.Val; /* Quantize LTP gain parameters */ BoxedValueSbyte boxed_periodicity = new BoxedValueSbyte(psEnc.indices.PERIndex); BoxedValueInt boxed_gain = new BoxedValueInt(psEnc.sum_log_gain_Q7); QuantizeLTPGains.silk_quant_LTP_gains(psEncCtrl.LTPCoef_Q14, psEnc.indices.LTPIndex, boxed_periodicity, boxed_gain, WLTP, psEnc.mu_LTP_Q9, psEnc.LTPQuantLowComplexity, psEnc.nb_subfr ); psEnc.indices.PERIndex = boxed_periodicity.Val; psEnc.sum_log_gain_Q7 = boxed_gain.Val; /* Control LTP scaling */ LTPScaleControl.silk_LTP_scale_ctrl(psEnc, psEncCtrl, condCoding); /* Create LTP residual */ LTPAnalysisFilter.silk_LTP_analysis_filter(LPC_in_pre, x, x_ptr - psEnc.predictLPCOrder, psEncCtrl.LTPCoef_Q14, psEncCtrl.pitchL, invGains_Q16, psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder); } else { /************/ /* UNVOICED */ /************/ /* Create signal with prepended subframes, scaled by inverse gains */ x_ptr2 = x_ptr - psEnc.predictLPCOrder; x_pre_ptr = 0; for (i = 0; i < psEnc.nb_subfr; i++) { Inlines.silk_scale_copy_vector16(LPC_in_pre, x_pre_ptr, x, x_ptr2, invGains_Q16[i], psEnc.subfr_length + psEnc.predictLPCOrder); x_pre_ptr += psEnc.subfr_length + psEnc.predictLPCOrder; x_ptr2 += psEnc.subfr_length; } Arrays.MemSetShort(psEncCtrl.LTPCoef_Q14, 0, psEnc.nb_subfr * SilkConstants.LTP_ORDER); psEncCtrl.LTPredCodGain_Q7 = 0; psEnc.sum_log_gain_Q7 = 0; } /* Limit on total predictive coding gain */ if (psEnc.first_frame_after_reset != 0) { minInvGain_Q30 = ((int)((1.0f / SilkConstants.MAX_PREDICTION_POWER_GAIN_AFTER_RESET) * ((long)1 << (30)) + 0.5)) /*Inlines.SILK_CONST(1.0f / SilkConstants.MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30)*/; } else { minInvGain_Q30 = Inlines.silk_log2lin(Inlines.silk_SMLAWB(16 << 7, (int)psEncCtrl.LTPredCodGain_Q7, ((int)((1.0f / 3f) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(1.0f / 3f, 16)*/)); /* Q16 */ minInvGain_Q30 = Inlines.silk_DIV32_varQ(minInvGain_Q30, Inlines.silk_SMULWW(((int)((SilkConstants.MAX_PREDICTION_POWER_GAIN) * ((long)1 << (0)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.MAX_PREDICTION_POWER_GAIN, 0)*/, Inlines.silk_SMLAWB(((int)((0.25f) * ((long)1 << (18)) + 0.5)) /*Inlines.SILK_CONST(0.25f, 18)*/, ((int)((0.75f) * ((long)1 << (18)) + 0.5)) /*Inlines.SILK_CONST(0.75f, 18)*/, psEncCtrl.coding_quality_Q14)), 14); } /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ FindLPC.silk_find_LPC(psEnc, NLSF_Q15, LPC_in_pre, minInvGain_Q30); /* Quantize LSFs */ NLSF.silk_process_NLSFs(psEnc, psEncCtrl.PredCoef_Q12, NLSF_Q15, psEnc.prev_NLSFq_Q15); /* Calculate residual energy using quantized LPC coefficients */ ResidualEnergy.silk_residual_energy(psEncCtrl.ResNrg, psEncCtrl.ResNrgQ, LPC_in_pre, psEncCtrl.PredCoef_Q12, local_gains, psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder); /* Copy to prediction struct for use in next frame for interpolation */ Array.Copy(NLSF_Q15, psEnc.prev_NLSFq_Q15, SilkConstants.MAX_LPC_ORDER); }
/* Decode side-information parameters from payload */ internal static void silk_decode_indices( SilkChannelDecoder psDec, /* I/O State */ EntropyCoder psRangeDec, /* I/O Compressor data structure */ int FrameIndex, /* I Frame number */ int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ int condCoding /* I The type of conditional coding to use */ ) { int i, k, Ix; int decode_absolute_lagIndex, delta_lagIndex; short[] ec_ix = new short[psDec.LPC_order]; byte[] pred_Q8 = new byte[psDec.LPC_order]; /*******************************************/ /* Decode signal type and quantizer offset */ /*******************************************/ if (decode_LBRR != 0 || psDec.VAD_flags[FrameIndex] != 0) { Ix = psRangeDec.dec_icdf(Tables.silk_type_offset_VAD_iCDF, 8) + 2; } else { Ix = psRangeDec.dec_icdf(Tables.silk_type_offset_no_VAD_iCDF, 8); } psDec.indices.signalType = (sbyte)Inlines.silk_RSHIFT(Ix, 1); psDec.indices.quantOffsetType = (sbyte)(Ix & 1); /****************/ /* Decode gains */ /****************/ /* First subframe */ if (condCoding == SilkConstants.CODE_CONDITIONALLY) { /* Conditional coding */ psDec.indices.GainsIndices[0] = (sbyte)psRangeDec.dec_icdf(Tables.silk_delta_gain_iCDF, 8); } else { /* Independent coding, in two stages: MSB bits followed by 3 LSBs */ psDec.indices.GainsIndices[0] = (sbyte)Inlines.silk_LSHIFT(psRangeDec.dec_icdf(Tables.silk_gain_iCDF[psDec.indices.signalType], 8), 3); psDec.indices.GainsIndices[0] += (sbyte)psRangeDec.dec_icdf(Tables.silk_uniform8_iCDF, 8); } /* Remaining subframes */ for (i = 1; i < psDec.nb_subfr; i++) { psDec.indices.GainsIndices[i] = (sbyte)psRangeDec.dec_icdf(Tables.silk_delta_gain_iCDF, 8); } /**********************/ /* Decode LSF Indices */ /**********************/ psDec.indices.NLSFIndices[0] = (sbyte)psRangeDec.dec_icdf(psDec.psNLSF_CB.CB1_iCDF, (psDec.indices.signalType >> 1) * psDec.psNLSF_CB.nVectors, 8); NLSF.silk_NLSF_unpack(ec_ix, pred_Q8, psDec.psNLSF_CB, psDec.indices.NLSFIndices[0]); Inlines.OpusAssert(psDec.psNLSF_CB.order == psDec.LPC_order); for (i = 0; i < psDec.psNLSF_CB.order; i++) { Ix = psRangeDec.dec_icdf(psDec.psNLSF_CB.ec_iCDF, (ec_ix[i]), 8); if (Ix == 0) { Ix -= psRangeDec.dec_icdf(Tables.silk_NLSF_EXT_iCDF, 8); } else if (Ix == 2 * SilkConstants.NLSF_QUANT_MAX_AMPLITUDE) { Ix += psRangeDec.dec_icdf(Tables.silk_NLSF_EXT_iCDF, 8); } psDec.indices.NLSFIndices[i + 1] = (sbyte)(Ix - SilkConstants.NLSF_QUANT_MAX_AMPLITUDE); } /* Decode LSF interpolation factor */ if (psDec.nb_subfr == SilkConstants.MAX_NB_SUBFR) { psDec.indices.NLSFInterpCoef_Q2 = (sbyte)psRangeDec.dec_icdf(Tables.silk_NLSF_interpolation_factor_iCDF, 8); } else { psDec.indices.NLSFInterpCoef_Q2 = 4; } if (psDec.indices.signalType == SilkConstants.TYPE_VOICED) { /*********************/ /* Decode pitch lags */ /*********************/ /* Get lag index */ decode_absolute_lagIndex = 1; if (condCoding == SilkConstants.CODE_CONDITIONALLY && psDec.ec_prevSignalType == SilkConstants.TYPE_VOICED) { /* Decode Delta index */ delta_lagIndex = (short)psRangeDec.dec_icdf(Tables.silk_pitch_delta_iCDF, 8); if (delta_lagIndex > 0) { delta_lagIndex = delta_lagIndex - 9; psDec.indices.lagIndex = (short)(psDec.ec_prevLagIndex + delta_lagIndex); decode_absolute_lagIndex = 0; } } if (decode_absolute_lagIndex != 0) { /* Absolute decoding */ psDec.indices.lagIndex = (short)(psRangeDec.dec_icdf(Tables.silk_pitch_lag_iCDF, 8) * Inlines.silk_RSHIFT(psDec.fs_kHz, 1)); psDec.indices.lagIndex += (short)psRangeDec.dec_icdf(psDec.pitch_lag_low_bits_iCDF, 8); } psDec.ec_prevLagIndex = psDec.indices.lagIndex; /* Get countour index */ psDec.indices.contourIndex = (sbyte)psRangeDec.dec_icdf(psDec.pitch_contour_iCDF, 8); /********************/ /* Decode LTP gains */ /********************/ /* Decode PERIndex value */ psDec.indices.PERIndex = (sbyte)psRangeDec.dec_icdf(Tables.silk_LTP_per_index_iCDF, 8); for (k = 0; k < psDec.nb_subfr; k++) { psDec.indices.LTPIndex[k] = (sbyte)psRangeDec.dec_icdf(Tables.silk_LTP_gain_iCDF_ptrs[psDec.indices.PERIndex], 8); } /**********************/ /* Decode LTP scaling */ /**********************/ if (condCoding == SilkConstants.CODE_INDEPENDENTLY) { psDec.indices.LTP_scaleIndex = (sbyte)psRangeDec.dec_icdf(Tables.silk_LTPscale_iCDF, 8); } else { psDec.indices.LTP_scaleIndex = 0; } } psDec.ec_prevSignalType = psDec.indices.signalType; /***************/ /* Decode seed */ /***************/ psDec.indices.Seed = (sbyte)psRangeDec.dec_icdf(Tables.silk_uniform4_iCDF, 8); }