static inline opus_int silk_setup_LBRR( silk_encoder_state *psEncC, /* I/O */ const opus_int32 TargetRate_bps /* I */ ) { opus_int ret = SILK_NO_ERROR; opus_int32 LBRR_rate_thres_bps; psEncC->LBRR_enabled = 0; if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) { if( psEncC->fs_kHz == 8 ) { LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS; } else if( psEncC->fs_kHz == 12 ) { LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS; } else { LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS; } LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) ); if( TargetRate_bps > LBRR_rate_thres_bps ) { /* Set gain increase for coding LBRR excitation */ psEncC->LBRR_enabled = 1; psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 ); } } return ret; }
static OPUS_INLINE opus_int silk_setup_LBRR( silk_encoder_state *psEncC, /* I/O */ const opus_int32 TargetRate_bps /* I */ ) { opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR; opus_int32 LBRR_rate_thres_bps; LBRR_in_previous_packet = psEncC->LBRR_enabled; psEncC->LBRR_enabled = 0; if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) { if( psEncC->fs_kHz == 8 ) { LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS; } else if( psEncC->fs_kHz == 12 ) { LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS; } else { LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS; } LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) ); if( TargetRate_bps > LBRR_rate_thres_bps ) { /* Set gain increase for coding LBRR excitation */ if( LBRR_in_previous_packet == 0 ) { /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */ psEncC->LBRR_GainIncreases = 7; } else { psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 ); } psEncC->LBRR_enabled = 1; } } return ret; }
/* Find least-squares prediction gain for one signal based on another and quantize it */ int32_t silk_stereo_find_predictor( /* O Returns predictor in Q13 */ int32_t * ratio_Q14, /* O Ratio of residual and mid energies */ const int16_t x[], /* I Basis signal */ const int16_t y[], /* I Target signal */ int32_t mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ int length, /* I Number of samples */ int smooth_coef_Q16 /* I Smoothing coefficient */ ) { int scale, scale1, scale2; int32_t nrgx, nrgy, corr, pred_Q13, pred2_Q10; /* Find predictor */ silk_sum_sqr_shift(&nrgx, &scale1, x, length); silk_sum_sqr_shift(&nrgy, &scale2, y, length); scale = silk_max_int(scale1, scale2); scale = scale + (scale & 1); /* make even */ nrgy = silk_RSHIFT32(nrgy, scale - scale2); nrgx = silk_RSHIFT32(nrgx, scale - scale1); nrgx = silk_max_int(nrgx, 1); corr = silk_inner_prod_aligned_scale(x, y, scale, length); pred_Q13 = silk_DIV32_varQ(corr, nrgx, 13); pred_Q13 = silk_LIMIT(pred_Q13, -(1 << 14), 1 << 14); pred2_Q10 = silk_SMULWB(pred_Q13, pred_Q13); /* Faster update for signals with large prediction parameters */ smooth_coef_Q16 = (int) silk_max_int(smooth_coef_Q16, silk_abs(pred2_Q10)); /* Smoothed mid and residual norms */ assert(smooth_coef_Q16 < 32768); scale = silk_RSHIFT(scale, 1); mid_res_amp_Q0[0] = silk_SMLAWB(mid_res_amp_Q0[0], silk_LSHIFT(silk_SQRT_APPROX(nrgx), scale) - mid_res_amp_Q0[0], smooth_coef_Q16); /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */ nrgy = silk_SUB_LSHIFT32(nrgy, silk_SMULWB(corr, pred_Q13), 3 + 1); nrgy = silk_ADD_LSHIFT32(nrgy, silk_SMULWB(nrgx, pred2_Q10), 6); mid_res_amp_Q0[1] = silk_SMLAWB(mid_res_amp_Q0[1], silk_LSHIFT(silk_SQRT_APPROX(nrgy), scale) - mid_res_amp_Q0[1], smooth_coef_Q16); /* Ratio of smoothed residual and mid norms */ *ratio_Q14 = silk_DIV32_varQ(mid_res_amp_Q0[1], silk_max(mid_res_amp_Q0[0], 1), 14); *ratio_Q14 = silk_LIMIT(*ratio_Q14, 0, 32767); return pred_Q13; }
/* Gain scalar quantization with hysteresis, uniform on log scale */ void silk_gains_quant( opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ opus_int8 *prev_ind, /* I/O last index in previous frame */ const opus_int conditional, /* I first gain is delta coded if 1 */ const opus_int nb_subfr /* I number of subframes */ ) { opus_int k, double_step_size_threshold; for( k = 0; k < nb_subfr; k++ ) { /* Convert to log scale, scale, floor() */ ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET ); /* Round towards previous quantized gain (hysteresis) */ if( ind[ k ] < *prev_ind ) { ind[ k ]++; } ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 ); /* Compute delta indices and limit */ if( k == 0 && conditional == 0 ) { /* Full index */ ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 ); *prev_ind = ind[ k ]; } else { /* Delta index */ ind[ k ] = ind[ k ] - *prev_ind; /* Double the quantization step size for large gain increases, so that the max gain level can be reached */ double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; if( ind[ k ] > double_step_size_threshold ) { ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 ); } ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT ); /* Accumulate deltas */ if( ind[ k ] > double_step_size_threshold ) { *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold; *prev_ind = silk_min_int( *prev_ind, N_LEVELS_QGAIN - 1 ); } else { *prev_ind += ind[ k ]; } /* Shift to make non-negative */ ind[ k ] -= MIN_DELTA_GAIN_QUANT; } /* Scale and convert to linear scale */ gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ } }
/* Gains scalar dequantization, uniform on log scale */ void silk_gains_dequant( opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ opus_int8 *prev_ind, /* I/O last index in previous frame */ const opus_int conditional, /* I first gain is delta coded if 1 */ const opus_int nb_subfr /* I number of subframes */ ) { opus_int k, ind_tmp, double_step_size_threshold; for( k = 0; k < nb_subfr; k++ ) { if( k == 0 && conditional == 0 ) { /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */ *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 ); } else { /* Delta index */ ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT; /* Accumulate deltas */ double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; if( ind_tmp > double_step_size_threshold ) { *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold; } else { *prev_ind += ind_tmp; } } *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 ); /* Scale and convert to linear scale */ gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ } }
static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL( opus_int16 *out, opus_int16 *buf, opus_int32 max_index_Q16, opus_int32 index_increment_Q16 ) { opus_int32 index_Q16, res_Q15; opus_int16 *buf_ptr; opus_int32 table_index; /* Interpolate upsampled signal and store in output array */ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 ); buf_ptr = &buf[ index_Q16 >> 16 ]; res_Q15 = silk_SMULBB( buf_ptr[ 0 ], silk_resampler_frac_FIR_12[ table_index ][ 0 ] ); res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[ table_index ][ 1 ] ); res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[ table_index ][ 2 ] ); res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[ table_index ][ 3 ] ); res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] ); res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] ); res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] ); res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] ); *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) ); } return out; }
/* Decode mid/side predictors */ void silk_stereo_decode_pred( ec_dec *psRangeDec, /* I/O Compressor data structure */ opus_int32 pred_Q13[] /* O Predictors */ ) { opus_int n, ix[ 2 ][ 3 ]; opus_int32 low_Q13, step_Q13; /* Entropy decoding */ n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 ); ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 ); ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ]; for( n = 0; n < 2; n++ ) { ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 ); ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 ); } /* Dequantize */ for( n = 0; n < 2; n++ ) { ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ]; low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ]; step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13, SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 ); } /* Subtract second from first predictor (helps when actually applying these) */ pred_Q13[ 0 ] -= pred_Q13[ 1 ]; }
/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ void silk_HP_variable_cutoff(silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ ) { int quality_Q15; int32_t pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7; silk_encoder_state *psEncC1 = &state_Fxx[0].sCmn; /* Adaptive cutoff frequency: estimate low end of pitch frequency range */ if (psEncC1->prevSignalType == TYPE_VOICED) { /* difference, in log domain */ pitch_freq_Hz_Q16 = silk_DIV32_16(silk_LSHIFT (silk_MUL(psEncC1->fs_kHz, 1000), 16), psEncC1->prevLag); pitch_freq_log_Q7 = silk_lin2log(pitch_freq_Hz_Q16) - (16 << 7); /* adjustment based on quality */ quality_Q15 = psEncC1->input_quality_bands_Q15[0]; pitch_freq_log_Q7 = silk_SMLAWB(pitch_freq_log_Q7, silk_SMULWB(silk_LSHIFT(-quality_Q15, 2), quality_Q15), pitch_freq_log_Q7 - (silk_lin2log (SILK_FIX_CONST(VARIABLE_HP_MIN_CUTOFF_HZ, 16)) - (16 << 7))); /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */ delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT(psEncC1->variable_HP_smth1_Q15, 8); if (delta_freq_Q7 < 0) { /* less smoothing for decreasing pitch frequency, to track something close to the minimum */ delta_freq_Q7 = silk_MUL(delta_freq_Q7, 3); } /* limit delta, to reduce impact of outliers in pitch estimation */ delta_freq_Q7 = silk_LIMIT_32(delta_freq_Q7, -SILK_FIX_CONST(VARIABLE_HP_MAX_DELTA_FREQ, 7), SILK_FIX_CONST(VARIABLE_HP_MAX_DELTA_FREQ, 7)); /* update smoother */ psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB(psEncC1->variable_HP_smth1_Q15, silk_SMULBB(psEncC1->speech_activity_Q8, delta_freq_Q7), SILK_FIX_CONST(VARIABLE_HP_SMTH_COEF1, 16)); /* limit frequency range */ psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32(psEncC1->variable_HP_smth1_Q15, silk_LSHIFT(silk_lin2log (VARIABLE_HP_MIN_CUTOFF_HZ), 8), silk_LSHIFT(silk_lin2log (VARIABLE_HP_MAX_CUTOFF_HZ), 8)); } }
/* Glues concealed frames with new good received frames */ void silk_PLC_glue_frames( silk_decoder_state *psDec, /* I/O decoder state */ opus_int16 frame[], /* I/O signal */ opus_int length /* I length of signal */ ) { opus_int i, energy_shift; opus_int32 energy; silk_PLC_struct *psPLC; psPLC = &psDec->sPLC; if( psDec->lossCnt ) { /* Calculate energy in concealed residual */ silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); psPLC->last_frame_lost = 1; } else { if( psDec->sPLC.last_frame_lost ) { /* Calculate residual in decoded signal if last frame was lost */ silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); /* Normalize energies */ if( energy_shift > psPLC->conc_energy_shift ) { psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); } else if( energy_shift < psPLC->conc_energy_shift ) { energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); } /* Fade in the energy difference */ if( energy > psPLC->conc_energy ) { opus_int32 frac_Q24, LZ; opus_int32 gain_Q16, slope_Q16; LZ = silk_CLZ32( psPLC->conc_energy ); LZ = LZ - 1; psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); /* Make slope 4x steeper to avoid missing onsets after DTX */ slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); for( i = 0; i < length; i++ ) { frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); gain_Q16 += slope_Q16; if( gain_Q16 > (opus_int32)1 << 16 ) { break; } } } } psPLC->last_frame_lost = 0; } }
/* Prefilter for finding Quantizer input signal */ static OPUS_INLINE void silk_prefilt_FIX( silk_prefilter_state_FIX *P, /* I/O state */ opus_int32 st_res_Q12[], /* I short term residual signal */ opus_int32 xw_Q3[], /* O prefiltered signal */ opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ opus_int Tilt_Q14, /* I Tilt shaping coeficient */ opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */ opus_int lag, /* I Lag for harmonic shaping */ opus_int length /* I Length of signals */ ) { opus_int i, idx, LTP_shp_buf_idx; opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10; opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12; opus_int16 *LTP_shp_buf; /* To speed up use temp variables instead of using the struct */ LTP_shp_buf = P->sLTP_shp; LTP_shp_buf_idx = P->sLTP_shp_buf_idx; sLF_AR_shp_Q12 = P->sLF_AR_shp_Q12; sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12; for (i = 0; i < length; i++) { if (lag > 0) { /* unrolled loop */ silk_assert(HARM_SHAPE_FIR_TAPS == 3); idx = lag + LTP_shp_buf_idx; n_LTP_Q12 = silk_SMULBB(LTP_shp_buf[(idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK], HarmShapeFIRPacked_Q12); n_LTP_Q12 = silk_SMLABT(n_LTP_Q12, LTP_shp_buf[(idx - HARM_SHAPE_FIR_TAPS / 2) & LTP_MASK], HarmShapeFIRPacked_Q12); n_LTP_Q12 = silk_SMLABB(n_LTP_Q12, LTP_shp_buf[(idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK], HarmShapeFIRPacked_Q12); } else { n_LTP_Q12 = 0; } n_Tilt_Q10 = silk_SMULWB(sLF_AR_shp_Q12, Tilt_Q14); n_LF_Q10 = silk_SMLAWB(silk_SMULWT(sLF_AR_shp_Q12, LF_shp_Q14), sLF_MA_shp_Q12, LF_shp_Q14); sLF_AR_shp_Q12 = silk_SUB32(st_res_Q12[i], silk_LSHIFT(n_Tilt_Q10, 2)); sLF_MA_shp_Q12 = silk_SUB32(sLF_AR_shp_Q12, silk_LSHIFT(n_LF_Q10, 2)); LTP_shp_buf_idx = (LTP_shp_buf_idx - 1) & LTP_MASK; LTP_shp_buf[LTP_shp_buf_idx] = (opus_int16) silk_SAT16( silk_RSHIFT_ROUND(sLF_MA_shp_Q12, 12)); xw_Q3[i] = silk_RSHIFT_ROUND(silk_SUB32(sLF_MA_shp_Q12, n_LTP_Q12), 9); } /* Copy temp variable back to state */ P->sLF_AR_shp_Q12 = sLF_AR_shp_Q12; P->sLF_MA_shp_Q12 = sLF_MA_shp_Q12; P->sLTP_shp_buf_idx = LTP_shp_buf_idx; }
/* Second order ARMA filter, alternative implementation */ void silk_biquad_alt(const int16_t * in, /* I input signal */ const int32_t * B_Q28, /* I MA coefficients [3] */ const int32_t * A_Q28, /* I AR coefficients [2] */ int32_t * S, /* I/O State vector [2] */ int16_t * out, /* O output signal */ const int32_t len, /* I signal length (must be even) */ int stride /* I Operate on interleaved signal if > 1 */ ) { /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ int k; int32_t inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14; /* Negate A_Q28 values and split in two parts */ A0_L_Q28 = (-A_Q28[0]) & 0x00003FFF; /* lower part */ A0_U_Q28 = silk_RSHIFT(-A_Q28[0], 14); /* upper part */ A1_L_Q28 = (-A_Q28[1]) & 0x00003FFF; /* lower part */ A1_U_Q28 = silk_RSHIFT(-A_Q28[1], 14); /* upper part */ for (k = 0; k < len; k++) { /* S[ 0 ], S[ 1 ]: Q12 */ inval = in[k * stride]; out32_Q14 = silk_LSHIFT(silk_SMLAWB(S[0], B_Q28[0], inval), 2); S[0] = S[1] + silk_RSHIFT_ROUND(silk_SMULWB(out32_Q14, A0_L_Q28), 14); S[0] = silk_SMLAWB(S[0], out32_Q14, A0_U_Q28); S[0] = silk_SMLAWB(S[0], B_Q28[1], inval); S[1] = silk_RSHIFT_ROUND(silk_SMULWB(out32_Q14, A1_L_Q28), 14); S[1] = silk_SMLAWB(S[1], out32_Q14, A1_U_Q28); S[1] = silk_SMLAWB(S[1], B_Q28[2], inval); /* Scale back to Q0 and saturate */ out[k * stride] = (int16_t) silk_SAT16(silk_RSHIFT(out32_Q14 + (1 << 14) - 1, 14)); } }
/* Copy and multiply a vector by a constant */ void silk_scale_copy_vector16( opus_int16 *data_out, const opus_int16 *data_in, opus_int32 gain_Q16, /* I Gain in Q16 */ const opus_int dataSize /* I Length */ ) { opus_int i; opus_int32 tmp32; for(i = 0; i < dataSize; i++) { tmp32 = silk_SMULWB(gain_Q16, data_in[ i ]); data_out[ i ] = (opus_int16)silk_CHECK_FIT16(tmp32); } }
/* Processing of gains */ void silk_process_gains_FIX( silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ opus_int condCoding /* I The type of conditional coding to use */ ) { silk_shape_state_FIX *psShapeSt = &psEnc->sShape; opus_int k; opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10; /* Gain reduction when LTP coding gain is high */ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */ s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) ); for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 ); } } /* Limit the quantized signal */ /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */ InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin( silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length ); for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { /* Soft limit on ratio residual energy and squared gains */ ResNrg = psEncCtrl->ResNrg[ k ]; ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 ); if( psEncCtrl->ResNrgQ[ k ] > 0 ) { ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] ); } else { if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) { ResNrgPart = silk_int32_MAX; } else { ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] ); } } gain = psEncCtrl->Gains_Q16[ k ]; gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) ); if( gain_squared < silk_int16_MAX ) { /* recalculate with higher precision */ gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain ); silk_assert( gain_squared > 0 ); gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */ gain = silk_min( gain, silk_int32_MAX >> 8 ); psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */ } else {
void silk_noise_shape_analysis_FIX( silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ int arch /* I Run-time architecture */ ) { silk_shape_state_FIX *psShapeSt = &psEnc->sShape; opus_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0; opus_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; opus_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; opus_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; opus_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ]; opus_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ]; VARDECL( opus_int16, x_windowed ); const opus_int16 *x_ptr, *pitch_res_ptr; SAVE_STACK; /* Point to start of first LPC analysis block */ x_ptr = x - psEnc->sCmn.la_shape; /****************/ /* GAIN CONTROL */ /****************/ SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; /* Input quality is the average of the quality in the lowest two VAD bands */ psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); /* Reduce coding SNR during low speech activity */ if( psEnc->sCmn.useCBR == 0 ) { b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ }
/* Second order AR filter with single delay elements */ void silk_resampler_private_AR2(int32_t S[], /* I/O State vector [ 2 ] */ int32_t out_Q8[], /* O Output signal */ const int16_t in[], /* I Input signal */ const int16_t A_Q14[], /* I AR coefficients, Q14 */ int32_t len /* I Signal length */ ) { int32_t k; int32_t out32; for (k = 0; k < len; k++) { out32 = silk_ADD_LSHIFT32(S[0], (int32_t) in[k], 8); out_Q8[k] = out32; out32 = silk_LSHIFT(out32, 2); S[0] = silk_SMLAWB(S[1], out32, A_Q14[0]); S[1] = silk_SMULWB(out32, A_Q14[1]); } }
/* Second order AR filter with single delay elements */ void silk_resampler_private_AR2( opus_int32 S[], /* I/O State vector [ 2 ] */ opus_int32 out_Q8[], /* O Output signal */ const opus_int16 in[], /* I Input signal */ const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ opus_int32 len /* I Signal length */ ) { opus_int32 k; opus_int32 out32; for(k = 0; k < len; k++) { out32 = silk_ADD_LSHIFT32(S[ 0 ], (opus_int32)in[ k ], 8); out_Q8[ k ] = out32; out32 = silk_LSHIFT(out32, 2); S[ 0 ] = silk_SMLAWB(S[ 1 ], out32, A_Q14[ 0 ]); S[ 1 ] = silk_SMULWB(out32, A_Q14[ 1 ]); } }
/* Calculation of LTP state scaling */ void silk_LTP_scale_ctrl_FIX( silk_encoder_state_FIX *psEnc, /* I/O encoder state */ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ opus_int condCoding /* I The type of conditional coding to use */ ) { opus_int round_loss; if( condCoding == CODE_INDEPENDENTLY ) { /* Only scale if first frame in packet */ round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 ); } else { /* Default is minimum scaling */ psEnc->sCmn.indices.LTP_scaleIndex = 0; } psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ]; }
void silk_warped_LPC_analysis_filter_FIX( opus_int32 state[], /* I/O State [order + 1] */ opus_int16 res[], /* O Residual signal [length] */ const opus_int16 coef_Q13[], /* I Coefficients [order] */ const opus_int16 input[], /* I Input signal [length] */ const opus_int16 lambda_Q16, /* I Warping factor */ const opus_int length, /* I Length of input signal */ const opus_int order /* I Filter order (even) */ ) { opus_int n, i; opus_int32 acc_Q11, tmp1, tmp2; /* Order must be even */ silk_assert( ( order & 1 ) == 0 ); for( n = 0; n < length; n++ ) { /* Output of lowpass section */ tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); state[ 0 ] = silk_LSHIFT( input[ n ], 14 ); /* Output of allpass section */ tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); state[ 1 ] = tmp2; acc_Q11 = silk_SMULWB( tmp2, coef_Q13[ 0 ] ); /* Loop over allpass sections */ for( i = 2; i < order; i += 2 ) { /* Output of allpass section */ tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); state[ i ] = tmp1; acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); /* Output of allpass section */ tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); state[ i + 1 ] = tmp2; acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); } state[ order ] = tmp1; acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); res[ n ] = ( opus_int16 )silk_SAT16( ( opus_int32 )input[ n ] - silk_RSHIFT_ROUND( acc_Q11, 11 ) ); } }
/* Quantize mid/side predictors */ void silk_stereo_quant_pred( opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ ) { opus_int i, j, n; opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0; /* Quantize */ for( n = 0; n < 2; n++ ) { /* Brute-force search over quantization levels */ err_min_Q13 = silk_int32_MAX; for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) { low_Q13 = silk_stereo_pred_quant_Q13[ i ]; step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13, SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) { lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 ); err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 ); if( err_Q13 < err_min_Q13 ) { err_min_Q13 = err_Q13; quant_pred_Q13 = lvl_Q13; ix[ n ][ 0 ] = i; ix[ n ][ 1 ] = j; } else { /* Error increasing, so we're past the optimum */ goto done; } } } done: ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 ); ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3; pred_Q13[ n ] = quant_pred_Q13; } /* Subtract second from first predictor (helps when actually applying these) */ pred_Q13[ 0 ] -= pred_Q13[ 1 ]; }
/* Split signal into two decimated bands using first-order allpass filters */ void silk_ana_filt_bank_1( const opus_int16 *in, /* I Input signal [N] */ opus_int32 *S, /* I/O State vector [2] */ opus_int16 *outL, /* O Low band [N/2] */ opus_int16 *outH, /* O High band [N/2] */ const opus_int32 N /* I Number of input samples */ ) { opus_int k, N2 = silk_RSHIFT( N, 1 ); opus_int32 in32, X, Y, out_1, out_2; /* Internal variables and state are in Q10 format */ for( k = 0; k < N2; k++ ) { /* Convert to Q10 */ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); /* All-pass section for even input sample */ Y = silk_SUB32( in32, S[ 0 ] ); X = silk_SMLAWB( Y, Y, A_fb1_21 ); out_1 = silk_ADD32( S[ 0 ], X ); S[ 0 ] = silk_ADD32( in32, X ); /* Convert to Q10 */ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); /* All-pass section for odd input sample, and add to output of previous section */ Y = silk_SUB32( in32, S[ 1 ] ); X = silk_SMULWB( Y, A_fb1_20 ); out_2 = silk_ADD32( S[ 1 ], X ); S[ 1 ] = silk_ADD32( in32, X ); /* Add/subtract, convert back to int16 and store to output */ outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) ); outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) ); } }
static OPUS_INLINE void silk_PLC_conceal( silk_decoder_state *psDec, /* I/O Decoder state */ silk_decoder_control *psDecCtrl, /* I/O Decoder control */ opus_int16 frame[], /* O LPC residual signal */ int arch /* I Run-time architecture */ ) { opus_int i, j, k; opus_int lag, idx, sLTP_buf_idx, shift1, shift2; opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; opus_int32 LPC_pred_Q10, LTP_pred_Q12; opus_int16 rand_scale_Q14; opus_int16 *B_Q14; opus_int32 *sLPC_Q14_ptr; opus_int16 A_Q12[ MAX_LPC_ORDER ]; #ifdef SMALL_FOOTPRINT opus_int16 *sLTP; #else VARDECL( opus_int16, sLTP ); #endif VARDECL( opus_int32, sLTP_Q14 ); silk_PLC_struct *psPLC = &psDec->sPLC; opus_int32 prevGain_Q10[2]; SAVE_STACK; ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); #ifdef SMALL_FOOTPRINT /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */ sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length; #else ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); #endif prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); if( psDec->first_frame_after_reset ) { silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); } silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr); if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { /* First sub-frame has lowest energy */ rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; } else { /* Second sub-frame has lowest energy */ rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - 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[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; if( psDec->prevSignalType == TYPE_VOICED ) { rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; } else { rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; } /* LPC concealment. Apply BWE to previous LPC */ silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); /* Preload LPC coeficients to array on stack. Gives small performance gain */ silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); /* First Lost frame */ if( psDec->lossCnt == 0 ) { rand_scale_Q14 = 1 << 14; /* Reduce random noise Gain for voiced frames */ if( psDec->prevSignalType == TYPE_VOICED ) { for( i = 0; i < LTP_ORDER; i++ ) { rand_scale_Q14 -= B_Q14[ i ]; } rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); } else { /* Reduce random noise for unvoiced frames with high LPC gain */ opus_int32 invGain_Q30, down_scale_Q30; invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch ); down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); } } rand_seed = psPLC->rand_seed; lag = 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 - LTP_ORDER / 2; silk_assert( idx > 0 ); silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch ); /* Scale LTP state */ inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { sLTP_Q14[ i ] = 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_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; for( i = 0; i < psDec->subfr_length; i++ ) { /* Unrolled loop */ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ LTP_pred_Q12 = 2; LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); pred_lag_ptr++; /* Generate LPC excitation */ rand_seed = silk_RAND( rand_seed ); idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); sLTP_buf_idx++; } /* Gradually reduce LTP gain */ for( j = 0; j < LTP_ORDER; j++ ) { B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); } if ( psDec->indices.signalType != TYPE_NO_VOICE_ACTIVITY ) { /* Gradually reduce excitation gain */ rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); } /* Slowly increase pitch lag */ psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); } /***************************/ /* LPC synthesis filtering */ /***************************/ sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; /* Copy LPC state */ silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ for( i = 0; i < psDec->frame_length; i++ ) { /* partly unrolled */ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); for( j = 10; j < psDec->LPC_order; j++ ) { LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); } /* Add prediction to LPC excitation */ sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 )); /* Scale with Gain */ frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); } /* Save LPC state */ silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); /**************************************/ /* Update states */ /**************************************/ psPLC->rand_seed = rand_seed; psPLC->randScale_Q14 = rand_scale_Q14; for( i = 0; i < MAX_NB_SUBFR; i++ ) { psDecCtrl->pitchL[ i ] = lag; } RESTORE_STACK; }
opus_int silk_VAD_GetSA_Q8( /* O Return value, 0 if success */ silk_encoder_state *psEncC, /* I/O Encoder state */ const opus_int16 pIn[] /* I PCM input */ ) { opus_int SA_Q15, pSNR_dB_Q7, input_tilt; opus_int decimated_framelength1, decimated_framelength2; opus_int decimated_framelength; opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; opus_int32 sumSquared, smooth_coef_Q16; opus_int16 HPstateTmp; VARDECL( opus_int16, X ); opus_int32 Xnrg[ VAD_N_BANDS ]; opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; opus_int32 speech_nrg, x_tmp; opus_int X_offset[ VAD_N_BANDS ]; opus_int ret = 0; silk_VAD_state *psSilk_VAD = &psEncC->sVAD; SAVE_STACK; /* Safety checks */ silk_assert( VAD_N_BANDS == 4 ); silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); silk_assert( psEncC->frame_length <= 512 ); silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); /***********************/ /* Filter and Decimate */ /***********************/ decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 ); decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 ); decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); /* Decimate into 4 bands: 0 L 3L L 3L 5L - -- - -- -- 8 8 2 4 4 [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz | They're arranged to allow the minimal ( frame_length / 4 ) extra scratch space during the downsampling process */ X_offset[ 0 ] = 0; X_offset[ 1 ] = decimated_framelength + decimated_framelength2; X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength; X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2; ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 ); /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], X, &X[ X_offset[ 3 ] ], psEncC->frame_length ); /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ], X, &X[ X_offset[ 2 ] ], decimated_framelength1 ); /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ], X, &X[ X_offset[ 1 ] ], decimated_framelength2 ); /*********************************************/ /* HP filter on lowest band (differentiator) */ /*********************************************/ X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 ); HPstateTmp = X[ decimated_framelength - 1 ]; for( i = decimated_framelength - 1; i > 0; i-- ) { X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 ); X[ i ] -= X[ i - 1 ]; } X[ 0 ] -= psSilk_VAD->HPstate; psSilk_VAD->HPstate = HPstateTmp; /*************************************/ /* Calculate the energy in each band */ /*************************************/ for( b = 0; b < VAD_N_BANDS; b++ ) { /* Find the decimated framelength in the non-uniformly divided bands */ decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); /* Split length into subframe lengths */ dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); dec_subframe_offset = 0; /* Compute energy per sub-frame */ /* initialize with summed energy of last subframe */ Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { sumSquared = 0; for( i = 0; i < dec_subframe_length; i++ ) { /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */ /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ x_tmp = silk_RSHIFT( X[ X_offset[ b ] + i + dec_subframe_offset ], 3 ); sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); /* Safety check */ silk_assert( sumSquared >= 0 ); } /* Add/saturate summed energy of current subframe */ if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); } else { /* Look-ahead subframe */ Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); } dec_subframe_offset += dec_subframe_length; } psSilk_VAD->XnrgSubfr[ b ] = sumSquared; } /********************/ /* Noise estimation */ /********************/ silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); /***********************************************/ /* Signal-plus-noise to noise ratio estimation */ /***********************************************/ sumSquared = 0; input_tilt = 0; for( b = 0; b < VAD_N_BANDS; b++ ) { speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; if( speech_nrg > 0 ) { /* Divide, with sufficient resolution */ if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); } else { NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); } /* Convert to log domain */ SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; /* Sum-of-squares */ sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ /* Tilt measure */ if( speech_nrg < ( (opus_int32)1 << 20 ) ) { /* Scale down SNR value for small subband speech energies */ SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); } input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); } else { NrgToNoiseRatio_Q8[ b ] = 256; } } /* Mean-of-squares */ sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ /* Root-mean-square approximation, scale to dBs, and write to output pointer */ pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ /*********************************/ /* Speech Probability Estimation */ /*********************************/ SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); /**************************/ /* Frequency Tilt Measure */ /**************************/ psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 ); /**************************************************/ /* Scale the sigmoid output based on power levels */ /**************************************************/ speech_nrg = 0; for( b = 0; b < VAD_N_BANDS; b++ ) { /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); } /* Power scaling */ if( speech_nrg <= 0 ) { SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); } else if( speech_nrg < 32768 ) { if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 ); } else { speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 ); } /* square-root */ speech_nrg = silk_SQRT_APPROX( speech_nrg ); SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); } /* Copy the resulting speech activity in Q8 */ psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); /***********************************/ /* Energy Level and SNR estimation */ /***********************************/ /* Smoothing coefficient */ smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) ); if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { smooth_coef_Q16 >>= 1; }
/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ static inline void limit_warped_coefs( opus_int32 *coefs_syn_Q24, opus_int32 *coefs_ana_Q24, opus_int lambda_Q16, opus_int32 limit_Q24, opus_int order ) { opus_int i, iter, ind = 0; opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16; opus_int32 nom_Q16, den_Q24; /* Convert to monic coefficients */ lambda_Q16 = -lambda_Q16; for( i = order - 1; i > 0; i-- ) { coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); } lambda_Q16 = -lambda_Q16; nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); for( i = 0; i < order; i++ ) { coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); coefs_ana_Q24[ i ] = 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 = silk_max( silk_abs_int32( coefs_syn_Q24[ i ] ), 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 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); } gain_syn_Q16 = silk_INVERSE32_varQ( gain_syn_Q16, 32 ); gain_ana_Q16 = silk_INVERSE32_varQ( gain_ana_Q16, 32 ); for( i = 0; i < order; i++ ) { coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); } /* Apply bandwidth expansion */ chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ( silk_SMULWB( maxabs_Q24 - limit_Q24, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ), silk_MUL( maxabs_Q24, ind + 1 ), 22 ); silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 ); 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 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); } lambda_Q16 = -lambda_Q16; nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); for( i = 0; i < order; i++ ) { coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); } } silk_assert( 0 ); }
static inline void silk_PLC_conceal( silk_decoder_state *psDec, /* I/O Decoder state */ silk_decoder_control *psDecCtrl, /* I/O Decoder control */ opus_int16 frame[] /* O LPC residual signal */ ) { opus_int i, j, k; opus_int lag, idx, sLTP_buf_idx, shift1, shift2; opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q16, inv_gain_Q30; opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; opus_int32 LPC_exc_Q14, LPC_pred_Q10, LTP_pred_Q12; opus_int16 rand_scale_Q14; opus_int16 *B_Q14, *exc_buf_ptr; opus_int32 *sLPC_Q14_ptr; opus_int16 exc_buf[ 2 * MAX_SUB_FRAME_LENGTH ]; opus_int16 A_Q12[ MAX_LPC_ORDER ]; opus_int16 sLTP[ MAX_FRAME_LENGTH ]; opus_int32 sLTP_Q14[ 2 * MAX_FRAME_LENGTH ]; silk_PLC_struct *psPLC = &psDec->sPLC; if (psDec->first_frame_after_reset) silk_memset(psPLC->prevLPC_Q12, 0, MAX_LPC_ORDER*sizeof(psPLC->prevLPC_Q12[ 0 ])); /* Find random noise component */ /* Scale previous excitation signal */ exc_buf_ptr = exc_buf; for( k = 0; k < 2; k++ ) { for( i = 0; i < psPLC->subfr_length; i++ ) { exc_buf_ptr[ i ] = ( opus_int16 )silk_RSHIFT( silk_SMULWW( psDec->exc_Q10[ i + ( k + psPLC->nb_subfr - 2 ) * psPLC->subfr_length ], psPLC->prevGain_Q16[ k ] ), 10 ); } exc_buf_ptr += psPLC->subfr_length; } /* Find the subframe with lowest energy of the last two and use that as random noise generator */ silk_sum_sqr_shift( &energy1, &shift1, exc_buf, psPLC->subfr_length ); silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psPLC->subfr_length ], psPLC->subfr_length ); if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { /* First sub-frame has lowest energy */ rand_ptr = &psDec->exc_Q10[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; } else { /* Second sub-frame has lowest energy */ rand_ptr = &psDec->exc_Q10[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; } /* Setup Gain to random noise component */ B_Q14 = psPLC->LTPCoef_Q14; rand_scale_Q14 = psPLC->randScale_Q14; /* Setup attenuation gains */ harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; if( psDec->prevSignalType == TYPE_VOICED ) { rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; } else { rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; } /* LPC concealment. Apply BWE to previous LPC */ silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); /* Preload LPC coeficients to array on stack. Gives small performance gain */ silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); /* First Lost frame */ if( psDec->lossCnt == 0 ) { rand_scale_Q14 = 1 << 14; /* Reduce random noise Gain for voiced frames */ if( psDec->prevSignalType == TYPE_VOICED ) { for( i = 0; i < LTP_ORDER; i++ ) { rand_scale_Q14 -= B_Q14[ i ]; } rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ rand_scale_Q14 = ( opus_int16 )silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); } else { /* Reduce random noise for unvoiced frames with high LPC gain */ opus_int32 invGain_Q30, down_scale_Q30; silk_LPC_inverse_pred_gain( &invGain_Q30, psPLC->prevLPC_Q12, psDec->LPC_order ); down_scale_Q30 = silk_min_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); down_scale_Q30 = silk_max_32( silk_RSHIFT( 1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); } } rand_seed = psPLC->rand_seed; lag = 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 - LTP_ORDER / 2; silk_assert( idx > 0 ); silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order ); /* Scale LTP state */ inv_gain_Q16 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 32 ); inv_gain_Q16 = silk_min( inv_gain_Q16, silk_int16_MAX ); inv_gain_Q30 = silk_LSHIFT( inv_gain_Q16, 14 ); for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); } /***************************/ /* LTP synthesis filtering */ /***************************/ for( k = 0; k < psDec->nb_subfr; k++ ) { /* Setup pointer */ pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; for( i = 0; i < psDec->subfr_length; i++ ) { /* Unrolled loop */ LTP_pred_Q12 = silk_SMULWB( pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); pred_lag_ptr++; /* Generate LPC excitation */ rand_seed = silk_RAND( rand_seed ); idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; LPC_exc_Q14 = silk_LSHIFT32( silk_SMULWB( rand_ptr[ idx ], rand_scale_Q14 ), 6 ); /* Random noise part */ LPC_exc_Q14 = silk_ADD32( LPC_exc_Q14, silk_LSHIFT32( LTP_pred_Q12, 2 ) ); /* Harmonic part */ sLTP_Q14[ sLTP_buf_idx ] = LPC_exc_Q14; sLTP_buf_idx++; } /* Gradually reduce LTP gain */ for( j = 0; j < LTP_ORDER; j++ ) { B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); } /* Gradually reduce excitation gain */ rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); /* Slowly increase pitch lag */ psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); } /***************************/ /* LPC synthesis filtering */ /***************************/ sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; /* Copy LPC state */ silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ for( i = 0; i < psDec->frame_length; i++ ) { /* partly unrolled */ LPC_pred_Q10 = silk_SMULWB( sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); for( j = 10; j < psDec->LPC_order; j++ ) { LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); } /* Add prediction to LPC excitation */ sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 ); /* Scale with Gain */ frame[ i ] = ( opus_int16 )silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], psPLC->prevGain_Q16[ 1 ] ), 14 ) ); } /* Save LPC state */ silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); /**************************************/ /* Update states */ /**************************************/ psPLC->rand_seed = rand_seed; psPLC->randScale_Q14 = rand_scale_Q14; for( i = 0; i < MAX_NB_SUBFR; i++ ) { psDecCtrl->pitchL[ i ] = lag; } }
void silk_prefilter_FIX( silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */ opus_int32 xw_Q3[], /* O Weighted signal */ const opus_int16 x[] /* I Speech signal */ ) { silk_prefilter_state_FIX *P = &psEnc->sPrefilt; opus_int j, k, lag; opus_int32 tmp_32; const opus_int16 *AR1_shp_Q13; const opus_int16 *px; opus_int32 *pxw_Q3; opus_int HarmShapeGain_Q12, Tilt_Q14; opus_int32 HarmShapeFIRPacked_Q12, LF_shp_Q14; VARDECL( opus_int32, x_filt_Q12 ); VARDECL( opus_int32, st_res_Q2 ); opus_int16 B_Q10[ 2 ]; SAVE_STACK; /* Set up pointers */ px = x; pxw_Q3 = xw_Q3; lag = P->lagPrev; ALLOC( x_filt_Q12, psEnc->sCmn.subfr_length, opus_int32 ); ALLOC( st_res_Q2, psEnc->sCmn.subfr_length, opus_int32 ); for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { /* Update Variables that change per sub frame */ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { lag = psEncCtrl->pitchL[ k ]; } /* Noise shape parameters */ HarmShapeGain_Q12 = silk_SMULWB( (opus_int32)psEncCtrl->HarmShapeGain_Q14[ k ], 16384 - psEncCtrl->HarmBoost_Q14[ k ] ); silk_assert( HarmShapeGain_Q12 >= 0 ); HarmShapeFIRPacked_Q12 = silk_RSHIFT( HarmShapeGain_Q12, 2 ); HarmShapeFIRPacked_Q12 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q12, 1 ), 16 ); Tilt_Q14 = psEncCtrl->Tilt_Q14[ k ]; LF_shp_Q14 = psEncCtrl->LF_shp_Q14[ k ]; AR1_shp_Q13 = &psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER ]; /* Short term FIR filtering*/ silk_warped_LPC_analysis_filter_FIX( P->sAR_shp, st_res_Q2, AR1_shp_Q13, px, psEnc->sCmn.warping_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder ); /* Reduce (mainly) low frequencies during harmonic emphasis */ B_Q10[ 0 ] = silk_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 4 ); tmp_32 = silk_SMLABB( SILK_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */ tmp_32 = silk_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */ tmp_32 = silk_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */ tmp_32 = silk_RSHIFT_ROUND( tmp_32, 14 ); /* Q10 */ B_Q10[ 1 ]= silk_SAT16( tmp_32 ); x_filt_Q12[ 0 ] = silk_MLA( silk_MUL( st_res_Q2[ 0 ], B_Q10[ 0 ] ), P->sHarmHP_Q2, B_Q10[ 1 ] ); for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { x_filt_Q12[ j ] = silk_MLA( silk_MUL( st_res_Q2[ j ], B_Q10[ 0 ] ), st_res_Q2[ j - 1 ], B_Q10[ 1 ] ); } P->sHarmHP_Q2 = st_res_Q2[ psEnc->sCmn.subfr_length - 1 ]; silk_prefilt_FIX( P, x_filt_Q12, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc->sCmn.subfr_length ); px += psEnc->sCmn.subfr_length; pxw_Q3 += psEnc->sCmn.subfr_length; } P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ]; RESTORE_STACK; }
void silk_find_LTP_FIX( opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ opus_int *LTPredCodGain_Q7, /* O LTP coding gain */ const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */ const opus_int subfr_length, /* I subframe length */ const opus_int nb_subfr, /* I number of subframes */ const opus_int mem_offset, /* I number of samples in LTP memory */ opus_int corr_rshifts[ MAX_NB_SUBFR ] /* O right shifts applied to correlations */ ) { opus_int i, k, lshift; const opus_int16 *r_ptr, *lag_ptr; opus_int16 *b_Q14_ptr; opus_int32 regu; opus_int32 *WLTP_ptr; opus_int32 b_Q16[ LTP_ORDER ], delta_b_Q14[ LTP_ORDER ], d_Q14[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], g_Q26; opus_int32 w[ MAX_NB_SUBFR ], WLTP_max, max_abs_d_Q14, max_w_bits; opus_int32 temp32, denom32; opus_int extra_shifts; opus_int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs; opus_int32 LPC_res_nrg, LPC_LTP_res_nrg, div_Q16; opus_int32 Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ]; opus_int32 wd, m_Q12; b_Q14_ptr = b_Q14; WLTP_ptr = WLTP; r_ptr = &r_lpc[ mem_offset ]; for( k = 0; k < nb_subfr; k++ ) { lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); silk_sum_sqr_shift( &rr[ k ], &rr_shifts, r_ptr, subfr_length ); /* rr[ k ] in Q( -rr_shifts ) */ /* Assure headroom */ LZs = silk_CLZ32( rr[k] ); if( LZs < LTP_CORRS_HEAD_ROOM ) { rr[ k ] = silk_RSHIFT_ROUND( rr[ k ], LTP_CORRS_HEAD_ROOM - LZs ); rr_shifts += ( LTP_CORRS_HEAD_ROOM - LZs ); } corr_rshifts[ k ] = rr_shifts; silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP_ptr, &corr_rshifts[ k ] ); /* WLTP_fix_ptr in Q( -corr_rshifts[ k ] ) */ /* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */ silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr, corr_rshifts[ k ] ); /* Rr_fix_ptr in Q( -corr_rshifts[ k ] ) */ if( corr_rshifts[ k ] > rr_shifts ) { rr[ k ] = silk_RSHIFT( rr[ k ], corr_rshifts[ k ] - rr_shifts ); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */ } silk_assert( rr[ k ] >= 0 ); regu = 1; regu = silk_SMLAWB( regu, rr[ k ], SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); silk_regularize_correlations_FIX( WLTP_ptr, &rr[k], regu, LTP_ORDER ); silk_solve_LDL_FIX( WLTP_ptr, LTP_ORDER, Rr, b_Q16 ); /* WLTP_fix_ptr and Rr_fix_ptr both in Q(-corr_rshifts[k]) */ /* Limit and store in Q14 */ silk_fit_LTP( b_Q16, b_Q14_ptr ); /* Calculate residual energy */ nrg[ k ] = silk_residual_energy16_covar_FIX( b_Q14_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER, 14 ); /* nrg_fix in Q( -corr_rshifts[ k ] ) */ /* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */ extra_shifts = silk_min_int( corr_rshifts[ k ], LTP_CORRS_HEAD_ROOM ); denom32 = silk_LSHIFT_SAT32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 + extra_shifts ) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */ silk_RSHIFT( silk_SMULWB( subfr_length, 655 ), corr_rshifts[ k ] - extra_shifts ); /* Q( -corr_rshifts[ k ] + extra_shifts ) */ denom32 = silk_max( denom32, 1 ); silk_assert( ((opus_int64)Wght_Q15[ k ] << 16 ) < silk_int32_MAX ); /* Wght always < 0.5 in Q0 */ temp32 = silk_DIV32( silk_LSHIFT( (opus_int32)Wght_Q15[ k ], 16 ), denom32 ); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */ temp32 = silk_RSHIFT( temp32, 31 + corr_rshifts[ k ] - extra_shifts - 26 ); /* Q26 */ /* Limit temp such that the below scaling never wraps around */ WLTP_max = 0; for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { WLTP_max = silk_max( WLTP_ptr[ i ], WLTP_max ); } lshift = silk_CLZ32( WLTP_max ) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor_fix */ silk_assert( 26 - 18 + lshift >= 0 ); if( 26 - 18 + lshift < 31 ) { temp32 = silk_min_32( temp32, silk_LSHIFT( (opus_int32)1, 26 - 18 + lshift ) ); } silk_scale_vector32_Q26_lshift_18( WLTP_ptr, temp32, LTP_ORDER * LTP_ORDER ); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */ w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER/2, LTP_ORDER/2, LTP_ORDER ); /* w in Q( 18 - corr_rshifts[ k ] ) */ silk_assert( w[k] >= 0 ); r_ptr += subfr_length; b_Q14_ptr += LTP_ORDER; WLTP_ptr += LTP_ORDER * LTP_ORDER; } maxRshifts = 0; for( k = 0; k < nb_subfr; k++ ) { maxRshifts = silk_max_int( corr_rshifts[ k ], maxRshifts ); } /* Compute LTP coding gain */ if( LTPredCodGain_Q7 != NULL ) { LPC_LTP_res_nrg = 0; LPC_res_nrg = 0; silk_assert( LTP_CORRS_HEAD_ROOM >= 2 ); /* Check that no overflow will happen when adding */ for( k = 0; k < nb_subfr; k++ ) { LPC_res_nrg = silk_ADD32( LPC_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( rr[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ LPC_LTP_res_nrg = silk_ADD32( LPC_LTP_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ } LPC_LTP_res_nrg = silk_max( LPC_LTP_res_nrg, 1 ); /* avoid division by zero */ div_Q16 = silk_DIV32_varQ( LPC_res_nrg, LPC_LTP_res_nrg, 16 ); *LTPredCodGain_Q7 = ( opus_int )silk_SMULBB( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ); silk_assert( *LTPredCodGain_Q7 == ( opus_int )silk_SAT16( silk_MUL( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ) ) ); } /* smoothing */ /* d = sum( B, 1 ); */ b_Q14_ptr = b_Q14; for( k = 0; k < nb_subfr; k++ ) { d_Q14[ k ] = 0; for( i = 0; i < LTP_ORDER; i++ ) { d_Q14[ k ] += b_Q14_ptr[ i ]; } b_Q14_ptr += LTP_ORDER; } /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ /* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */ max_abs_d_Q14 = 0; max_w_bits = 0; for( k = 0; k < nb_subfr; k++ ) { max_abs_d_Q14 = silk_max_32( max_abs_d_Q14, silk_abs( d_Q14[ k ] ) ); /* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */ /* Find bits needed in Q( 18 - maxRshifts ) */ max_w_bits = silk_max_32( max_w_bits, 32 - silk_CLZ32( w[ k ] ) + corr_rshifts[ k ] - maxRshifts ); } /* max_abs_d_Q14 = (5 << 15); worst case, i.e. LTP_ORDER * -silk_int16_MIN */ silk_assert( max_abs_d_Q14 <= ( 5 << 15 ) ); /* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */ extra_shifts = max_w_bits + 32 - silk_CLZ32( max_abs_d_Q14 ) - 14; /* Subtract what we got available; bits in output var plus maxRshifts */ extra_shifts -= ( 32 - 1 - 2 + maxRshifts ); /* Keep sign bit free as well as 2 bits for accumulation */ extra_shifts = silk_max_int( extra_shifts, 0 ); maxRshifts_wxtra = maxRshifts + extra_shifts; temp32 = silk_RSHIFT( 262, maxRshifts + extra_shifts ) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */ wd = 0; for( k = 0; k < nb_subfr; k++ ) { /* w has at least 2 bits of headroom so no overflow should happen */ temp32 = silk_ADD32( temp32, silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ) ); /* Q( 18 - maxRshifts_wxtra ) */ wd = silk_ADD32( wd, silk_LSHIFT( silk_SMULWW( silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ), d_Q14[ k ] ), 2 ) ); /* Q( 18 - maxRshifts_wxtra ) */ } m_Q12 = silk_DIV32_varQ( wd, temp32, 12 ); b_Q14_ptr = b_Q14; for( k = 0; k < nb_subfr; k++ ) { /* w_fix[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */ if( 2 - corr_rshifts[k] > 0 ) { temp32 = silk_RSHIFT( w[ k ], 2 - corr_rshifts[ k ] ); } else { temp32 = silk_LSHIFT_SAT32( w[ k ], corr_rshifts[ k ] - 2 ); } g_Q26 = silk_MUL( silk_DIV32( SILK_FIX_CONST( LTP_SMOOTHING, 26 ), silk_RSHIFT( SILK_FIX_CONST( LTP_SMOOTHING, 26 ), 10 ) + temp32 ), /* Q10 */ silk_LSHIFT_SAT32( silk_SUB_SAT32( (opus_int32)m_Q12, silk_RSHIFT( d_Q14[ k ], 2 ) ), 4 ) ); /* Q16 */ temp32 = 0; for( i = 0; i < LTP_ORDER; i++ ) { delta_b_Q14[ i ] = silk_max_16( b_Q14_ptr[ i ], 1638 ); /* 1638_Q14 = 0.1_Q0 */ temp32 += delta_b_Q14[ i ]; /* Q14 */ } temp32 = silk_DIV32( g_Q26, temp32 ); /* Q14 -> Q12 */ for( i = 0; i < LTP_ORDER; i++ ) { b_Q14_ptr[ i ] = silk_LIMIT_32( (opus_int32)b_Q14_ptr[ i ] + silk_SMULWB( silk_LSHIFT_SAT32( temp32, 4 ), delta_b_Q14[ i ] ), -16000, 28000 ); } b_Q14_ptr += LTP_ORDER; } }
/* notch filter just above Nyquist. */ void silk_resampler_private_up2_HQ( opus_int32 *S, /* I/O Resampler state [ 6 ] */ opus_int16 *out, /* O Output signal [ 2 * len ] */ const opus_int16 *in, /* I Input signal [ len ] */ opus_int32 len /* I Number of input samples */ ) { opus_int32 k; opus_int32 in32, out32_1, out32_2, Y, X; silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 ); silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 ); silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 ); silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 ); silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 ); silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 ); /* Internal variables and state are in Q10 format */ for( k = 0; k < len; k++ ) { /* Convert to Q10 */ in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 ); /* First all-pass section for even output sample */ Y = silk_SUB32( in32, S[ 0 ] ); X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] ); out32_1 = silk_ADD32( S[ 0 ], X ); S[ 0 ] = silk_ADD32( in32, X ); /* Second all-pass section for even output sample */ Y = silk_SUB32( out32_1, S[ 1 ] ); X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] ); out32_2 = silk_ADD32( S[ 1 ], X ); S[ 1 ] = silk_ADD32( out32_1, X ); /* Third all-pass section for even output sample */ Y = silk_SUB32( out32_2, S[ 2 ] ); X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] ); out32_1 = silk_ADD32( S[ 2 ], X ); S[ 2 ] = silk_ADD32( out32_2, X ); /* Apply gain in Q15, convert back to int16 and store to output */ out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); /* First all-pass section for odd output sample */ Y = silk_SUB32( in32, S[ 3 ] ); X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] ); out32_1 = silk_ADD32( S[ 3 ], X ); S[ 3 ] = silk_ADD32( in32, X ); /* Second all-pass section for odd output sample */ Y = silk_SUB32( out32_1, S[ 4 ] ); X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] ); out32_2 = silk_ADD32( S[ 4 ], X ); S[ 4 ] = silk_ADD32( out32_1, X ); /* Third all-pass section for odd output sample */ Y = silk_SUB32( out32_2, S[ 5 ] ); X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] ); out32_1 = silk_ADD32( S[ 5 ], X ); S[ 5 ] = silk_ADD32( out32_2, X ); /* Apply gain in Q15, convert back to int16 and store to output */ out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); } }
/* Downsample by a factor 2/3, low quality */ void silk_resampler_down2_3( opus_int32 *S, /* I/O State vector [ 6 ] */ opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ const opus_int16 *in, /* I Input signal [ inLen ] */ opus_int32 inLen /* I Number of input samples */ ) { opus_int32 nSamplesIn, counter, res_Q6; VARDECL( opus_int32, buf ); opus_int32 *buf_ptr; SAVE_STACK; ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 ); /* Copy buffered samples to start of buffer */ silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) ); /* Iterate over blocks of frameSizeIn input samples */ while( 1 ) { nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); /* Second-order AR filter (output in Q8) */ silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, silk_Resampler_2_3_COEFS_LQ, nSamplesIn ); /* Interpolate filtered signal */ buf_ptr = buf; counter = nSamplesIn; while( counter > 2 ) { /* Inner product */ res_Q6 = silk_SMULWB( buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); /* Scale down, saturate and store in output array */ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); res_Q6 = silk_SMULWB( buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); /* Scale down, saturate and store in output array */ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); buf_ptr += 3; counter -= 3; } in += nSamplesIn; inLen -= nSamplesIn; if( inLen > 0 ) { /* More iterations to do; copy last part of filtered signal to beginning of buffer */ silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); } else { break; } } /* Copy last part of filtered signal to the state for the next call */ silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); RESTORE_STACK; }
/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ void silk_VQ_WMat_EC( opus_int8 *ind, /* O index of best codebook vector */ opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ const opus_int16 *in_Q14, /* I input vector to be quantized */ const opus_int32 *W_Q18, /* I weighting matrix */ const opus_int8 *cb_Q7, /* I codebook */ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ opus_int L /* I number of vectors in codebook */ ) { opus_int k, gain_tmp_Q7; const opus_int8 *cb_row_Q7; opus_int16 diff_Q14[ 5 ]; opus_int32 sum1_Q14, sum2_Q16; /* Loop over codebook */ *rate_dist_Q14 = silk_int32_MAX; cb_row_Q7 = cb_Q7; for( k = 0; k < L; k++ ) { gain_tmp_Q7 = cb_gain_Q7[k]; diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 ); diff_Q14[ 1 ] = in_Q14[ 1 ] - silk_LSHIFT( cb_row_Q7[ 1 ], 7 ); diff_Q14[ 2 ] = in_Q14[ 2 ] - silk_LSHIFT( cb_row_Q7[ 2 ], 7 ); diff_Q14[ 3 ] = in_Q14[ 3 ] - silk_LSHIFT( cb_row_Q7[ 3 ], 7 ); diff_Q14[ 4 ] = in_Q14[ 4 ] - silk_LSHIFT( cb_row_Q7[ 4 ], 7 ); /* Weighted rate */ sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] ); /* Penalty for too large gain */ sum1_Q14 = silk_ADD_LSHIFT32( sum1_Q14, silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 10 ); silk_assert( sum1_Q14 >= 0 ); /* first row of W_Q18 */ sum2_Q16 = silk_SMULWB( W_Q18[ 1 ], diff_Q14[ 1 ] ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14[ 2 ] ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 3 ], diff_Q14[ 3 ] ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14[ 4 ] ); sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] ); sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] ); /* second row of W_Q18 */ sum2_Q16 = silk_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] ); sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] ); sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] ); /* third row of W_Q18 */ sum2_Q16 = silk_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] ); sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] ); sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] ); /* fourth row of W_Q18 */ sum2_Q16 = silk_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] ); sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] ); sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] ); /* last row of W_Q18 */ sum2_Q16 = silk_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] ); sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] ); silk_assert( sum1_Q14 >= 0 ); /* find best */ if( sum1_Q14 < *rate_dist_Q14 ) { *rate_dist_Q14 = sum1_Q14; *ind = (opus_int8)k; *gain_Q7 = gain_tmp_Q7; } /* Go to next cbk vector */ cb_row_Q7 += LTP_ORDER; } }
/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ opus_int32 silk_residual_energy16_covar_FIX( const opus_int16 *c, /* I Prediction vector */ const opus_int32 *wXX, /* I Correlation matrix */ const opus_int32 *wXx, /* I Correlation vector */ opus_int32 wxx, /* I Signal energy */ opus_int D, /* I Dimension */ opus_int cQ /* I Q value for c vector 0 - 15 */ ) { opus_int i, j, lshifts, Qxtra; opus_int32 c_max, w_max, tmp, tmp2, nrg; opus_int cn[ MAX_MATRIX_SIZE ]; const opus_int32 *pRow; /* Safety checks */ silk_assert( D >= 0 ); silk_assert( D <= 16 ); silk_assert( cQ > 0 ); silk_assert( cQ < 16 ); lshifts = 16 - cQ; Qxtra = lshifts; c_max = 0; for( i = 0; i < D; i++ ) { c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) ); } Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 ); w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] ); Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 ); Qxtra = silk_max_int( Qxtra, 0 ); for( i = 0; i < D; i++ ) { cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra ); silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */ } lshifts -= Qxtra; /* Compute wxx - 2 * wXx * c */ tmp = 0; for( i = 0; i < D; i++ ) { tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] ); } nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */ /* Add c' * wXX * c, assuming wXX is symmetric */ tmp2 = 0; for( i = 0; i < D; i++ ) { tmp = 0; pRow = &wXX[ i * D ]; for( j = i + 1; j < D; j++ ) { tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] ); } tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] ); tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] ); } nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */ /* Keep one bit free always, because we add them for LSF interpolation */ if( nrg < 1 ) { nrg = 1; } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) { nrg = silk_int32_MAX >> 1; } else {