/* 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 */ } }
/* 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 */ } }
/* 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_quant_LTP_gains( opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)quantized LTP gains */ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ opus_int8 *periodicity_index, /* O Periodicity Index */ opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */ opus_int mu_Q9, /* I Mu value (R/D tradeoff) */ opus_int lowComplexity, /* I Flag for low complexity */ const opus_int nb_subfr, /* I number of subframes */ int arch /* I Run-time architecture */ ) { opus_int j, k, cbk_size; opus_int8 temp_idx[ MAX_NB_SUBFR ]; const opus_uint8 *cl_ptr_Q5; const opus_int8 *cbk_ptr_Q7; const opus_uint8 *cbk_gain_ptr_Q7; const opus_int16 *b_Q14_ptr; const opus_int32 *W_Q18_ptr; opus_int32 rate_dist_Q14_subfr, rate_dist_Q14, min_rate_dist_Q14; opus_int32 sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7, gain_Q7; /***************************************************/ /* iterate over different codebooks with different */ /* rates/distortions, and choose best */ /***************************************************/ min_rate_dist_Q14 = silk_int32_MAX; best_sum_log_gain_Q7 = 0; for(k = 0; k < 3; k++) { /* Safety margin for pitch gain control, to take into account factors such as state rescaling/rewhitening. */ opus_int32 gain_safety = SILK_FIX_CONST(0.4, 7); cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ]; cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ]; cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[ k ]; cbk_size = silk_LTP_vq_sizes[ k ]; /* Set up pointer to first subframe */ W_Q18_ptr = W_Q18; b_Q14_ptr = B_Q14; rate_dist_Q14 = 0; sum_log_gain_tmp_Q7 = *sum_log_gain_Q7; for(j = 0; j < nb_subfr; j++) { max_gain_Q7 = silk_log2lin((SILK_FIX_CONST(MAX_SUM_LOG_GAIN_DB / 6.0, 7) - sum_log_gain_tmp_Q7) + SILK_FIX_CONST(7, 7)) - gain_safety; silk_VQ_WMat_EC( &temp_idx[ j ], /* O index of best codebook vector */ &rate_dist_Q14_subfr, /* O best weighted quantization error + mu * rate */ &gain_Q7, /* O sum of absolute LTP coefficients */ b_Q14_ptr, /* I input vector to be quantized */ W_Q18_ptr, /* I weighting matrix */ cbk_ptr_Q7, /* I codebook */ cbk_gain_ptr_Q7, /* I codebook effective gains */ cl_ptr_Q5, /* I code length for each codebook vector */ mu_Q9, /* I tradeoff between weighted error and rate */ max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ cbk_size, /* I number of vectors in codebook */ arch /* I Run-time architecture */ ); rate_dist_Q14 = silk_ADD_POS_SAT32(rate_dist_Q14, rate_dist_Q14_subfr); sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7 + silk_lin2log(gain_safety + gain_Q7) - SILK_FIX_CONST(7, 7)); b_Q14_ptr += LTP_ORDER; W_Q18_ptr += LTP_ORDER * LTP_ORDER; } /* Avoid never finding a codebook */ rate_dist_Q14 = silk_min(silk_int32_MAX - 1, rate_dist_Q14); if(rate_dist_Q14 < min_rate_dist_Q14) { min_rate_dist_Q14 = rate_dist_Q14; *periodicity_index = (opus_int8)k; silk_memcpy(cbk_index, temp_idx, nb_subfr * sizeof(opus_int8)); best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7; } /* Break early in low-complexity mode if rate distortion is below threshold */ if(lowComplexity && (rate_dist_Q14 < silk_LTP_gain_middle_avg_RD_Q14)) { break; } } cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ]; for(j = 0; j < nb_subfr; j++) { for(k = 0; k < LTP_ORDER; k++) { B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT(cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7); } } *sum_log_gain_Q7 = best_sum_log_gain_Q7; }
opus_int silk_encode_frame_FLP( silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ opus_int32 *pnBytesOut, /* O Number of payload bytes; */ ec_enc *psRangeEnc, /* I/O compressor data structure */ opus_int condCoding, /* I The type of conditional coding to use */ opus_int maxBits, /* I If > 0: maximum number of output bits */ opus_int useCBR /* I Flag to force constant-bitrate operation */ ) { silk_encoder_control_FLP sEncCtrl; opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; silk_float *x_frame, *res_pitch_frame; silk_float xfw[ MAX_FRAME_LENGTH ]; silk_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; ec_enc sRangeEnc_copy, sRangeEnc_copy2; silk_nsq_state sNSQ_copy, sNSQ_copy2; opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; opus_int32 gainsID, gainsID_lower, gainsID_upper; opus_int16 gainMult_Q8; opus_int16 ec_prevLagIndex_copy; opus_int ec_prevSignalType_copy; opus_int8 LastGainIndex_copy2; opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; opus_uint8 ec_buf_copy[ 1275 ]; /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; /**************************************************************/ /* Set up Input Pointers, and insert frame in input buffer */ /**************************************************************/ /* pointers aligned with start of frame to encode */ x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */ res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */ /***************************************/ /* Ensure smooth bandwidth transitions */ /***************************************/ silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); /*******************************************/ /* Copy new frame to front of input buffer */ /*******************************************/ silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */ for( i = 0; i < 8; i++ ) { x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f; } if( !psEnc->sCmn.prefillFlag ) { /*****************************************/ /* Find pitch lags, initial LPC analysis */ /*****************************************/ silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame ); /************************/ /* Noise shape analysis */ /************************/ silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); /***************************************************/ /* Find linear prediction coefficients (LPC + LTP) */ /***************************************************/ silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding ); /****************************************/ /* Process gains */ /****************************************/ silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding ); /*****************************************/ /* Prefiltering for noise shaper */ /*****************************************/ silk_prefilter_FLP( psEnc, &sEncCtrl, xfw, x_frame ); /****************************************/ /* Low Bitrate Redundant Encoding */ /****************************************/ silk_LBRR_encode_FLP( psEnc, &sEncCtrl, xfw, condCoding ); /* Loop over quantizer and entroy coding to control bitrate */ maxIter = 6; gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); found_lower = 0; found_upper = 0; gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); gainsID_lower = -1; gainsID_upper = -1; /* Copy part of the input state */ silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); seed_copy = psEnc->sCmn.indices.Seed; ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; for( iter = 0; ; iter++ ) { if( gainsID == gainsID_lower ) { nBits = nBits_lower; } else if( gainsID == gainsID_upper ) { nBits = nBits_upper; } else { /* Restore part of the input state */ if( iter > 0 ) { silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); psEnc->sCmn.indices.Seed = seed_copy; psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; } /*****************************************/ /* Noise shaping quantization */ /*****************************************/ silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw ); /****************************************/ /* Encode Parameters */ /****************************************/ silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); /****************************************/ /* Encode Excitation Signal */ /****************************************/ silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); nBits = ec_tell( psRangeEnc ); if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { break; } } if( iter == maxIter ) { if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { /* Restore output state from earlier iteration that did meet the bitrate budget */ silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); silk_assert( sRangeEnc_copy2.offs <= 1275 ); silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); psEnc->sShape.LastGainIndex = LastGainIndex_copy2; } break; } if( nBits > maxBits ) { if( found_lower == 0 && iter >= 2 ) { /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ sEncCtrl.Lambda *= 1.5f; found_upper = 0; gainsID_upper = -1; } else { found_upper = 1; nBits_upper = nBits; gainMult_upper = gainMult_Q8; gainsID_upper = gainsID; } } else if( nBits < maxBits - 5 ) { found_lower = 1; nBits_lower = nBits; gainMult_lower = gainMult_Q8; if( gainsID != gainsID_lower ) { gainsID_lower = gainsID; /* Copy part of the output state */ silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); silk_assert( psRangeEnc->offs <= 1275 ); silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; } } else { /* Within 5 bits of budget: close enough */ break; } if( ( found_lower & found_upper ) == 0 ) { /* Adjust gain according to high-rate rate/distortion curve */ opus_int32 gain_factor_Q16; gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) ); if( nBits > maxBits ) { gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) ); } gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); } else { /* Adjust gain by interpolating */ gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower ); /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); } else if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); } } for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 ); } /* Quantize gains */ psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); /* Unique identifier of gains vector */ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f; } } } /* Update input buffer */ silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) ); /* Parameters needed for next frame */ psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; /* Exit without entropy coding */ if( psEnc->sCmn.prefillFlag ) { /* No payload */ *pnBytesOut = 0; return ret; } /****************************************/ /* Finalize payload */ /****************************************/ psEnc->sCmn.first_frame_after_reset = 0; /* Payload size */ *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); return ret; }
void silk_find_pred_coefs_FIX( silk_encoder_state_FIX *psEnc, /* I/O encoder state */ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ const opus_int16 res_pitch[], /* I Residual from pitch analysis */ const opus_int16 x[], /* I Speech signal */ opus_int condCoding /* I The type of conditional coding to use */ ) { opus_int i; opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ], Wght_Q15[ MAX_NB_SUBFR ]; opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; const opus_int16 *x_ptr; opus_int16 *x_pre_ptr; VARDECL( opus_int16, LPC_in_pre ); opus_int32 tmp, min_gain_Q16, minInvGain_Q30; opus_int LTP_corrs_rshift[ MAX_NB_SUBFR ]; SAVE_STACK; /* weighting for weighted least squares */ min_gain_Q16 = silk_int32_MAX >> 6; for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] ); } for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { /* Divide to Q16 */ silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 ); /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */ invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 ); /* Ensure Wght_Q15 a minimum value 1 */ invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 363 ); /* Square the inverted gains */ silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) ); tmp = silk_SMULWB( invGains_Q16[ i ], invGains_Q16[ i ] ); Wght_Q15[ i ] = silk_RSHIFT( tmp, 1 ); /* Invert the inverted and normalized gains */ local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] ); } ALLOC( LPC_in_pre, psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder + psEnc->sCmn.frame_length, opus_int16 ); if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { VARDECL( opus_int32, WLTP ); /**********/ /* VOICED */ /**********/ silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); ALLOC( WLTP, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 ); /* LTP analysis */ silk_find_LTP_FIX( psEncCtrl->LTPCoef_Q14, WLTP, &psEncCtrl->LTPredCodGain_Q7, res_pitch, psEncCtrl->pitchL, Wght_Q15, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length, LTP_corrs_rshift ); /* Quantize LTP gain parameters */ silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, &psEnc->sCmn.sum_log_gain_Q7, WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr); /* Control LTP scaling */ silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding ); /* Create LTP residual */ silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14, psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); } else { /************/ /* UNVOICED */ /************/ /* Create signal with prepended subframes, scaled by inverse gains */ x_ptr = x - psEnc->sCmn.predictLPCOrder; x_pre_ptr = LPC_in_pre; for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ], psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; x_ptr += psEnc->sCmn.subfr_length; } silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) ); psEncCtrl->LTPredCodGain_Q7 = 0; psEnc->sCmn.sum_log_gain_Q7 = 0; } /* Limit on total predictive coding gain */ if( psEnc->sCmn.first_frame_after_reset ) { minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 ); } else { minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */ minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30, silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ), silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 ); } /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 ); /* Quantize LSFs */ silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); /* Calculate residual energy using quantized LPC coefficients */ silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); /* Copy to prediction struct for use in next frame for interpolation */ silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); RESTORE_STACK; }
int silk_encode_frame_FIX(silk_encoder_state_FIX * psEnc, /* I/O Pointer to Silk FIX encoder state */ int32_t * pnBytesOut, /* O Pointer to number of payload bytes; */ ec_enc * psRangeEnc, /* I/O compressor data structure */ int condCoding, /* I The type of conditional coding to use */ int maxBits, /* I If > 0: maximum number of output bits */ int useCBR /* I Flag to force constant-bitrate operation */ ) { silk_encoder_control_FIX sEncCtrl; int i, iter, maxIter, found_upper, found_lower, ret = 0; int16_t *x_frame; ec_enc sRangeEnc_copy, sRangeEnc_copy2; silk_nsq_state sNSQ_copy, sNSQ_copy2; int32_t seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; int32_t gainsID, gainsID_lower, gainsID_upper; int16_t gainMult_Q8; int16_t ec_prevLagIndex_copy; int ec_prevSignalType_copy; int8_t LastGainIndex_copy2; /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; /**************************************************************/ /* Set up Input Pointers, and insert frame in input buffer */ /*************************************************************/ /* start of frame to encode */ x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /***************************************/ /* Ensure smooth bandwidth transitions */ /***************************************/ silk_LP_variable_cutoff(&psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length); /*******************************************/ /* Copy new frame to front of input buffer */ /*******************************************/ memcpy(x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof(int16_t)); if (!psEnc->sCmn.prefillFlag) { int16_t *res_pitch_frame; int16_t res_pitch[psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length]; /* start of pitch LPC residual frame */ res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /*****************************************/ /* Find pitch lags, initial LPC analysis */ /*****************************************/ silk_find_pitch_lags_FIX(psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch); /************************/ /* Noise shape analysis */ /************************/ silk_noise_shape_analysis_FIX(psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch); /***************************************************/ /* Find linear prediction coefficients (LPC + LTP) */ /***************************************************/ silk_find_pred_coefs_FIX(psEnc, &sEncCtrl, res_pitch, x_frame, condCoding); /****************************************/ /* Process gains */ /****************************************/ silk_process_gains_FIX(psEnc, &sEncCtrl, condCoding); /*****************************************/ /* Prefiltering for noise shaper */ /*****************************************/ int32_t xfw_Q3[psEnc->sCmn.frame_length]; silk_prefilter_FIX(psEnc, &sEncCtrl, xfw_Q3, x_frame); /****************************************/ /* Low Bitrate Redundant Encoding */ /****************************************/ silk_LBRR_encode_FIX(psEnc, &sEncCtrl, xfw_Q3, condCoding); /* Loop over quantizer and entropy coding to control bitrate */ maxIter = 6; gainMult_Q8 = SILK_FIX_CONST(1, 8); found_lower = 0; found_upper = 0; gainsID = silk_gains_ID(psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr); gainsID_lower = -1; gainsID_upper = -1; /* Copy part of the input state */ memcpy(&sRangeEnc_copy, psRangeEnc, sizeof(ec_enc)); memcpy(&sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof(silk_nsq_state)); seed_copy = psEnc->sCmn.indices.Seed; ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; uint8_t ec_buf_copy[1275]; for (iter = 0;; iter++) { if (gainsID == gainsID_lower) { nBits = nBits_lower; } else if (gainsID == gainsID_upper) { nBits = nBits_upper; } else { /* Restore part of the input state */ if (iter > 0) { memcpy(psRangeEnc, &sRangeEnc_copy, sizeof(ec_enc)); memcpy(&psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof(silk_nsq_state)); psEnc->sCmn.indices.Seed = seed_copy; psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; } /*****************************************/ /* Noise shaping quantization */ /*****************************************/ if (psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0) { silk_NSQ_del_dec(&psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses, sEncCtrl. PredCoef_Q12[0], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl. HarmShapeGain_Q14, sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl. LTP_scale_Q14); } else { silk_NSQ(&psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses, sEncCtrl.PredCoef_Q12[0], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14); } /****************************************/ /* Encode Parameters */ /****************************************/ silk_encode_indices(&psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding); /****************************************/ /* Encode Excitation Signal */ /****************************************/ silk_encode_pulses(psRangeEnc, psEnc->sCmn.indices. signalType, psEnc->sCmn.indices. quantOffsetType, psEnc->sCmn.pulses, psEnc->sCmn.frame_length); nBits = ec_tell(psRangeEnc); if (useCBR == 0 && iter == 0 && nBits <= maxBits) { break; } } if (iter == maxIter) { if (found_lower && (gainsID == gainsID_lower || nBits > maxBits)) { /* Restore output state from earlier iteration that did meet the bitrate budget */ memcpy(psRangeEnc, &sRangeEnc_copy2, sizeof(ec_enc)); assert(sRangeEnc_copy2.offs <= 1275); memcpy(psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs); memcpy(&psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof(silk_nsq_state)); psEnc->sShape.LastGainIndex = LastGainIndex_copy2; } break; } if (nBits > maxBits) { if (found_lower == 0 && iter >= 2) { /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32(sEncCtrl. Lambda_Q10, sEncCtrl. Lambda_Q10, 1); found_upper = 0; gainsID_upper = -1; } else { found_upper = 1; nBits_upper = nBits; gainMult_upper = gainMult_Q8; gainsID_upper = gainsID; } } else if (nBits < maxBits - 5) { found_lower = 1; nBits_lower = nBits; gainMult_lower = gainMult_Q8; if (gainsID != gainsID_lower) { gainsID_lower = gainsID; /* Copy part of the output state */ memcpy(&sRangeEnc_copy2, psRangeEnc, sizeof(ec_enc)); assert(psRangeEnc->offs <= 1275); memcpy(ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs); memcpy(&sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof(silk_nsq_state)); LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; } } else { /* Within 5 bits of budget: close enough */ break; } if ((found_lower & found_upper) == 0) { /* Adjust gain according to high-rate rate/distortion curve */ int32_t gain_factor_Q16; gain_factor_Q16 = silk_log2lin(silk_LSHIFT(nBits - maxBits, 7) / psEnc->sCmn.frame_length + SILK_FIX_CONST(16, 7)); gain_factor_Q16 = silk_min_32(gain_factor_Q16, SILK_FIX_CONST(2, 16)); if (nBits > maxBits) { gain_factor_Q16 = silk_max_32(gain_factor_Q16, SILK_FIX_CONST(1.3, 16)); } gainMult_Q8 = silk_SMULWB(gain_factor_Q16, gainMult_Q8); } else { /* Adjust gain by interpolating */ assert(nBits_upper != nBits_lower); gainMult_Q8 = gainMult_lower + silk_DIV32_16(silk_MUL (gainMult_upper - gainMult_lower, maxBits - nBits_lower), nBits_upper - nBits_lower); /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ if (gainMult_Q8 > silk_ADD_RSHIFT32(gainMult_lower, gainMult_upper - gainMult_lower, 2)) { gainMult_Q8 = silk_ADD_RSHIFT32(gainMult_lower, gainMult_upper - gainMult_lower, 2); } else if (gainMult_Q8 < silk_SUB_RSHIFT32(gainMult_upper, gainMult_upper - gainMult_lower, 2)) { gainMult_Q8 = silk_SUB_RSHIFT32(gainMult_upper, gainMult_upper - gainMult_lower, 2); } } for (i = 0; i < psEnc->sCmn.nb_subfr; i++) { sEncCtrl.Gains_Q16[i] = silk_LSHIFT_SAT32(silk_SMULWB (sEncCtrl.GainsUnq_Q16[i], gainMult_Q8), 8); } /* Quantize gains */ psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; silk_gains_quant(psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16, &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr); /* Unique identifier of gains vector */ gainsID = silk_gains_ID(psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr); } } /* Update input buffer */ memmove(psEnc->x_buf, &psEnc->x_buf[psEnc->sCmn.frame_length], (psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz) * sizeof(int16_t)); /* Exit without entropy coding */ if (psEnc->sCmn.prefillFlag) { /* No payload */ *pnBytesOut = 0; return ret; } /* Parameters needed for next frame */ psEnc->sCmn.prevLag = sEncCtrl.pitchL[psEnc->sCmn.nb_subfr - 1]; psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; /****************************************/ /* Finalize payload */ /****************************************/ psEnc->sCmn.first_frame_after_reset = 0; /* Payload size */ *pnBytesOut = silk_RSHIFT(ec_tell(psRangeEnc) + 7, 3); return ret; }