/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ SKP_INLINE void limit_warped_coefs( SKP_int32 *coefs_syn_Q24, SKP_int32 *coefs_ana_Q24, SKP_int lambda_Q16, SKP_int32 limit_Q24, SKP_int order ) { SKP_int i, iter, ind = 0; SKP_int32 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16; SKP_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 ] = SKP_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); coefs_ana_Q24[ i - 1 ] = SKP_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); } lambda_Q16 = -lambda_Q16; nom_Q16 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); gain_syn_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); gain_ana_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); for( i = 0; i < order; i++ ) { coefs_syn_Q24[ i ] = SKP_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); coefs_ana_Q24[ i ] = SKP_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 = SKP_max( SKP_abs_int32( coefs_syn_Q24[ i ] ), SKP_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 ] = SKP_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); coefs_ana_Q24[ i - 1 ] = SKP_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); } gain_syn_Q16 = SKP_INVERSE32_varQ( gain_syn_Q16, 32 ); gain_ana_Q16 = SKP_INVERSE32_varQ( gain_ana_Q16, 32 ); for( i = 0; i < order; i++ ) { coefs_syn_Q24[ i ] = SKP_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); coefs_ana_Q24[ i ] = SKP_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); } /* Apply bandwidth expansion */ chirp_Q16 = SKP_FIX_CONST( 0.99, 16 ) - SKP_DIV32_varQ( SKP_SMULWB( maxabs_Q24 - limit_Q24, SKP_SMLABB( SKP_FIX_CONST( 0.8, 10 ), SKP_FIX_CONST( 0.1, 10 ), iter ) ), SKP_MUL( maxabs_Q24, ind + 1 ), 22 ); SKP_Silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 ); SKP_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 ] = SKP_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); coefs_ana_Q24[ i - 1 ] = SKP_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); } lambda_Q16 = -lambda_Q16; nom_Q16 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); gain_syn_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); gain_ana_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); for( i = 0; i < order; i++ ) { coefs_syn_Q24[ i ] = SKP_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); coefs_ana_Q24[ i ] = SKP_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); } } SKP_assert( 0 ); }
/* compute whitening filter coefficients from normalized line spectral frequencies */ void SKP_Silk_NLSF2A(int16_t * a, /* o monic whitening filter coefficients in Q12, [d] */ const int *NLSF, /* i normalized line spectral frequencies in Q15, [d] */ const int d /* i filter order (should be even) */ ) { int k, i, dd; int32_t cos_LSF_Q20[SigProc_MAX_ORDER_LPC]; int32_t P[SigProc_MAX_ORDER_LPC / 2 + 1], Q[SigProc_MAX_ORDER_LPC / 2 + 1]; int32_t Ptmp, Qtmp; int32_t f_int; int32_t f_frac; int32_t cos_val, delta; int32_t a_int32[SigProc_MAX_ORDER_LPC]; int32_t maxabs, absval, idx = 0, sc_Q16; assert(LSF_COS_TAB_SZ_FIX == 128); memzero(a_int32, SigProc_MAX_ORDER_LPC * sizeof(int32_t)); memzero(cos_LSF_Q20, SigProc_MAX_ORDER_LPC * sizeof(int32_t)); /* convert LSFs to 2*cos(LSF(i)), using piecewise linear curve from table */ for (k = 0; k < d; k++) { assert(NLSF[k] >= 0); assert(NLSF[k] <= 32767); /* f_int on a scale 0-127 (rounded down) */ f_int = SKP_RSHIFT(NLSF[k], 15 - 7); /* f_frac, range: 0..255 */ f_frac = NLSF[k] - SKP_LSHIFT(f_int, 15 - 7); assert(f_int >= 0); assert(f_int < LSF_COS_TAB_SZ_FIX); /* Read start and end value from table */ cos_val = SKP_Silk_LSFCosTab_FIX_Q12[f_int]; /* Q12 */ delta = SKP_Silk_LSFCosTab_FIX_Q12[f_int + 1] - cos_val; /* Q12, with a range of 0..200 */ /* Linear interpolation */ cos_LSF_Q20[k] = SKP_LSHIFT(cos_val, 8) + SKP_MUL(delta, f_frac); /* Q20 */ } dd = SKP_RSHIFT(d, 1); assert(dd < SigProc_MAX_ORDER_LPC / 2 + 3); /* generate even and odd polynomials using convolution */ SKP_Silk_NLSF2A_find_poly(P, &cos_LSF_Q20[0], dd); SKP_Silk_NLSF2A_find_poly(Q, &cos_LSF_Q20[1], dd); /* convert even and odd polynomials to int32_t Q12 filter coefs */ for (k = 0; k < dd; k++) { Ptmp = P[k + 1] + P[k]; Qtmp = Q[k + 1] - Q[k]; /* the Ptmp and Qtmp values at this stage need to fit in int32 */ a_int32[k] = -SKP_RSHIFT_ROUND(Ptmp + Qtmp, 9); /* Q20 -> Q12 */ a_int32[d - k - 1] = SKP_RSHIFT_ROUND(Qtmp - Ptmp, 9); /* Q20 -> Q12 */ } /* Limit the maximum absolute value of the prediction coefficients */ for (i = 0; i < 10; i++) { /* Find maximum absolute value and its index */ maxabs = 0; for (k = 0; k < d; k++) { absval = SKP_abs(a_int32[k]); if (absval > maxabs) { maxabs = absval; idx = k; } } if (maxabs > int16_t_MAX) { /* Reduce magnitude of prediction coefficients */ sc_Q16 = 65470 - SKP_DIV32(SKP_MUL(65470 >> 2, maxabs - int16_t_MAX), SKP_RSHIFT32(SKP_MUL(maxabs, idx + 1), 2)); SKP_Silk_bwexpander_32(a_int32, d, sc_Q16); } else { break;
/* Finds LPC vector from correlations, and converts to NLSF */ void SKP_Silk_find_LPC_FIX( SKP_int NLSF_Q15[], /* O NLSFs */ SKP_int *interpIndex, /* O NLSF interpolation index, only used for NLSF interpolation */ const SKP_int prev_NLSFq_Q15[], /* I previous NLSFs, only used for NLSF interpolation */ const SKP_int useInterpolatedNLSFs, /* I Flag */ const SKP_int LPC_order, /* I LPC order */ const SKP_int16 x[], /* I Input signal */ const SKP_int subfr_length /* I Input signal subframe length including preceeding samples */ ) { SKP_int k; SKP_int32 a_Q16[ MAX_LPC_ORDER ]; SKP_int isInterpLower, shift; SKP_int16 S[ MAX_LPC_ORDER ]; SKP_int32 res_nrg0, res_nrg1; SKP_int rshift0, rshift1; /* Used only for LSF interpolation */ SKP_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; SKP_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; SKP_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; SKP_int NLSF0_Q15[ MAX_LPC_ORDER ]; SKP_int16 LPC_res[ ( MAX_FRAME_LENGTH + NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; /* Default: no interpolation */ *interpIndex = 4; /* Burg AR analysis for the full frame */ SKP_Silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, subfr_length, NB_SUBFR, SKP_FIX_CONST( FIND_LPC_COND_FAC, 32 ), LPC_order ); SKP_Silk_bwexpander_32( a_Q16, LPC_order, SKP_FIX_CONST( FIND_LPC_CHIRP, 16 ) ); if( useInterpolatedNLSFs == 1 ) { /* Optimal solution for last 10 ms */ SKP_Silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + ( NB_SUBFR >> 1 ) * subfr_length, subfr_length, ( NB_SUBFR >> 1 ), SKP_FIX_CONST( FIND_LPC_COND_FAC, 32 ), LPC_order ); SKP_Silk_bwexpander_32( a_tmp_Q16, LPC_order, SKP_FIX_CONST( FIND_LPC_CHIRP, 16 ) ); /* subtract residual energy here, as that's easier than adding it to the */ /* residual energy of the first 10 ms in each iteration of the search below */ shift = res_tmp_nrg_Q - res_nrg_Q; if( shift >= 0 ) { if( shift < 32 ) { res_nrg = res_nrg - SKP_RSHIFT( res_tmp_nrg, shift ); } } else { SKP_assert( shift > -32 ); res_nrg = SKP_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; res_nrg_Q = res_tmp_nrg_Q; } /* Convert to NLSFs */ SKP_Silk_A2NLSF( NLSF_Q15, a_tmp_Q16, LPC_order ); /* Search over interpolation indices to find the one with lowest residual energy */ for( k = 3; k >= 0; k-- ) { /* Interpolate NLSFs for first half */ SKP_Silk_interpolate( NLSF0_Q15, prev_NLSFq_Q15, NLSF_Q15, k, LPC_order ); /* Convert to LPC for residual energy evaluation */ SKP_Silk_NLSF2A_stable( a_tmp_Q12, NLSF0_Q15, LPC_order ); /* Calculate residual energy with NLSF interpolation */ SKP_memset( S, 0, LPC_order * sizeof( SKP_int16 ) ); SKP_Silk_LPC_analysis_filter( x, a_tmp_Q12, S, LPC_res, 2 * subfr_length, LPC_order ); SKP_Silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + LPC_order, subfr_length - LPC_order ); SKP_Silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + LPC_order + subfr_length, subfr_length - LPC_order ); /* Add subframe energies from first half frame */ shift = rshift0 - rshift1; if( shift >= 0 ) { res_nrg1 = SKP_RSHIFT( res_nrg1, shift ); res_nrg_interp_Q = -rshift0; } else { res_nrg0 = SKP_RSHIFT( res_nrg0, -shift ); res_nrg_interp_Q = -rshift1; } res_nrg_interp = SKP_ADD32( res_nrg0, res_nrg1 ); /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */ shift = res_nrg_interp_Q - res_nrg_Q; if( shift >= 0 ) { if( SKP_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { isInterpLower = SKP_TRUE; } else { isInterpLower = SKP_FALSE; } } else { if( -shift < 32 ) { if( res_nrg_interp < SKP_RSHIFT( res_nrg, -shift ) ) { isInterpLower = SKP_TRUE; } else { isInterpLower = SKP_FALSE; } } else { isInterpLower = SKP_FALSE; } } /* Determine whether current interpolated NLSFs are best so far */ if( isInterpLower == SKP_TRUE ) { /* Interpolation has lower residual energy */ res_nrg = res_nrg_interp; res_nrg_Q = res_nrg_interp_Q; *interpIndex = k; } } }
void SKP_Silk_noise_shape_analysis_FIX( SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ const SKP_int16 *pitch_res, /* I LPC residual from pitch analysis */ const SKP_int16 *x /* I Input signal [ frame_length + la_shape ] */ ) { SKP_Silk_shape_state_FIX *psShapeSt = &psEnc->sShape; SKP_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0; SKP_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; SKP_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; SKP_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; SKP_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; SKP_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; SKP_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ]; SKP_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ]; SKP_int16 x_windowed[ SHAPE_LPC_WIN_MAX ]; const SKP_int16 *x_ptr, *pitch_res_ptr; SKP_int32 sqrt_nrg[ NB_SUBFR ], Qnrg_vec[ NB_SUBFR ]; /* Point to start of first LPC analysis block */ x_ptr = x - psEnc->sCmn.la_shape; /****************/ /* CONTROL SNR */ /****************/ /* Reduce SNR_dB values if recent bitstream has exceeded TargetRate */ psEncCtrl->current_SNR_dB_Q7 = psEnc->SNR_dB_Q7 - SKP_SMULWB( SKP_LSHIFT( ( SKP_int32 )psEnc->BufferedInChannel_ms, 7 ), SKP_FIX_CONST( 0.05, 16 ) ); /* Reduce SNR_dB if inband FEC used */ if( psEnc->speech_activity_Q8 > SKP_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { psEncCtrl->current_SNR_dB_Q7 -= SKP_RSHIFT( psEnc->inBandFEC_SNR_comp_Q8, 1 ); } /****************/ /* GAIN CONTROL */ /****************/ /* Input quality is the average of the quality in the lowest two VAD bands */ psEncCtrl->input_quality_Q14 = ( SKP_int )SKP_RSHIFT( ( SKP_int32 )psEncCtrl->input_quality_bands_Q15[ 0 ] + psEncCtrl->input_quality_bands_Q15[ 1 ], 2 ); /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ psEncCtrl->coding_quality_Q14 = SKP_RSHIFT( SKP_Silk_sigm_Q15( SKP_RSHIFT_ROUND( psEncCtrl->current_SNR_dB_Q7 - SKP_FIX_CONST( 18.0, 7 ), 4 ) ), 1 ); /* Reduce coding SNR during low speech activity */ b_Q8 = SKP_FIX_CONST( 1.0, 8 ) - psEnc->speech_activity_Q8; b_Q8 = SKP_SMULWB( SKP_LSHIFT( b_Q8, 8 ), b_Q8 ); SNR_adj_dB_Q7 = SKP_SMLAWB( psEncCtrl->current_SNR_dB_Q7, SKP_SMULBB( SKP_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), // Q11 SKP_SMULWB( SKP_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); // Q12 if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { /* Reduce gains for periodic signals */ SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, SKP_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); } else { /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, SKP_SMLAWB( SKP_FIX_CONST( 6.0, 9 ), -SKP_FIX_CONST( 0.4, 18 ), psEncCtrl->current_SNR_dB_Q7 ), SKP_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); } /*************************/ /* SPARSENESS PROCESSING */ /*************************/ /* Set quantizer offset */ if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { /* Initally set to 0; may be overruled in process_gains(..) */ psEncCtrl->sCmn.QuantOffsetType = 0; psEncCtrl->sparseness_Q8 = 0; } else { /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ nSamples = SKP_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); energy_variation_Q7 = 0; log_energy_prev_Q7 = 0; pitch_res_ptr = pitch_res; for( k = 0; k < FRAME_LENGTH_MS / 2; k++ ) { SKP_Silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); nrg += SKP_RSHIFT( nSamples, scale ); // Q(-scale) log_energy_Q7 = SKP_Silk_lin2log( nrg ); if( k > 0 ) { energy_variation_Q7 += SKP_abs( log_energy_Q7 - log_energy_prev_Q7 ); } log_energy_prev_Q7 = log_energy_Q7; pitch_res_ptr += nSamples; } psEncCtrl->sparseness_Q8 = SKP_RSHIFT( SKP_Silk_sigm_Q15( SKP_SMULWB( energy_variation_Q7 - SKP_FIX_CONST( 5.0, 7 ), SKP_FIX_CONST( 0.1, 16 ) ) ), 7 ); /* Set quantization offset depending on sparseness measure */ if( psEncCtrl->sparseness_Q8 > SKP_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) { psEncCtrl->sCmn.QuantOffsetType = 0; } else { psEncCtrl->sCmn.QuantOffsetType = 1; } /* Increase coding SNR for sparse signals */ SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, SKP_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SKP_FIX_CONST( 0.5, 8 ) ); } /*******************************/ /* Control bandwidth expansion */ /*******************************/ /* More BWE for signals with high prediction gain */ strength_Q16 = SKP_SMULWB( psEncCtrl->predGain_Q16, SKP_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); BWExp1_Q16 = BWExp2_Q16 = SKP_DIV32_varQ( SKP_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), SKP_SMLAWW( SKP_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); delta_Q16 = SKP_SMULWB( SKP_FIX_CONST( 1.0, 16 ) - SKP_SMULBB( 3, psEncCtrl->coding_quality_Q14 ), SKP_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) ); BWExp1_Q16 = SKP_SUB32( BWExp1_Q16, delta_Q16 ); BWExp2_Q16 = SKP_ADD32( BWExp2_Q16, delta_Q16 ); /* BWExp1 will be applied after BWExp2, so make it relative */ BWExp1_Q16 = SKP_DIV32_16( SKP_LSHIFT( BWExp1_Q16, 14 ), SKP_RSHIFT( BWExp2_Q16, 2 ) ); if( psEnc->sCmn.warping_Q16 > 0 ) { /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ warping_Q16 = SKP_SMLAWB( psEnc->sCmn.warping_Q16, psEncCtrl->coding_quality_Q14, SKP_FIX_CONST( 0.01, 18 ) ); } else { warping_Q16 = 0; } /********************************************/ /* Compute noise shaping AR coefs and gains */ /********************************************/ for( k = 0; k < NB_SUBFR; k++ ) { /* Apply window: sine slope followed by flat part followed by cosine slope */ SKP_int shift, slope_part, flat_part; flat_part = psEnc->sCmn.fs_kHz * 5; slope_part = SKP_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); SKP_Silk_apply_sine_window_new( x_windowed, x_ptr, 1, slope_part ); shift = slope_part; SKP_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(SKP_int16) ); shift += flat_part; SKP_Silk_apply_sine_window_new( x_windowed + shift, x_ptr + shift, 2, slope_part ); /* Update pointer: next LPC analysis block */ x_ptr += psEnc->sCmn.subfr_length; if( psEnc->sCmn.warping_Q16 > 0 ) { /* Calculate warped auto correlation */ SKP_Silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); } else { /* Calculate regular auto correlation */ SKP_Silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); } /* Add white noise, as a fraction of energy */ auto_corr[0] = SKP_ADD32( auto_corr[0], SKP_max_32( SKP_SMULWB( SKP_RSHIFT( auto_corr[ 0 ], 4 ), SKP_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); /* Calculate the reflection coefficients using schur */ nrg = SKP_Silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); SKP_assert( nrg >= 0 ); /* Convert reflection coefficients to prediction coefficients */ SKP_Silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); Qnrg = -scale; // range: -12...30 SKP_assert( Qnrg >= -12 ); SKP_assert( Qnrg <= 30 ); /* Make sure that Qnrg is an even number */ if( Qnrg & 1 ) { Qnrg -= 1; nrg >>= 1; } tmp32 = SKP_Silk_SQRT_APPROX( nrg ); Qnrg >>= 1; // range: -6...15 sqrt_nrg[ k ] = tmp32; Qnrg_vec[ k ] = Qnrg; psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( tmp32, 16 - Qnrg ); if( psEnc->sCmn.warping_Q16 > 0 ) { /* Adjust gain for warping */ gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); SKP_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); psEncCtrl->Gains_Q16[ k ] = SKP_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); if( psEncCtrl->Gains_Q16[ k ] < 0 ) { psEncCtrl->Gains_Q16[ k ] = SKP_int32_MAX; } } /* Bandwidth expansion for synthesis filter shaping */ SKP_Silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 ); /* Compute noise shaping filter coefficients */ SKP_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( SKP_int32 ) ); /* Bandwidth expansion for analysis filter shaping */ SKP_assert( BWExp1_Q16 <= SKP_FIX_CONST( 1.0, 16 ) ); SKP_Silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 ); /* Ratio of prediction gains, in energy domain */ SKP_Silk_LPC_inverse_pred_gain_Q24( &pre_nrg_Q30, AR2_Q24, psEnc->sCmn.shapingLPCOrder ); SKP_Silk_LPC_inverse_pred_gain_Q24( &nrg, AR1_Q24, psEnc->sCmn.shapingLPCOrder ); //psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg; pre_nrg_Q30 = SKP_LSHIFT32( SKP_SMULWB( pre_nrg_Q30, SKP_FIX_CONST( 0.7, 15 ) ), 1 ); psEncCtrl->GainsPre_Q14[ k ] = ( SKP_int ) SKP_FIX_CONST( 0.3, 14 ) + SKP_DIV32_varQ( pre_nrg_Q30, nrg, 14 ); /* Convert to monic warped prediction coefficients and limit absolute values */ limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SKP_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); /* Convert from Q24 to Q13 and store in int16 */ for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) ); psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) ); } }
void SKP_Silk_noise_shape_analysis_FIX( SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ const SKP_int16 *pitch_res, /* I LPC residual from pitch analysis */ const SKP_int16 *x /* I Input signal [ 2 * frame_length + la_shape ]*/ ) { SKP_Silk_shape_state_FIX *psShapeSt = &psEnc->sShape; SKP_int k, nSamples, lz, Qnrg, b_Q14, scale = 0, sz; SKP_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; SKP_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; SKP_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; SKP_int32 auto_corr[ SHAPE_LPC_ORDER_MAX + 1 ]; SKP_int32 refl_coef_Q16[ SHAPE_LPC_ORDER_MAX ]; SKP_int32 AR_Q24[ SHAPE_LPC_ORDER_MAX ]; SKP_int16 x_windowed[ SHAPE_LPC_WIN_MAX ]; const SKP_int16 *x_ptr, *pitch_res_ptr; SKP_int32 sqrt_nrg[ NB_SUBFR ], Qnrg_vec[ NB_SUBFR ]; /* Point to start of first LPC analysis block */ x_ptr = x + psEnc->sCmn.la_shape - SKP_SMULBB( SHAPE_LPC_WIN_MS, psEnc->sCmn.fs_kHz ) + psEnc->sCmn.frame_length / NB_SUBFR; /****************/ /* CONTROL SNR */ /****************/ /* Reduce SNR_dB values if recent bitstream has exceeded TargetRate */ psEncCtrl->current_SNR_dB_Q7 = psEnc->SNR_dB_Q7 - SKP_SMULWB( SKP_LSHIFT( ( SKP_int32 )psEnc->BufferedInChannel_ms, 7 ), 3277 ); /* Reduce SNR_dB if inband FEC used */ if( psEnc->speech_activity_Q8 > LBRR_SPEECH_ACTIVITY_THRES_Q8 ) { psEncCtrl->current_SNR_dB_Q7 -= SKP_RSHIFT( psEnc->inBandFEC_SNR_comp_Q8, 1 ); } /****************/ /* GAIN CONTROL */ /****************/ /* Input quality is the average of the quality in the lowest two VAD bands */ psEncCtrl->input_quality_Q14 = ( SKP_int )SKP_RSHIFT( ( SKP_int32 )psEncCtrl->input_quality_bands_Q15[ 0 ] + psEncCtrl->input_quality_bands_Q15[ 1 ], 2 ); /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ psEncCtrl->coding_quality_Q14 = SKP_RSHIFT( SKP_Silk_sigm_Q15( SKP_RSHIFT_ROUND( psEncCtrl->current_SNR_dB_Q7 - ( 18 << 7 ), 4 ) ), 1 ); /* Reduce coding SNR during low speech activity */ b_Q8 = ( 1 << 8 ) - psEnc->speech_activity_Q8; b_Q8 = SKP_SMULWB( SKP_LSHIFT( b_Q8, 8 ), b_Q8 ); SNR_adj_dB_Q7 = SKP_SMLAWB( psEncCtrl->current_SNR_dB_Q7, SKP_SMULBB( -BG_SNR_DECR_dB_Q7 >> ( 4 + 1 ), b_Q8 ), // Q11 SKP_SMULWB( ( 1 << 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); // Q12 if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { /* Reduce gains for periodic signals */ SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, HARM_SNR_INCR_dB_Q7 << 1, psEnc->LTPCorr_Q15 ); } else { /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, SKP_SMLAWB( 6 << ( 7 + 2 ), -104856, psEncCtrl->current_SNR_dB_Q7 ), //-104856_Q18 = -0.4_Q0, Q9 ( 1 << 14 ) - psEncCtrl->input_quality_Q14 ); // Q14 } /*************************/ /* SPARSENESS PROCESSING */ /*************************/ /* Set quantizer offset */ if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { /* Initally set to 0; may be overruled in process_gains(..) */ psEncCtrl->sCmn.QuantOffsetType = 0; psEncCtrl->sparseness_Q8 = 0; } else { /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ nSamples = SKP_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); energy_variation_Q7 = 0; log_energy_prev_Q7 = 0; pitch_res_ptr = pitch_res; for( k = 0; k < FRAME_LENGTH_MS / 2; k++ ) { SKP_Silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); nrg += SKP_RSHIFT( nSamples, scale ); // Q(-scale) log_energy_Q7 = SKP_Silk_lin2log( nrg ); if( k > 0 ) { energy_variation_Q7 += SKP_abs( log_energy_Q7 - log_energy_prev_Q7 ); } log_energy_prev_Q7 = log_energy_Q7; pitch_res_ptr += nSamples; } psEncCtrl->sparseness_Q8 = SKP_RSHIFT( SKP_Silk_sigm_Q15( SKP_SMULWB( energy_variation_Q7 - ( 5 << 7 ), 6554 ) ), 7 ); // 6554_Q16 = 0.1_Q0 /* Set quantization offset depending on sparseness measure */ if( psEncCtrl->sparseness_Q8 > SPARSENESS_THRESHOLD_QNT_OFFSET_Q8 ) { psEncCtrl->sCmn.QuantOffsetType = 0; } else { psEncCtrl->sCmn.QuantOffsetType = 1; } /* Increase coding SNR for sparse signals */ SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, SPARSE_SNR_INCR_dB_Q7 << 8, psEncCtrl->sparseness_Q8 - ( 1 << 7 ) ); } /*******************************/ /* Control bandwidth expansion */ /*******************************/ delta_Q16 = SKP_SMULWB( ( 1 << 16 ) - SKP_SMULBB( 3, psEncCtrl->coding_quality_Q14 ), LOW_RATE_BANDWIDTH_EXPANSION_DELTA_Q16 ); BWExp1_Q16 = BANDWIDTH_EXPANSION_Q16 - delta_Q16; BWExp2_Q16 = BANDWIDTH_EXPANSION_Q16 + delta_Q16; if( psEnc->sCmn.fs_kHz == 24 ) { /* Less bandwidth expansion for super wideband */ BWExp1_Q16 = ( 1 << 16 ) - SKP_SMULWB( SWB_BANDWIDTH_EXPANSION_REDUCTION_Q16, ( 1 << 16 ) - BWExp1_Q16 ); BWExp2_Q16 = ( 1 << 16 ) - SKP_SMULWB( SWB_BANDWIDTH_EXPANSION_REDUCTION_Q16, ( 1 << 16 ) - BWExp2_Q16 ); } /* BWExp1 will be applied after BWExp2, so make it relative */ BWExp1_Q16 = SKP_DIV32_16( SKP_LSHIFT( BWExp1_Q16, 14 ), SKP_RSHIFT( BWExp2_Q16, 2 ) ); /********************************************/ /* Compute noise shaping AR coefs and gains */ /********************************************/ sz = ( SKP_int )SKP_SMULBB( SHAPE_LPC_WIN_MS, psEnc->sCmn.fs_kHz ); for( k = 0; k < NB_SUBFR; k++ ) { /* Apply window */ SKP_Silk_apply_sine_window( x_windowed, x_ptr, 0, SHAPE_LPC_WIN_MS * psEnc->sCmn.fs_kHz ); /* Update pointer: next LPC analysis block */ x_ptr += psEnc->sCmn.frame_length / NB_SUBFR; /* Calculate auto correlation */ SKP_Silk_autocorr( auto_corr, &scale, x_windowed, sz, psEnc->sCmn.shapingLPCOrder + 1 ); /* Add white noise, as a fraction of energy */ auto_corr[0] = SKP_ADD32( auto_corr[0], SKP_max_32( SKP_SMULWB( SKP_RSHIFT( auto_corr[ 0 ], 4 ), SHAPE_WHITE_NOISE_FRACTION_Q20 ), 1 ) ); /* Calculate the reflection coefficients using schur */ nrg = SKP_Silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); /* Convert reflection coefficients to prediction coefficients */ SKP_Silk_k2a_Q16( AR_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); /* Bandwidth expansion for synthesis filter shaping */ SKP_Silk_bwexpander_32( AR_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 ); /* Make sure to fit in Q13 SKP_int16 */ SKP_Silk_LPC_fit( &psEncCtrl->AR2_Q13[ k * SHAPE_LPC_ORDER_MAX ], AR_Q24, 13, psEnc->sCmn.shapingLPCOrder ); /* Compute noise shaping filter coefficients */ SKP_memcpy( &psEncCtrl->AR1_Q13[ k * SHAPE_LPC_ORDER_MAX ], &psEncCtrl->AR2_Q13[ k * SHAPE_LPC_ORDER_MAX ], psEnc->sCmn.shapingLPCOrder * sizeof( SKP_int16 ) ); /* Bandwidth expansion for analysis filter shaping */ SKP_assert( BWExp1_Q16 <= ( 1 << 16 ) ); // If ever breaking, use LPC_stabilize() in these cases to stay within range SKP_Silk_bwexpander( &psEncCtrl->AR1_Q13[ k * SHAPE_LPC_ORDER_MAX ], psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 ); /* Increase residual energy */ nrg = SKP_SMLAWB( nrg, SKP_RSHIFT( auto_corr[ 0 ], 8 ), SHAPE_MIN_ENERGY_RATIO_Q24 ); Qnrg = -scale; // range: -12...30 SKP_assert( Qnrg >= -12 ); SKP_assert( Qnrg <= 30 ); /* Make sure that Qnrg is an even number */ if( Qnrg & 1 ) { Qnrg -= 1; nrg >>= 1; } tmp32 = SKP_Silk_SQRT_APPROX( nrg ); Qnrg >>= 1; // range: -6...15 sqrt_nrg[ k ] = tmp32; Qnrg_vec[ k ] = Qnrg; psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( tmp32, 16 - Qnrg ); /* Ratio of prediction gains, in energy domain */ SKP_Silk_LPC_inverse_pred_gain_Q13( &pre_nrg_Q30, &psEncCtrl->AR2_Q13[ k * SHAPE_LPC_ORDER_MAX ], psEnc->sCmn.shapingLPCOrder ); SKP_Silk_LPC_inverse_pred_gain_Q13( &nrg, &psEncCtrl->AR1_Q13[ k * SHAPE_LPC_ORDER_MAX ], psEnc->sCmn.shapingLPCOrder ); lz = SKP_min_32( SKP_Silk_CLZ32( pre_nrg_Q30 ) - 1, 19 ); pre_nrg_Q30 = SKP_DIV32( SKP_LSHIFT( pre_nrg_Q30, lz ), SKP_RSHIFT( nrg, 20 - lz ) + 1 ); // Q20 pre_nrg_Q30 = SKP_RSHIFT( SKP_LSHIFT_SAT32( pre_nrg_Q30, 9 ), 1 ); /* Q28 */ psEncCtrl->GainsPre_Q14[ k ] = ( SKP_int )SKP_Silk_SQRT_APPROX( pre_nrg_Q30 ); }