void SKP_Silk_resampler_private_ARMA4( SKP_int32 S[], /* I/O: State vector [ 4 ] */ SKP_int16 out[], /* O: Output signal */ const SKP_int16 in[], /* I: Input signal */ const SKP_int16 Coef[], /* I: ARMA coefficients [ 7 ] */ SKP_int32 len /* I: Signal length */ ) { SKP_int32 k; SKP_int32 in_Q8, out1_Q8, out2_Q8, X; for( k = 0; k < len; k++ ) { in_Q8 = SKP_LSHIFT32( (SKP_int32)in[ k ], 8 ); /* Outputs of first and second biquad */ out1_Q8 = SKP_ADD_LSHIFT32( in_Q8, S[ 0 ], 2 ); out2_Q8 = SKP_ADD_LSHIFT32( out1_Q8, S[ 2 ], 2 ); /* Update states, which are stored in Q6. Coefficients are in Q14 here */ X = SKP_SMLAWB( S[ 1 ], in_Q8, Coef[ 0 ] ); S[ 0 ] = SKP_SMLAWB( X, out1_Q8, Coef[ 2 ] ); X = SKP_SMLAWB( S[ 3 ], out1_Q8, Coef[ 1 ] ); S[ 2 ] = SKP_SMLAWB( X, out2_Q8, Coef[ 4 ] ); S[ 1 ] = SKP_SMLAWB( SKP_RSHIFT32( in_Q8, 2 ), out1_Q8, Coef[ 3 ] ); S[ 3 ] = SKP_SMLAWB( SKP_RSHIFT32( out1_Q8, 2 ), out2_Q8, Coef[ 5 ] ); /* Apply gain and store to output. The coefficient is in Q16 */ out[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT32( SKP_SMLAWB( 128, out2_Q8, Coef[ 6 ] ), 8 ) ); } }
/* Resample with a 2x downsampler (optional), a 2nd order AR filter followed by FIR interpolation */ void silk_resampler_private_down_FIR( void *SS, /* I/O: Resampler state */ opus_int16 out[], /* O: Output signal */ const opus_int16 in[], /* I: Input signal */ opus_int32 inLen /* I: Number of input samples */ ) { silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; opus_int32 nSamplesIn; opus_int32 max_index_Q16, index_increment_Q16; opus_int16 buf1[ RESAMPLER_MAX_BATCH_SIZE_IN / 2 ]; opus_int32 buf2[ RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_DOWN_ORDER_FIR ]; const opus_int16 *FIR_Coefs; /* Copy buffered samples to start of buffer */ SKP_memcpy( buf2, S->sFIR, RESAMPLER_DOWN_ORDER_FIR * sizeof( opus_int32 ) ); FIR_Coefs = &S->Coefs[ 2 ]; /* Iterate over blocks of frameSizeIn input samples */ index_increment_Q16 = S->invRatio_Q16; while( 1 ) { nSamplesIn = SKP_min( inLen, S->batchSize ); if( S->input2x == 1 ) { /* Downsample 2x */ silk_resampler_down2( S->sDown2, buf1, in, nSamplesIn ); nSamplesIn = SKP_RSHIFT32( nSamplesIn, 1 ); /* Second-order AR filter (output in Q8) */ silk_resampler_private_AR2( S->sIIR, &buf2[ RESAMPLER_DOWN_ORDER_FIR ], buf1, S->Coefs, nSamplesIn ); } else { /* Second-order AR filter (output in Q8) */ silk_resampler_private_AR2( S->sIIR, &buf2[ RESAMPLER_DOWN_ORDER_FIR ], in, S->Coefs, nSamplesIn ); } max_index_Q16 = SKP_LSHIFT32( nSamplesIn, 16 ); /* Interpolate filtered signal */ if( S->FIR_Fracs == 1 ) { out = silk_resampler_private_down_FIR_INTERPOL0(out, buf2, FIR_Coefs, max_index_Q16, index_increment_Q16); } else { out = silk_resampler_private_down_FIR_INTERPOL1(out, buf2, FIR_Coefs, max_index_Q16, index_increment_Q16, S->FIR_Fracs); } in += nSamplesIn << S->input2x; inLen -= nSamplesIn << S->input2x; if( inLen > S->input2x ) { /* More iterations to do; copy last part of filtered signal to beginning of buffer */ SKP_memcpy( buf2, &buf2[ nSamplesIn ], RESAMPLER_DOWN_ORDER_FIR * sizeof( opus_int32 ) ); } else { break; } } /* Copy last part of filtered signal to the state for the next call */ SKP_memcpy( S->sFIR, &buf2[ nSamplesIn ], RESAMPLER_DOWN_ORDER_FIR * sizeof( opus_int32 ) ); }
/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ void SKP_Silk_resampler_private_IIR_FIR( void *SS, /* I/O: Resampler state */ SKP_int16 out[], /* O: Output signal */ const SKP_int16 in[], /* I: Input signal */ SKP_int32 inLen /* I: Number of input samples */ ) { SKP_Silk_resampler_state_struct *S = (SKP_Silk_resampler_state_struct *)SS; SKP_int32 nSamplesIn, table_index; SKP_int32 max_index_Q16, index_Q16, index_increment_Q16, res_Q15; SKP_int16 buf[ 2 * RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_144 ]; SKP_int16 *buf_ptr; /* Copy buffered samples to start of buffer */ SKP_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); /* Iterate over blocks of frameSizeIn input samples */ index_increment_Q16 = S->invRatio_Q16; while( 1 ) { nSamplesIn = SKP_min( inLen, S->batchSize ); if( S->input2x == 1 ) { /* Upsample 2x */ S->up2_function( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_144 ], in, nSamplesIn ); } else { /* Fourth-order ARMA filter */ SKP_Silk_resampler_private_ARMA4( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_144 ], in, S->Coefs, nSamplesIn ); } max_index_Q16 = SKP_LSHIFT32( nSamplesIn, 16 + S->input2x ); /* +1 if 2x upsampling */ /* Interpolate upsampled signal and store in output array */ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { table_index = SKP_SMULWB( index_Q16 & 0xFFFF, 144 ); buf_ptr = &buf[ index_Q16 >> 16 ]; res_Q15 = SKP_SMULBB( buf_ptr[ 0 ], SKP_Silk_resampler_frac_FIR_144[ table_index ][ 0 ] ); res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 1 ], SKP_Silk_resampler_frac_FIR_144[ table_index ][ 1 ] ); res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 2 ], SKP_Silk_resampler_frac_FIR_144[ table_index ][ 2 ] ); res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 3 ], SKP_Silk_resampler_frac_FIR_144[ 143 - table_index ][ 2 ] ); res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 4 ], SKP_Silk_resampler_frac_FIR_144[ 143 - table_index ][ 1 ] ); res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 5 ], SKP_Silk_resampler_frac_FIR_144[ 143 - table_index ][ 0 ] ); *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q15, 15 ) ); } in += nSamplesIn; inLen -= nSamplesIn; if( inLen > 0 ) { /* More iterations to do; copy last part of filtered signal to beginning of buffer */ SKP_memcpy( buf, &buf[ nSamplesIn << S->input2x ], RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); } else { break; } } /* Copy last part of filtered signal to the state for the next call */ SKP_memcpy( S->sFIR, &buf[nSamplesIn << S->input2x ], RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); }
/* Autocorrelations for a warped frequency axis */ void silk_warped_autocorrelation_FIX( opus_int32 *corr, /* O Result [order + 1] */ opus_int *scale, /* O Scaling of the correlation vector */ const opus_int16 *input, /* I Input data to correlate */ const opus_int warping_Q16, /* I Warping coefficient */ const opus_int length, /* I Length of input */ const opus_int order /* I Correlation order (even) */ ) { opus_int n, i, lsh; opus_int32 tmp1_QS, tmp2_QS; opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; /* Order must be even */ SKP_assert( ( order & 1 ) == 0 ); SKP_assert( 2 * QS - QC >= 0 ); /* Loop over samples */ for( n = 0; n < length; n++ ) { tmp1_QS = SKP_LSHIFT32( ( opus_int32 )input[ n ], QS ); /* Loop over allpass sections */ for( i = 0; i < order; i += 2 ) { /* Output of allpass section */ tmp2_QS = SKP_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); state_QS[ i ] = tmp1_QS; corr_QC[ i ] += SKP_RSHIFT64( SKP_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); /* Output of allpass section */ tmp1_QS = SKP_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); state_QS[ i + 1 ] = tmp2_QS; corr_QC[ i + 1 ] += SKP_RSHIFT64( SKP_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC ); } state_QS[ order ] = tmp1_QS; corr_QC[ order ] += SKP_RSHIFT64( SKP_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); } lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35; lsh = SKP_LIMIT( lsh, -12 - QC, 30 - QC ); *scale = -( QC + lsh ); SKP_assert( *scale >= -30 && *scale <= 12 ); if( lsh >= 0 ) { for( i = 0; i < order + 1; i++ ) { corr[ i ] = ( opus_int32 )SKP_CHECK_FIT32( SKP_LSHIFT64( corr_QC[ i ], lsh ) ); } } else { for( i = 0; i < order + 1; i++ ) { corr[ i ] = ( opus_int32 )SKP_CHECK_FIT32( SKP_RSHIFT64( corr_QC[ i ], -lsh ) ); } } SKP_assert( corr_QC[ 0 ] >= 0 ); // If breaking, decrease QC }
/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ void SKP_Silk_resampler_private_IIR_FIR( void *SS, /* I/O: Resampler state */ SKP_int16 out[], /* O: Output signal */ const SKP_int16 in[], /* I: Input signal */ SKP_int32 inLen /* I: Number of input samples */ ) { SKP_Silk_resampler_state_struct *S = (SKP_Silk_resampler_state_struct *)SS; SKP_int32 nSamplesIn; SKP_int32 max_index_Q16, index_increment_Q16; SKP_int16 buf[ 2 * RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_144 ]; /* Copy buffered samples to start of buffer */ SKP_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); /* Iterate over blocks of frameSizeIn input samples */ index_increment_Q16 = S->invRatio_Q16; while( 1 ) { nSamplesIn = SKP_min( inLen, S->batchSize ); if( S->input2x == 1 ) { /* Upsample 2x */ S->up2_function( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_144 ], in, nSamplesIn ); } else { /* Fourth-order ARMA filter */ SKP_Silk_resampler_private_ARMA4( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_144 ], in, S->Coefs, nSamplesIn ); } max_index_Q16 = SKP_LSHIFT32( nSamplesIn, 16 + S->input2x ); /* +1 if 2x upsampling */ out = SKP_Silk_resampler_private_IIR_FIR_INTERPOL(out, buf, max_index_Q16, index_increment_Q16); in += nSamplesIn; inLen -= nSamplesIn; if( inLen > 0 ) { /* More iterations to do; copy last part of filtered signal to beginning of buffer */ SKP_memcpy( buf, &buf[ nSamplesIn << S->input2x ], RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); } else { break; } } /* Copy last part of filtered signal to the state for the next call */ SKP_memcpy( S->sFIR, &buf[nSamplesIn << S->input2x ], RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); }
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 ) ); } }
/* Compute reflection coefficients from input signal */ void SKP_Silk_burg_modified( SKP_int32 *res_nrg, /* O residual energy */ SKP_int *res_nrg_Q, /* O residual energy Q value */ SKP_int32 A_Q16[], /* O prediction coefficients (length order) */ const SKP_int16 x[], /* I input signal, length: nb_subfr * ( D + subfr_length ) */ const SKP_int subfr_length, /* I input signal subframe length (including D preceeding samples) */ const SKP_int nb_subfr, /* I number of subframes stacked in x */ const SKP_int32 WhiteNoiseFrac_Q32, /* I fraction added to zero-lag autocorrelation */ const SKP_int D /* I order */ ) { SKP_int k, n, s, lz, rshifts, rshifts_extra; SKP_int32 C0, num, nrg, rc_Q31, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; const SKP_int16 *x_ptr; SKP_int32 C_first_row[ SKP_Silk_MAX_ORDER_LPC ]; SKP_int32 C_last_row[ SKP_Silk_MAX_ORDER_LPC ]; SKP_int32 Af_QA[ SKP_Silk_MAX_ORDER_LPC ]; SKP_int32 CAf[ SKP_Silk_MAX_ORDER_LPC + 1 ]; SKP_int32 CAb[ SKP_Silk_MAX_ORDER_LPC + 1 ]; SKP_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); SKP_assert( nb_subfr <= MAX_NB_SUBFR ); /* Compute autocorrelations, added over subframes */ SKP_Silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); if( rshifts > MAX_RSHIFTS ) { C0 = SKP_LSHIFT32( C0, rshifts - MAX_RSHIFTS ); SKP_assert( C0 > 0 ); rshifts = MAX_RSHIFTS; } else { lz = SKP_Silk_CLZ32( C0 ) - 1; rshifts_extra = N_BITS_HEAD_ROOM - lz; if( rshifts_extra > 0 ) { rshifts_extra = SKP_min( rshifts_extra, MAX_RSHIFTS - rshifts ); C0 = SKP_RSHIFT32( C0, rshifts_extra ); } else { rshifts_extra = SKP_max( rshifts_extra, MIN_RSHIFTS - rshifts ); C0 = SKP_LSHIFT32( C0, -rshifts_extra ); } rshifts += rshifts_extra; } SKP_memset( C_first_row, 0, SKP_Silk_MAX_ORDER_LPC * sizeof( SKP_int32 ) ); if( rshifts > 0 ) { for( s = 0; s < nb_subfr; s++ ) { x_ptr = x + s * subfr_length; for( n = 1; n < D + 1; n++ ) { C_first_row[ n - 1 ] += (SKP_int32)SKP_RSHIFT64( SKP_Silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n ), rshifts ); } } } else { for( s = 0; s < nb_subfr; s++ ) { x_ptr = x + s * subfr_length; for( n = 1; n < D + 1; n++ ) { C_first_row[ n - 1 ] += SKP_LSHIFT32( SKP_Silk_inner_prod_aligned( x_ptr, x_ptr + n, subfr_length - n ), -rshifts ); } } } SKP_memcpy( C_last_row, C_first_row, SKP_Silk_MAX_ORDER_LPC * sizeof( SKP_int32 ) ); /* Initialize */ CAb[ 0 ] = CAf[ 0 ] = C0 + SKP_SMMUL( WhiteNoiseFrac_Q32, C0 ) + 1; // Q(-rshifts) for( n = 0; n < D; n++ ) { /* Update first row of correlation matrix (without first element) */ /* Update last row of correlation matrix (without last element, stored in reversed order) */ /* Update C * Af */ /* Update C * flipud(Af) (stored in reversed order) */ if( rshifts > -2 ) { for( s = 0; s < nb_subfr; s++ ) { x_ptr = x + s * subfr_length; x1 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], 16 - rshifts ); // Q(16-rshifts) x2 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); // Q(16-rshifts) tmp1 = SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], QA - 16 ); // Q(QA-16) tmp2 = SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); // Q(QA-16) for( k = 0; k < n; k++ ) { C_first_row[ k ] = SKP_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); // Q( -rshifts ) C_last_row[ k ] = SKP_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); // Q( -rshifts ) Atmp_QA = Af_QA[ k ]; tmp1 = SKP_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); // Q(QA-16) tmp2 = SKP_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); // Q(QA-16) } tmp1 = SKP_LSHIFT32( -tmp1, 32 - QA - rshifts ); // Q(16-rshifts) tmp2 = SKP_LSHIFT32( -tmp2, 32 - QA - rshifts ); // Q(16-rshifts) for( k = 0; k <= n; k++ ) { CAf[ k ] = SKP_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); // Q( -rshift ) CAb[ k ] = SKP_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); // Q( -rshift ) } } } else { for( s = 0; s < nb_subfr; s++ ) { x_ptr = x + s * subfr_length; x1 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], -rshifts ); // Q( -rshifts ) x2 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); // Q( -rshifts ) tmp1 = SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], 17 ); // Q17 tmp2 = SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], 17 ); // Q17 for( k = 0; k < n; k++ ) { C_first_row[ k ] = SKP_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); // Q( -rshifts ) C_last_row[ k ] = SKP_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); // Q( -rshifts ) Atmp1 = SKP_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); // Q17 tmp1 = SKP_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); // Q17 tmp2 = SKP_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); // Q17 } tmp1 = -tmp1; // Q17 tmp2 = -tmp2; // Q17 for( k = 0; k <= n; k++ ) { CAf[ k ] = SKP_SMLAWW( CAf[ k ], tmp1, SKP_LSHIFT32( (SKP_int32)x_ptr[ n - k ], -rshifts - 1 ) ); // Q( -rshift ) CAb[ k ] = SKP_SMLAWW( CAb[ k ], tmp2, SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) );// Q( -rshift ) } } } /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ tmp1 = C_first_row[ n ]; // Q( -rshifts ) tmp2 = C_last_row[ n ]; // Q( -rshifts ) num = 0; // Q( -rshifts ) nrg = SKP_ADD32( CAb[ 0 ], CAf[ 0 ] ); // Q( 1-rshifts ) for( k = 0; k < n; k++ ) { Atmp_QA = Af_QA[ k ]; lz = SKP_Silk_CLZ32( SKP_abs( Atmp_QA ) ) - 1; lz = SKP_min( 32 - QA, lz ); Atmp1 = SKP_LSHIFT32( Atmp_QA, lz ); // Q( QA + lz ) tmp1 = SKP_ADD_LSHIFT32( tmp1, SKP_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); // Q( -rshifts ) tmp2 = SKP_ADD_LSHIFT32( tmp2, SKP_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); // Q( -rshifts ) num = SKP_ADD_LSHIFT32( num, SKP_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); // Q( -rshifts ) nrg = SKP_ADD_LSHIFT32( nrg, SKP_SMMUL( SKP_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), Atmp1 ), 32 - QA - lz ); // Q( 1-rshifts ) } CAf[ n + 1 ] = tmp1; // Q( -rshifts ) CAb[ n + 1 ] = tmp2; // Q( -rshifts ) num = SKP_ADD32( num, tmp2 ); // Q( -rshifts ) num = SKP_LSHIFT32( -num, 1 ); // Q( 1-rshifts ) /* Calculate the next order reflection (parcor) coefficient */ if( SKP_abs( num ) < nrg ) { rc_Q31 = SKP_DIV32_varQ( num, nrg, 31 ); } else { /* Negative energy or ratio too high; set remaining coefficients to zero and exit loop */ SKP_memset( &Af_QA[ n ], 0, ( D - n ) * sizeof( SKP_int32 ) ); SKP_assert( 0 ); break; } /* Update the AR coefficients */ for( k = 0; k < (n + 1) >> 1; k++ ) { tmp1 = Af_QA[ k ]; // QA tmp2 = Af_QA[ n - k - 1 ]; // QA Af_QA[ k ] = SKP_ADD_LSHIFT32( tmp1, SKP_SMMUL( tmp2, rc_Q31 ), 1 ); // QA Af_QA[ n - k - 1 ] = SKP_ADD_LSHIFT32( tmp2, SKP_SMMUL( tmp1, rc_Q31 ), 1 ); // QA } Af_QA[ n ] = SKP_RSHIFT32( rc_Q31, 31 - QA ); // QA /* Update C * Af and C * Ab */ for( k = 0; k <= n + 1; k++ ) { tmp1 = CAf[ k ]; // Q( -rshifts ) tmp2 = CAb[ n - k + 1 ]; // Q( -rshifts ) CAf[ k ] = SKP_ADD_LSHIFT32( tmp1, SKP_SMMUL( tmp2, rc_Q31 ), 1 ); // Q( -rshifts ) CAb[ n - k + 1 ] = SKP_ADD_LSHIFT32( tmp2, SKP_SMMUL( tmp1, rc_Q31 ), 1 ); // Q( -rshifts ) } } /* Return residual energy */ nrg = CAf[ 0 ]; // Q( -rshifts ) tmp1 = 1 << 16; // Q16 for( k = 0; k < D; k++ ) { Atmp1 = SKP_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); // Q16 nrg = SKP_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); // Q( -rshifts ) tmp1 = SKP_SMLAWW( tmp1, Atmp1, Atmp1 ); // Q16 A_Q16[ k ] = -Atmp1; } *res_nrg = SKP_SMLAWW( nrg, SKP_SMMUL( WhiteNoiseFrac_Q32, C0 ), -tmp1 ); // Q( -rshifts ) *res_nrg_Q = -rshifts; }
void SKP_Silk_NSQ_wrapper_FLP( SKP_Silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ SKP_Silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ const SKP_float x[], /* I Prefiltered input signal */ SKP_int8 q[], /* O Quantized pulse signal */ const SKP_int useLBRR /* I LBRR flag */ ) { SKP_int i, j; SKP_float tmp_float; SKP_int16 x_16[ MAX_FRAME_LENGTH ]; /* Prediction and coding parameters */ SKP_int32 Gains_Q16[ NB_SUBFR ]; SKP_DWORD_ALIGN SKP_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ]; SKP_int LTP_scale_Q14; /* Noise shaping parameters */ /* Testing */ SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; SKP_int32 LF_shp_Q14[ NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ SKP_int Lambda_Q10; SKP_int Tilt_Q14[ NB_SUBFR ]; SKP_int HarmShapeGain_Q14[ NB_SUBFR ]; /* Convert control struct to fix control struct */ /* Noise shape parameters */ for( i = 0; i < NB_SUBFR * MAX_SHAPE_LPC_ORDER; i++ ) { AR2_Q13[ i ] = SKP_float2int( psEncCtrl->AR2[ i ] * 8192.0f ); } for( i = 0; i < NB_SUBFR; i++ ) { LF_shp_Q14[ i ] = SKP_LSHIFT32( SKP_float2int( psEncCtrl->LF_AR_shp[ i ] * 16384.0f ), 16 ) | (SKP_uint16)SKP_float2int( psEncCtrl->LF_MA_shp[ i ] * 16384.0f ); Tilt_Q14[ i ] = (SKP_int)SKP_float2int( psEncCtrl->Tilt[ i ] * 16384.0f ); HarmShapeGain_Q14[ i ] = (SKP_int)SKP_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f ); } Lambda_Q10 = ( SKP_int )SKP_float2int( psEncCtrl->Lambda * 1024.0f ); /* prediction and coding parameters */ for( i = 0; i < NB_SUBFR * LTP_ORDER; i++ ) { LTPCoef_Q14[ i ] = ( SKP_int16 )SKP_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f ); } for( j = 0; j < NB_SUBFR >> 1; j++ ) { for( i = 0; i < MAX_LPC_ORDER; i++ ) { PredCoef_Q12[ j ][ i ] = ( SKP_int16 )SKP_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f ); } } for( i = 0; i < NB_SUBFR; i++ ) { tmp_float = SKP_LIMIT( ( psEncCtrl->Gains[ i ] * 65536.0f ), 2147483000.0f, -2147483000.0f ); Gains_Q16[ i ] = SKP_float2int( tmp_float ); if( psEncCtrl->Gains[ i ] > 0.0f ) { SKP_assert( tmp_float >= 0.0f ); SKP_assert( Gains_Q16[ i ] >= 0 ); } } if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { LTP_scale_Q14 = SKP_Silk_LTPScales_table_Q14[ psEncCtrl->sCmn.LTP_scaleIndex ]; } else { LTP_scale_Q14 = 0; } /* Convert input to fix */ SKP_float2short_array( x_16, x, psEnc->sCmn.frame_length ); /* Call NSQ */ if( useLBRR ) { if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { SKP_Silk_NSQ_del_dec( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sNSQ_LBRR, x_16, q, psEncCtrl->sCmn.NLSFInterpCoef_Q2, PredCoef_Q12[ 0 ], LTPCoef_Q14, AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, Lambda_Q10, LTP_scale_Q14 ); } else { SKP_Silk_NSQ( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sNSQ_LBRR, x_16, q, psEncCtrl->sCmn.NLSFInterpCoef_Q2, PredCoef_Q12[ 0 ], LTPCoef_Q14, AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, Lambda_Q10, LTP_scale_Q14 ); } } else { if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { SKP_Silk_NSQ_del_dec( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sNSQ, x_16, q, psEncCtrl->sCmn.NLSFInterpCoef_Q2, PredCoef_Q12[ 0 ], LTPCoef_Q14, AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, Lambda_Q10, LTP_scale_Q14 ); } else { SKP_Silk_NSQ( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sNSQ, x_16, q, psEncCtrl->sCmn.NLSFInterpCoef_Q2, PredCoef_Q12[ 0 ], LTPCoef_Q14, AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, Lambda_Q10, LTP_scale_Q14 ); } } }
/* Resample with a 2x downsampler (optional), a 2nd order AR filter followed by FIR interpolation */ void SKP_Silk_resampler_private_down_FIR( void *SS, /* I/O: Resampler state */ SKP_int16 out[], /* O: Output signal */ const SKP_int16 in[], /* I: Input signal */ SKP_int32 inLen /* I: Number of input samples */ ) { SKP_Silk_resampler_state_struct *S = (SKP_Silk_resampler_state_struct *)SS; SKP_int32 nSamplesIn, interpol_ind; SKP_int32 max_index_Q16, index_Q16, index_increment_Q16, res_Q6; SKP_int16 buf1[ RESAMPLER_MAX_BATCH_SIZE_IN / 2 ]; SKP_int32 buf2[ RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_DOWN_ORDER_FIR ]; SKP_int32 *buf_ptr; const SKP_int16 *interpol_ptr, *FIR_Coefs; /* Copy buffered samples to start of buffer */ SKP_memcpy( buf2, S->sFIR, RESAMPLER_DOWN_ORDER_FIR * sizeof( SKP_int32 ) ); FIR_Coefs = &S->Coefs[ 2 ]; /* Iterate over blocks of frameSizeIn input samples */ index_increment_Q16 = S->invRatio_Q16; while( 1 ) { nSamplesIn = SKP_min( inLen, S->batchSize ); if( S->input2x == 1 ) { /* Downsample 2x */ SKP_Silk_resampler_down2( S->sDown2, buf1, in, nSamplesIn ); nSamplesIn = SKP_RSHIFT32( nSamplesIn, 1 ); /* Second-order AR filter (output in Q8) */ SKP_Silk_resampler_private_AR2( S->sIIR, &buf2[ RESAMPLER_DOWN_ORDER_FIR ], buf1, S->Coefs, nSamplesIn ); } else { /* Second-order AR filter (output in Q8) */ SKP_Silk_resampler_private_AR2( S->sIIR, &buf2[ RESAMPLER_DOWN_ORDER_FIR ], in, S->Coefs, nSamplesIn ); } max_index_Q16 = SKP_LSHIFT32( nSamplesIn, 16 ); /* Interpolate filtered signal */ if( S->FIR_Fracs == 1 ) { for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { /* Integer part gives pointer to buffered input */ buf_ptr = buf2 + SKP_RSHIFT( index_Q16, 16 ); /* Inner product */ res_Q6 = SKP_SMULWB( SKP_ADD32( buf_ptr[ 0 ], buf_ptr[ 11 ] ), FIR_Coefs[ 0 ] ); res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 1 ], buf_ptr[ 10 ] ), FIR_Coefs[ 1 ] ); res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 2 ], buf_ptr[ 9 ] ), FIR_Coefs[ 2 ] ); res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 3 ], buf_ptr[ 8 ] ), FIR_Coefs[ 3 ] ); res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 4 ], buf_ptr[ 7 ] ), FIR_Coefs[ 4 ] ); res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 5 ], buf_ptr[ 6 ] ), FIR_Coefs[ 5 ] ); /* Scale down, saturate and store in output array */ *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); } } else { for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { /* Integer part gives pointer to buffered input */ buf_ptr = buf2 + SKP_RSHIFT( index_Q16, 16 ); /* Fractional part gives interpolation coefficients */ interpol_ind = SKP_SMULWB( index_Q16 & 0xFFFF, S->FIR_Fracs ); /* Inner product */ interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR / 2 * interpol_ind ]; res_Q6 = SKP_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] ); interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR / 2 * ( S->FIR_Fracs - 1 - interpol_ind ) ]; res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 0 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 1 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 2 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 3 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 4 ] ); res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 5 ] ); /* Scale down, saturate and store in output array */ *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); } } in += nSamplesIn << S->input2x; inLen -= nSamplesIn << S->input2x; if( inLen > S->input2x ) { /* More iterations to do; copy last part of filtered signal to beginning of buffer */ SKP_memcpy( buf2, &buf2[ nSamplesIn ], RESAMPLER_DOWN_ORDER_FIR * sizeof( SKP_int32 ) ); } else { break; } } /* Copy last part of filtered signal to the state for the next call */ SKP_memcpy( S->sFIR, &buf2[ nSamplesIn ], RESAMPLER_DOWN_ORDER_FIR * sizeof( SKP_int32 ) ); }