/* Compute reflection coefficients from input signal */ internal static void silk_burg_modified( BoxedValueInt res_nrg, /* O Residual energy */ BoxedValueInt res_nrg_Q, /* O Residual energy Q value */ int[] A_Q16, /* O Prediction coefficients (length order) */ short[] x, /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ int x_ptr, int minInvGain_Q30, /* I Inverse of max prediction gain */ int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ int nb_subfr, /* I Number of subframes stacked in x */ int D /* I Order */ ) { int k, n, s, lz, rshifts, reached_max_gain; int C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; int x_offset; int[] C_first_row = new int[SilkConstants.SILK_MAX_ORDER_LPC]; int[] C_last_row = new int[SilkConstants.SILK_MAX_ORDER_LPC]; int[] Af_QA = new int[SilkConstants.SILK_MAX_ORDER_LPC]; int[] CAf = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1]; int[] CAb = new int[SilkConstants.SILK_MAX_ORDER_LPC + 1]; int[] xcorr = new int[SilkConstants.SILK_MAX_ORDER_LPC]; long C0_64; Inlines.OpusAssert(subfr_length * nb_subfr <= MAX_FRAME_SIZE); /* Compute autocorrelations, added over subframes */ C0_64 = Inlines.silk_inner_prod16_aligned_64(x, x_ptr, x, x_ptr, subfr_length * nb_subfr); lz = Inlines.silk_CLZ64(C0_64); rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz; if (rshifts > MAX_RSHIFTS) { rshifts = MAX_RSHIFTS; } if (rshifts < MIN_RSHIFTS) { rshifts = MIN_RSHIFTS; } if (rshifts > 0) { C0 = (int)Inlines.silk_RSHIFT64(C0_64, rshifts); } else { C0 = Inlines.silk_LSHIFT32((int)C0_64, -rshifts); } CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */ Arrays.MemSetInt(C_first_row, 0, SilkConstants.SILK_MAX_ORDER_LPC); if (rshifts > 0) { for (s = 0; s < nb_subfr; s++) { x_offset = x_ptr + s * subfr_length; for (n = 1; n < D + 1; n++) { C_first_row[n - 1] += (int)Inlines.silk_RSHIFT64( Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset + n, subfr_length - n), rshifts); } } } else { for (s = 0; s < nb_subfr; s++) { int i; int d; x_offset = x_ptr + s * subfr_length; CeltPitchXCorr.pitch_xcorr(x, x_offset, x, x_offset + 1, xcorr, subfr_length - D, D); for (n = 1; n < D + 1; n++) { for (i = n + subfr_length - D, d = 0; i < subfr_length; i++) { d = Inlines.MAC16_16(d, x[x_offset + i], x[x_offset + i - n]); } xcorr[n - 1] += d; } for (n = 1; n < D + 1; n++) { C_first_row[n - 1] += Inlines.silk_LSHIFT32(xcorr[n - 1], -rshifts); } } } Array.Copy(C_first_row, C_last_row, SilkConstants.SILK_MAX_ORDER_LPC); /* Initialize */ CAb[0] = CAf[0] = C0 + Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0) + 1; /* Q(-rshifts) */ invGain_Q30 = (int)1 << 30; reached_max_gain = 0; for (n = 0; n < D; n++) { /* Update first row of correlation matrix (without first element) */ /* Update last row of correlation matrix (without last element, stored in reversed order) */ /* Update C * Af */ /* Update C * flipud(Af) (stored in reversed order) */ if (rshifts > -2) { for (s = 0; s < nb_subfr; s++) { x_offset = x_ptr + s * subfr_length; x1 = -Inlines.silk_LSHIFT32((int)x[x_offset + n], 16 - rshifts); /* Q(16-rshifts) */ x2 = -Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], 16 - rshifts); /* Q(16-rshifts) */ tmp1 = Inlines.silk_LSHIFT32((int)x[x_offset + n], QA - 16); /* Q(QA-16) */ tmp2 = Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], QA - 16); /* Q(QA-16) */ for (k = 0; k < n; k++) { C_first_row[k] = Inlines.silk_SMLAWB(C_first_row[k], x1, x[x_offset + n - k - 1]); /* Q( -rshifts ) */ C_last_row[k] = Inlines.silk_SMLAWB(C_last_row[k], x2, x[x_offset + subfr_length - n + k]); /* Q( -rshifts ) */ Atmp_QA = Af_QA[k]; tmp1 = Inlines.silk_SMLAWB(tmp1, Atmp_QA, x[x_offset + n - k - 1]); /* Q(QA-16) */ tmp2 = Inlines.silk_SMLAWB(tmp2, Atmp_QA, x[x_offset + subfr_length - n + k]); /* Q(QA-16) */ } tmp1 = Inlines.silk_LSHIFT32(-tmp1, 32 - QA - rshifts); /* Q(16-rshifts) */ tmp2 = Inlines.silk_LSHIFT32(-tmp2, 32 - QA - rshifts); /* Q(16-rshifts) */ for (k = 0; k <= n; k++) { CAf[k] = Inlines.silk_SMLAWB(CAf[k], tmp1, x[x_offset + n - k]); /* Q( -rshift ) */ CAb[k] = Inlines.silk_SMLAWB(CAb[k], tmp2, x[x_offset + subfr_length - n + k - 1]); /* Q( -rshift ) */ } } } else { for (s = 0; s < nb_subfr; s++) { x_offset = x_ptr + s * subfr_length; x1 = -Inlines.silk_LSHIFT32((int)x[x_offset + n], -rshifts); /* Q( -rshifts ) */ x2 = -Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], -rshifts); /* Q( -rshifts ) */ tmp1 = Inlines.silk_LSHIFT32((int)x[x_offset + n], 17); /* Q17 */ tmp2 = Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n - 1], 17); /* Q17 */ for (k = 0; k < n; k++) { C_first_row[k] = Inlines.silk_MLA(C_first_row[k], x1, x[x_offset + n - k - 1]); /* Q( -rshifts ) */ C_last_row[k] = Inlines.silk_MLA(C_last_row[k], x2, x[x_offset + subfr_length - n + k]); /* Q( -rshifts ) */ Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 17); /* Q17 */ tmp1 = Inlines.silk_MLA(tmp1, x[x_offset + n - k - 1], Atmp1); /* Q17 */ tmp2 = Inlines.silk_MLA(tmp2, x[x_offset + subfr_length - n + k], Atmp1); /* Q17 */ } tmp1 = -tmp1; /* Q17 */ tmp2 = -tmp2; /* Q17 */ for (k = 0; k <= n; k++) { CAf[k] = Inlines.silk_SMLAWW(CAf[k], tmp1, Inlines.silk_LSHIFT32((int)x[x_offset + n - k], -rshifts - 1)); /* Q( -rshift ) */ CAb[k] = Inlines.silk_SMLAWW(CAb[k], tmp2, Inlines.silk_LSHIFT32((int)x[x_offset + subfr_length - n + k - 1], -rshifts - 1)); /* Q( -rshift ) */ } } } /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ tmp1 = C_first_row[n]; /* Q( -rshifts ) */ tmp2 = C_last_row[n]; /* Q( -rshifts ) */ num = 0; /* Q( -rshifts ) */ nrg = Inlines.silk_ADD32(CAb[0], CAf[0]); /* Q( 1-rshifts ) */ for (k = 0; k < n; k++) { Atmp_QA = Af_QA[k]; lz = Inlines.silk_CLZ32(Inlines.silk_abs(Atmp_QA)) - 1; lz = Inlines.silk_min(32 - QA, lz); Atmp1 = Inlines.silk_LSHIFT32(Atmp_QA, lz); /* Q( QA + lz ) */ tmp1 = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(C_last_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */ tmp2 = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(C_first_row[n - k - 1], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */ num = Inlines.silk_ADD_LSHIFT32(num, Inlines.silk_SMMUL(CAb[n - k], Atmp1), 32 - QA - lz); /* Q( -rshifts ) */ nrg = Inlines.silk_ADD_LSHIFT32(nrg, Inlines.silk_SMMUL(Inlines.silk_ADD32(CAb[k + 1], CAf[k + 1]), Atmp1), 32 - QA - lz); /* Q( 1-rshifts ) */ } CAf[n + 1] = tmp1; /* Q( -rshifts ) */ CAb[n + 1] = tmp2; /* Q( -rshifts ) */ num = Inlines.silk_ADD32(num, tmp2); /* Q( -rshifts ) */ num = Inlines.silk_LSHIFT32(-num, 1); /* Q( 1-rshifts ) */ /* Calculate the next order reflection (parcor) coefficient */ if (Inlines.silk_abs(num) < nrg) { rc_Q31 = Inlines.silk_DIV32_varQ(num, nrg, 31); } else { rc_Q31 = (num > 0) ? int.MaxValue : int.MinValue; } /* Update inverse prediction gain */ tmp1 = ((int)1 << 30) - Inlines.silk_SMMUL(rc_Q31, rc_Q31); tmp1 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, tmp1), 2); if (tmp1 <= minInvGain_Q30) { /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ tmp2 = ((int)1 << 30) - Inlines.silk_DIV32_varQ(minInvGain_Q30, invGain_Q30, 30); /* Q30 */ rc_Q31 = Inlines.silk_SQRT_APPROX(tmp2); /* Q15 */ /* Newton-Raphson iteration */ rc_Q31 = Inlines.silk_RSHIFT32(rc_Q31 + Inlines.silk_DIV32(tmp2, rc_Q31), 1); /* Q15 */ rc_Q31 = Inlines.silk_LSHIFT32(rc_Q31, 16); /* Q31 */ if (num < 0) { /* Ensure adjusted reflection coefficients has the original sign */ rc_Q31 = -rc_Q31; } invGain_Q30 = minInvGain_Q30; reached_max_gain = 1; } else { invGain_Q30 = tmp1; } /* Update the AR coefficients */ for (k = 0; k < (n + 1) >> 1; k++) { tmp1 = Af_QA[k]; /* QA */ tmp2 = Af_QA[n - k - 1]; /* QA */ Af_QA[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* QA */ Af_QA[n - k - 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* QA */ } Af_QA[n] = Inlines.silk_RSHIFT32(rc_Q31, 31 - QA); /* QA */ if (reached_max_gain != 0) { /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ for (k = n + 1; k < D; k++) { Af_QA[k] = 0; } break; } /* Update C * Af and C * Ab */ for (k = 0; k <= n + 1; k++) { tmp1 = CAf[k]; /* Q( -rshifts ) */ tmp2 = CAb[n - k + 1]; /* Q( -rshifts ) */ CAf[k] = Inlines.silk_ADD_LSHIFT32(tmp1, Inlines.silk_SMMUL(tmp2, rc_Q31), 1); /* Q( -rshifts ) */ CAb[n - k + 1] = Inlines.silk_ADD_LSHIFT32(tmp2, Inlines.silk_SMMUL(tmp1, rc_Q31), 1); /* Q( -rshifts ) */ } } if (reached_max_gain != 0) { for (k = 0; k < D; k++) { /* Scale coefficients */ A_Q16[k] = -Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16); } /* Subtract energy of preceding samples from C0 */ if (rshifts > 0) { for (s = 0; s < nb_subfr; s++) { x_offset = x_ptr + s * subfr_length; C0 -= (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, x_offset, x, x_offset, D), rshifts); } } else { for (s = 0; s < nb_subfr; s++) { x_offset = x_ptr + s * subfr_length; C0 -= Inlines.silk_LSHIFT32(Inlines.silk_inner_prod_self(x, x_offset, D), -rshifts); } } /* Approximate residual energy */ res_nrg.Val = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(invGain_Q30, C0), 2); res_nrg_Q.Val = 0 - rshifts; } else { /* Return residual energy */ nrg = CAf[0]; /* Q( -rshifts ) */ tmp1 = (int)1 << 16; /* Q16 */ for (k = 0; k < D; k++) { Atmp1 = Inlines.silk_RSHIFT_ROUND(Af_QA[k], QA - 16); /* Q16 */ nrg = Inlines.silk_SMLAWW(nrg, CAf[k + 1], Atmp1); /* Q( -rshifts ) */ tmp1 = Inlines.silk_SMLAWW(tmp1, Atmp1, Atmp1); /* Q16 */ A_Q16[k] = -Atmp1; } res_nrg.Val = Inlines.silk_SMLAWW(nrg, Inlines.silk_SMMUL(((int)((TuningParameters.FIND_LPC_COND_FAC) * ((long)1 << (32)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.FIND_LPC_COND_FAC, 32)*/, C0), -tmp1);/* Q( -rshifts ) */ res_nrg_Q.Val = -rshifts; } }
/*************************************************************/ /* FIXED POINT CORE PITCH ANALYSIS FUNCTION */ /*************************************************************/ internal static int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ short[] frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ int[] pitch_out, /* O 4 pitch lag values */ BoxedValueShort lagIndex, /* O Lag Index */ BoxedValueSbyte contourIndex, /* O Pitch contour Index */ BoxedValueInt LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ int search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */ int Fs_kHz, /* I Sample frequency (kHz) */ int complexity, /* I Complexity setting, 0-2, where 2 is highest */ int nb_subfr /* I number of 5 ms subframes */ ) { short[] frame_8kHz; short[] frame_4kHz; int[] filt_state = new int[6]; short[] input_frame_ptr; int i, k, d, j; short[] C; int[] xcorr32; short[] basis; int basis_ptr; short[] target; int target_ptr; int cross_corr, normalizer, energy, shift, energy_basis, energy_target; int Cmax, length_d_srch, length_d_comp; int[] d_srch = new int[SilkConstants.PE_D_SRCH_LENGTH]; short[] d_comp; int sum, threshold, lag_counter; int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new; int CCmax, CCmax_b, CCmax_new_b, CCmax_new; int[] CC = new int[SilkConstants.PE_NB_CBKS_STAGE2_EXT]; silk_pe_stage3_vals[] energies_st3; silk_pe_stage3_vals[] cross_corr_st3; int frame_length, frame_length_8kHz, frame_length_4kHz; int sf_length; int min_lag; int max_lag; int contour_bias_Q15, diff; int nb_cbk_search; int delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13; sbyte[][] Lag_CB_ptr; /* Check for valid sampling frequency */ Inlines.OpusAssert(Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16); /* Check for valid complexity setting */ Inlines.OpusAssert(complexity >= SilkConstants.SILK_PE_MIN_COMPLEX); Inlines.OpusAssert(complexity <= SilkConstants.SILK_PE_MAX_COMPLEX); Inlines.OpusAssert(search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1 << 16)); Inlines.OpusAssert(search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1 << 13)); /* Set up frame lengths max / min lag for the sampling frequency */ frame_length = (SilkConstants.PE_LTP_MEM_LENGTH_MS + nb_subfr * SilkConstants.PE_SUBFR_LENGTH_MS) * Fs_kHz; frame_length_4kHz = (SilkConstants.PE_LTP_MEM_LENGTH_MS + nb_subfr * SilkConstants.PE_SUBFR_LENGTH_MS) * 4; frame_length_8kHz = (SilkConstants.PE_LTP_MEM_LENGTH_MS + nb_subfr * SilkConstants.PE_SUBFR_LENGTH_MS) * 8; sf_length = SilkConstants.PE_SUBFR_LENGTH_MS * Fs_kHz; min_lag = SilkConstants.PE_MIN_LAG_MS * Fs_kHz; max_lag = SilkConstants.PE_MAX_LAG_MS * Fs_kHz - 1; /* Resample from input sampled at Fs_kHz to 8 kHz */ frame_8kHz = new short[frame_length_8kHz]; if (Fs_kHz == 16) { Arrays.MemSetInt(filt_state, 0, 2); Resampler.silk_resampler_down2(filt_state, frame_8kHz, frame, frame_length); } else if (Fs_kHz == 12) { Arrays.MemSetInt(filt_state, 0, 6); Resampler.silk_resampler_down2_3(filt_state, frame_8kHz, frame, frame_length); } else { Inlines.OpusAssert(Fs_kHz == 8); Array.Copy(frame, frame_8kHz, frame_length_8kHz); } /* Decimate again to 4 kHz */ Arrays.MemSetInt(filt_state, 0, 2); /* Set state to zero */ frame_4kHz = new short[frame_length_4kHz]; Resampler.silk_resampler_down2(filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz); /* Low-pass filter */ for (i = frame_length_4kHz - 1; i > 0; i--) { frame_4kHz[i] = Inlines.silk_ADD_SAT16(frame_4kHz[i], frame_4kHz[i - 1]); } /******************************************************************************* ** Scale 4 kHz signal down to prevent correlations measures from overflowing ** find scaling as max scaling for each 8kHz(?) subframe *******************************************************************************/ /* Inner product is calculated with different lengths, so scale for the worst case */ SumSqrShift.silk_sum_sqr_shift(out energy, out shift, frame_4kHz, frame_length_4kHz); if (shift > 0) { shift = Inlines.silk_RSHIFT(shift, 1); for (i = 0; i < frame_length_4kHz; i++) { frame_4kHz[i] = Inlines.silk_RSHIFT16(frame_4kHz[i], shift); } } /****************************************************************************** * FIRST STAGE, operating in 4 khz ******************************************************************************/ C = new short[nb_subfr * CSTRIDE_8KHZ]; xcorr32 = new int[MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1]; Arrays.MemSetShort(C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ); target = frame_4kHz; target_ptr = Inlines.silk_LSHIFT(SF_LENGTH_4KHZ, 2); for (k = 0; k < nb_subfr >> 1; k++) { basis = target; basis_ptr = target_ptr - MIN_LAG_4KHZ; CeltPitchXCorr.pitch_xcorr(target, target_ptr, target, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1); /* Calculate first vector products before loop */ cross_corr = xcorr32[MAX_LAG_4KHZ - MIN_LAG_4KHZ]; normalizer = Inlines.silk_inner_prod_self(target, target_ptr, SF_LENGTH_8KHZ); normalizer = Inlines.silk_ADD32(normalizer, Inlines.silk_inner_prod_self(basis, basis_ptr, SF_LENGTH_8KHZ)); normalizer = Inlines.silk_ADD32(normalizer, Inlines.silk_SMULBB(SF_LENGTH_8KHZ, 4000)); Inlines.MatrixSet(C, k, 0, CSTRIDE_4KHZ, (short)Inlines.silk_DIV32_varQ(cross_corr, normalizer, 13 + 1)); /* Q13 */ /* From now on normalizer is computed recursively */ for (d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++) { basis_ptr--; cross_corr = xcorr32[MAX_LAG_4KHZ - d]; /* Add contribution of new sample and remove contribution from oldest sample */ normalizer = Inlines.silk_ADD32(normalizer, Inlines.silk_SMULBB(basis[basis_ptr], basis[basis_ptr]) - Inlines.silk_SMULBB(basis[basis_ptr + SF_LENGTH_8KHZ], basis[basis_ptr + SF_LENGTH_8KHZ])); Inlines.MatrixSet(C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ, (short)Inlines.silk_DIV32_varQ(cross_corr, normalizer, 13 + 1)); /* Q13 */ } /* Update target pointer */ target_ptr += SF_LENGTH_8KHZ; } /* Combine two subframes into single correlation measure and apply short-lag bias */ if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR) { for (i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i--) { sum = (int)Inlines.MatrixGet(C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ) + (int)Inlines.MatrixGet(C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ); /* Q14 */ sum = Inlines.silk_SMLAWB(sum, sum, Inlines.silk_LSHIFT(-i, 4)); /* Q14 */ C[i - MIN_LAG_4KHZ] = (short)sum; /* Q14 */ } } else { /* Only short-lag bias */ for (i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i--) { sum = Inlines.silk_LSHIFT((int)C[i - MIN_LAG_4KHZ], 1); /* Q14 */ sum = Inlines.silk_SMLAWB(sum, sum, Inlines.silk_LSHIFT(-i, 4)); /* Q14 */ C[i - MIN_LAG_4KHZ] = (short)sum; /* Q14 */ } } /* Sort */ length_d_srch = Inlines.silk_ADD_LSHIFT32(4, complexity, 1); Inlines.OpusAssert(3 * length_d_srch <= SilkConstants.PE_D_SRCH_LENGTH); Sort.silk_insertion_sort_decreasing_int16(C, d_srch, CSTRIDE_4KHZ, length_d_srch); /* Escape if correlation is very low already here */ Cmax = (int)C[0]; /* Q14 */ if (Cmax < ((int)((0.2f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(0.2f, 14)*/) { Arrays.MemSetInt(pitch_out, 0, nb_subfr); LTPCorr_Q15.Val = 0; lagIndex.Val = 0; contourIndex.Val = 0; return(1); } threshold = Inlines.silk_SMULWB(search_thres1_Q16, Cmax); for (i = 0; i < length_d_srch; i++) { /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ if (C[i] > threshold) { d_srch[i] = Inlines.silk_LSHIFT(d_srch[i] + MIN_LAG_4KHZ, 1); } else { length_d_srch = i; break; } } Inlines.OpusAssert(length_d_srch > 0); d_comp = new short[D_COMP_STRIDE]; for (i = D_COMP_MIN; i < D_COMP_MAX; i++) { d_comp[i - D_COMP_MIN] = 0; } for (i = 0; i < length_d_srch; i++) { d_comp[d_srch[i] - D_COMP_MIN] = 1; } /* Convolution */ for (i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i--) { d_comp[i - D_COMP_MIN] += (short)(d_comp[i - 1 - D_COMP_MIN] + d_comp[i - 2 - D_COMP_MIN]); } length_d_srch = 0; for (i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++) { if (d_comp[i + 1 - D_COMP_MIN] > 0) { d_srch[length_d_srch] = i; length_d_srch++; } } /* Convolution */ for (i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i--) { d_comp[i - D_COMP_MIN] += (short)(d_comp[i - 1 - D_COMP_MIN] + d_comp[i - 2 - D_COMP_MIN] + d_comp[i - 3 - D_COMP_MIN]); } length_d_comp = 0; for (i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++) { if (d_comp[i - D_COMP_MIN] > 0) { d_comp[length_d_comp] = (short)(i - 2); length_d_comp++; } } /********************************************************************************** ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation *************************************************************************************/ /****************************************************************************** ** Scale signal down to avoid correlations measures from overflowing *******************************************************************************/ /* find scaling as max scaling for each subframe */ SumSqrShift.silk_sum_sqr_shift(out energy, out shift, frame_8kHz, frame_length_8kHz); if (shift > 0) { shift = Inlines.silk_RSHIFT(shift, 1); for (i = 0; i < frame_length_8kHz; i++) { frame_8kHz[i] = Inlines.silk_RSHIFT16(frame_8kHz[i], shift); } } /********************************************************************************* * Find energy of each subframe projected onto its history, for a range of delays *********************************************************************************/ Arrays.MemSetShort(C, 0, nb_subfr * CSTRIDE_8KHZ); target = frame_8kHz; target_ptr = SilkConstants.PE_LTP_MEM_LENGTH_MS * 8; for (k = 0; k < nb_subfr; k++) { energy_target = Inlines.silk_ADD32(Inlines.silk_inner_prod(target, target_ptr, target, target_ptr, SF_LENGTH_8KHZ), 1); for (j = 0; j < length_d_comp; j++) { d = d_comp[j]; basis = target; basis_ptr = target_ptr - d; cross_corr = Inlines.silk_inner_prod(target, target_ptr, basis, basis_ptr, SF_LENGTH_8KHZ); if (cross_corr > 0) { energy_basis = Inlines.silk_inner_prod_self(basis, basis_ptr, SF_LENGTH_8KHZ); Inlines.MatrixSet(C, k, d - (MIN_LAG_8KHZ - 2), CSTRIDE_8KHZ, (short)Inlines.silk_DIV32_varQ(cross_corr, Inlines.silk_ADD32(energy_target, energy_basis), 13 + 1)); /* Q13 */ } else { Inlines.MatrixSet <short>(C, k, d - (MIN_LAG_8KHZ - 2), CSTRIDE_8KHZ, 0); } } target_ptr += SF_LENGTH_8KHZ; } /* search over lag range and lags codebook */ /* scale factor for lag codebook, as a function of center lag */ CCmax = int.MinValue; CCmax_b = int.MinValue; CBimax = 0; /* To avoid returning undefined lag values */ lag = -1; /* To check if lag with strong enough correlation has been found */ if (prevLag > 0) { if (Fs_kHz == 12) { prevLag = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(prevLag, 1), 3); } else if (Fs_kHz == 16) { prevLag = Inlines.silk_RSHIFT(prevLag, 1); } prevLag_log2_Q7 = Inlines.silk_lin2log((int)prevLag); } else { prevLag_log2_Q7 = 0; } Inlines.OpusAssert(search_thres2_Q13 == Inlines.silk_SAT16(search_thres2_Q13)); /* Set up stage 2 codebook based on number of subframes */ if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR) { Lag_CB_ptr = Tables.silk_CB_lags_stage2; if (Fs_kHz == 8 && complexity > SilkConstants.SILK_PE_MIN_COMPLEX) { /* If input is 8 khz use a larger codebook here because it is last stage */ nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE2_EXT; } else { nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE2; } } else { Lag_CB_ptr = Tables.silk_CB_lags_stage2_10_ms; nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE2_10MS; } for (k = 0; k < length_d_srch; k++) { d = d_srch[k]; for (j = 0; j < nb_cbk_search; j++) { CC[j] = 0; for (i = 0; i < nb_subfr; i++) { int d_subfr; /* Try all codebooks */ d_subfr = d + Lag_CB_ptr[i][j]; CC[j] = CC[j] + (int)Inlines.MatrixGet(C, i, d_subfr - (MIN_LAG_8KHZ - 2), CSTRIDE_8KHZ); } } /* Find best codebook */ CCmax_new = int.MinValue; CBimax_new = 0; for (i = 0; i < nb_cbk_search; i++) { if (CC[i] > CCmax_new) { CCmax_new = CC[i]; CBimax_new = i; } } /* Bias towards shorter lags */ lag_log2_Q7 = Inlines.silk_lin2log(d); /* Q7 */ Inlines.OpusAssert(lag_log2_Q7 == Inlines.silk_SAT16(lag_log2_Q7)); Inlines.OpusAssert(nb_subfr * ((int)((SilkConstants.PE_SHORTLAG_BIAS) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.PE_SHORTLAG_BIAS, 13)*/ == Inlines.silk_SAT16(nb_subfr * ((int)((SilkConstants.PE_SHORTLAG_BIAS) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.PE_SHORTLAG_BIAS, 13)*/)); CCmax_new_b = CCmax_new - Inlines.silk_RSHIFT(Inlines.silk_SMULBB(nb_subfr * ((int)((SilkConstants.PE_SHORTLAG_BIAS) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.PE_SHORTLAG_BIAS, 13)*/, lag_log2_Q7), 7); /* Q13 */ /* Bias towards previous lag */ Inlines.OpusAssert(nb_subfr * ((int)((SilkConstants.PE_PREVLAG_BIAS) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.PE_PREVLAG_BIAS, 13)*/ == Inlines.silk_SAT16(nb_subfr * ((int)((SilkConstants.PE_PREVLAG_BIAS) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.PE_PREVLAG_BIAS, 13)*/)); if (prevLag > 0) { delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; Inlines.OpusAssert(delta_lag_log2_sqr_Q7 == Inlines.silk_SAT16(delta_lag_log2_sqr_Q7)); delta_lag_log2_sqr_Q7 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7), 7); prev_lag_bias_Q13 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(nb_subfr * ((int)((SilkConstants.PE_PREVLAG_BIAS) * ((long)1 << (13)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.PE_PREVLAG_BIAS, 13)*/, LTPCorr_Q15.Val), 15); /* Q13 */ prev_lag_bias_Q13 = Inlines.silk_DIV32(Inlines.silk_MUL(prev_lag_bias_Q13, delta_lag_log2_sqr_Q7), delta_lag_log2_sqr_Q7 + ((int)((0.5f) * ((long)1 << (7)) + 0.5)) /*Inlines.SILK_CONST(0.5f, 7)*/); CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */ } if (CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ CCmax_new > Inlines.silk_SMULBB(nb_subfr, search_thres2_Q13) && /* Correlation needs to be high enough to be voiced */ Tables.silk_CB_lags_stage2[0][CBimax_new] <= MIN_LAG_8KHZ /* Lag must be in range */ ) { CCmax_b = CCmax_new_b; CCmax = CCmax_new; lag = d; CBimax = CBimax_new; } } if (lag == -1) { /* No suitable candidate found */ Arrays.MemSetInt(pitch_out, 0, nb_subfr); LTPCorr_Q15.Val = 0; lagIndex.Val = 0; contourIndex.Val = 0; return(1); } /* Output normalized correlation */ LTPCorr_Q15.Val = (int)Inlines.silk_LSHIFT(Inlines.silk_DIV32_16(CCmax, nb_subfr), 2); Inlines.OpusAssert(LTPCorr_Q15.Val >= 0); if (Fs_kHz > 8) { short[] scratch_mem; /***************************************************************************/ /* Scale input signal down to avoid correlations measures from overflowing */ /***************************************************************************/ /* find scaling as max scaling for each subframe */ SumSqrShift.silk_sum_sqr_shift(out energy, out shift, frame, frame_length); if (shift > 0) { scratch_mem = new short[frame_length]; /* Move signal to scratch mem because the input signal should be unchanged */ shift = Inlines.silk_RSHIFT(shift, 1); for (i = 0; i < frame_length; i++) { scratch_mem[i] = Inlines.silk_RSHIFT16(frame[i], shift); } input_frame_ptr = scratch_mem; } else { input_frame_ptr = frame; } /* Search in original signal */ CBimax_old = CBimax; /* Compensate for decimation */ Inlines.OpusAssert(lag == Inlines.silk_SAT16(lag)); if (Fs_kHz == 12) { lag = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(lag, 3), 1); } else if (Fs_kHz == 16) { lag = Inlines.silk_LSHIFT(lag, 1); } else { lag = Inlines.silk_SMULBB(lag, 3); } lag = Inlines.silk_LIMIT_int(lag, min_lag, max_lag); start_lag = Inlines.silk_max_int(lag - 2, min_lag); end_lag = Inlines.silk_min_int(lag + 2, max_lag); lag_new = lag; /* to avoid undefined lag */ CBimax = 0; /* to avoid undefined lag */ CCmax = int.MinValue; /* pitch lags according to second stage */ for (k = 0; k < nb_subfr; k++) { pitch_out[k] = lag + 2 * Tables.silk_CB_lags_stage2[k][CBimax_old]; } /* Set up codebook parameters according to complexity setting and frame length */ if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR) { nb_cbk_search = (int)Tables.silk_nb_cbk_searchs_stage3[complexity]; Lag_CB_ptr = Tables.silk_CB_lags_stage3; } else { nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE3_10MS; Lag_CB_ptr = Tables.silk_CB_lags_stage3_10_ms; } /* Calculate the correlations and energies needed in stage 3 */ energies_st3 = new silk_pe_stage3_vals[nb_subfr * nb_cbk_search]; cross_corr_st3 = new silk_pe_stage3_vals[nb_subfr * nb_cbk_search]; for (int c = 0; c < nb_subfr * nb_cbk_search; c++) { energies_st3[c] = new silk_pe_stage3_vals(); // fixme: these can be replaced with a linearized array probably, or at least a struct cross_corr_st3[c] = new silk_pe_stage3_vals(); } silk_P_Ana_calc_corr_st3(cross_corr_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity); silk_P_Ana_calc_energy_st3(energies_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity); lag_counter = 0; Inlines.OpusAssert(lag == Inlines.silk_SAT16(lag)); contour_bias_Q15 = Inlines.silk_DIV32_16(((int)((SilkConstants.PE_FLATCONTOUR_BIAS) * ((long)1 << (15)) + 0.5)) /*Inlines.SILK_CONST(SilkConstants.PE_FLATCONTOUR_BIAS, 15)*/, lag); target = input_frame_ptr; target_ptr = SilkConstants.PE_LTP_MEM_LENGTH_MS * Fs_kHz; energy_target = Inlines.silk_ADD32(Inlines.silk_inner_prod_self(target, target_ptr, nb_subfr * sf_length), 1); for (d = start_lag; d <= end_lag; d++) { for (j = 0; j < nb_cbk_search; j++) { cross_corr = 0; energy = energy_target; for (k = 0; k < nb_subfr; k++) { cross_corr = Inlines.silk_ADD32(cross_corr, Inlines.MatrixGet(cross_corr_st3, k, j, nb_cbk_search).Values[lag_counter]); energy = Inlines.silk_ADD32(energy, Inlines.MatrixGet(energies_st3, k, j, nb_cbk_search).Values[lag_counter]); Inlines.OpusAssert(energy >= 0); } if (cross_corr > 0) { CCmax_new = Inlines.silk_DIV32_varQ(cross_corr, energy, 13 + 1); /* Q13 */ /* Reduce depending on flatness of contour */ diff = short.MaxValue - Inlines.silk_MUL(contour_bias_Q15, j); /* Q15 */ Inlines.OpusAssert(diff == Inlines.silk_SAT16(diff)); CCmax_new = Inlines.silk_SMULWB(CCmax_new, diff); /* Q14 */ } else { CCmax_new = 0; } if (CCmax_new > CCmax && (d + Tables.silk_CB_lags_stage3[0][j]) <= max_lag) { CCmax = CCmax_new; lag_new = d; CBimax = j; } } lag_counter++; } for (k = 0; k < nb_subfr; k++) { pitch_out[k] = lag_new + Lag_CB_ptr[k][CBimax]; pitch_out[k] = Inlines.silk_LIMIT(pitch_out[k], min_lag, SilkConstants.PE_MAX_LAG_MS * Fs_kHz); } lagIndex.Val = (short)(lag_new - min_lag); contourIndex.Val = (sbyte)CBimax; } else /* Fs_kHz == 8 */ /* Save Lags */ { for (k = 0; k < nb_subfr; k++) { pitch_out[k] = lag + Lag_CB_ptr[k][CBimax]; pitch_out[k] = Inlines.silk_LIMIT(pitch_out[k], MIN_LAG_8KHZ, SilkConstants.PE_MAX_LAG_MS * 8); } lagIndex.Val = (short)(lag - MIN_LAG_8KHZ); contourIndex.Val = (sbyte)CBimax; } Inlines.OpusAssert(lagIndex.Val >= 0); /* return as voiced */ return(0); }
internal static int _celt_autocorr( short[] x, /* in: [0...n-1] samples x */ int[] ac, /* out: [0...lag-1] ac values */ int lag, int n ) { int d; int i, k; int fastN = n - lag; int shift; short[] xptr; short[] xx = new short[n]; Inlines.OpusAssert(n > 0); xptr = x; shift = 0; { int ac0; ac0 = 1 + (n << 7); if ((n & 1) != 0) { ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[0], xptr[0]), 9); } for (i = (n & 1); i < n; i += 2) { ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i], xptr[i]), 9); ac0 += Inlines.SHR32(Inlines.MULT16_16(xptr[i + 1], xptr[i + 1]), 9); } shift = Inlines.celt_ilog2(ac0) - 30 + 10; shift = (shift) / 2; if (shift > 0) { for (i = 0; i < n; i++) { xx[i] = (short)(Inlines.PSHR32(xptr[i], shift)); } xptr = xx; } else { shift = 0; } } CeltPitchXCorr.pitch_xcorr(xptr, xptr, ac, fastN, lag + 1); for (k = 0; k <= lag; k++) { for (i = k + fastN, d = 0; i < n; i++) { d = Inlines.MAC16_16(d, xptr[i], xptr[i - k]); } ac[k] += d; } shift = 2 * shift; if (shift <= 0) { ac[0] += Inlines.SHL32((int)1, -shift); } if (ac[0] < 268435456) { int shift2 = 29 - Inlines.EC_ILOG((uint)ac[0]); for (i = 0; i <= lag; i++) { ac[i] = Inlines.SHL32(ac[i], shift2); } shift -= shift2; } else if (ac[0] >= 536870912) { int shift2 = 1; if (ac[0] >= 1073741824) { shift2++; } for (i = 0; i <= lag; i++) { ac[i] = Inlines.SHR32(ac[i], shift2); } shift += shift2; } return(shift); }
/*********************************************************************** * Calculates the correlations used in stage 3 search. In order to cover * the whole lag codebook for all the searched offset lags (lag +- 2), * the following correlations are needed in each sub frame: * * sf1: lag range [-8,...,7] total 16 correlations * sf2: lag range [-4,...,4] total 9 correlations * sf3: lag range [-3,....4] total 8 correltions * sf4: lag range [-6,....8] total 15 correlations * * In total 48 correlations. The direct implementation computed in worst * case 4*12*5 = 240 correlations, but more likely around 120. ***********************************************************************/ private static void silk_P_Ana_calc_corr_st3( silk_pe_stage3_vals[] cross_corr_st3, /* O 3 DIM correlation array */ short[] frame, /* I vector to correlate */ int start_lag, /* I lag offset to search around */ int sf_length, /* I length of a 5 ms subframe */ int nb_subfr, /* I number of subframes */ int complexity /* I Complexity setting */ ) { int target_ptr; int i, j, k, lag_counter, lag_low, lag_high; int nb_cbk_search, delta, idx; int[] scratch_mem; int[] xcorr32; sbyte[][] Lag_range_ptr; sbyte[][] Lag_CB_ptr; Inlines.OpusAssert(complexity >= SilkConstants.SILK_PE_MIN_COMPLEX); Inlines.OpusAssert(complexity <= SilkConstants.SILK_PE_MAX_COMPLEX); if (nb_subfr == SilkConstants.PE_MAX_NB_SUBFR) { Lag_range_ptr = Tables.silk_Lag_range_stage3[complexity]; Lag_CB_ptr = Tables.silk_CB_lags_stage3; nb_cbk_search = Tables.silk_nb_cbk_searchs_stage3[complexity]; } else { Inlines.OpusAssert(nb_subfr == SilkConstants.PE_MAX_NB_SUBFR >> 1); Lag_range_ptr = Tables.silk_Lag_range_stage3_10_ms; Lag_CB_ptr = Tables.silk_CB_lags_stage3_10_ms; nb_cbk_search = SilkConstants.PE_NB_CBKS_STAGE3_10MS; } scratch_mem = new int[SCRATCH_SIZE]; xcorr32 = new int[SCRATCH_SIZE]; target_ptr = Inlines.silk_LSHIFT(sf_length, 2); /* Pointer to middle of frame */ for (k = 0; k < nb_subfr; k++) { lag_counter = 0; /* Calculate the correlations for each subframe */ lag_low = Lag_range_ptr[k][0]; lag_high = Lag_range_ptr[k][1]; Inlines.OpusAssert(lag_high - lag_low + 1 <= SCRATCH_SIZE); CeltPitchXCorr.pitch_xcorr(frame, target_ptr, frame, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1); for (j = lag_low; j <= lag_high; j++) { Inlines.OpusAssert(lag_counter < SCRATCH_SIZE); scratch_mem[lag_counter] = xcorr32[lag_high - j]; lag_counter++; } delta = Lag_range_ptr[k][0]; for (i = 0; i < nb_cbk_search; i++) { /* Fill out the 3 dim array that stores the correlations for */ /* each code_book vector for each start lag */ idx = Lag_CB_ptr[k][i] - delta; for (j = 0; j < SilkConstants.PE_NB_STAGE3_LAGS; j++) { Inlines.OpusAssert(idx + j < SCRATCH_SIZE); Inlines.OpusAssert(idx + j < lag_counter); Inlines.MatrixGet(cross_corr_st3, k, i, nb_cbk_search).Values[j] = scratch_mem[idx + j]; } } target_ptr += sf_length; } }