Commit bf75c8ec authored by Koen Vos's avatar Koen Vos Committed by Jean-Marc Valin
Browse files

SILK fixes following last codec WG meeting

decoder:
- fixed incorrect scaling of filter states for the smallest quantization
  step sizes
- NLSF2A now limits the prediction gain of LPC filters

encoder:
- increased damping of LTP coefficients in LTP analysis
- increased white noise fraction in noise shaping LPC analysis
- introduced maximum total prediction gain.  Used by Burg's method to
  exit early if prediction gain is exceeded.  This improves packet
  loss robustness and numerical robustness in Burg's method
- Prefiltered signal is now in int32 Q10 domain, from int16 Q0
- Increased max number of iterations in CBR gain control loop from 5 to 6
- Removed useless code from LTP scaling control
- Optimization: smarter LPC loop unrolling
- Switched default win32 compile mode to be floating-point

resampler:
- made resampler have constant delay of 0.75 ms; removed delay
  compensation from silk code.
- removed obsolete table entries (~850 Bytes)
- increased downsampling filter order from 16 to 18/24/36 (depending on
  frequency ratio)
- reoptimized filter coefficients
parent 6619a736
......@@ -54,7 +54,7 @@ static inline void silk_CNG_exc(
idx = ( opus_int )( silk_RSHIFT( seed, 24 ) & exc_mask );
silk_assert( idx >= 0 );
silk_assert( idx <= CNG_BUF_MASK_MAX );
residual_Q10[ i ] = ( opus_int16 )silk_SAT16( silk_SMULWW( exc_buf_Q10[ idx ], Gain_Q16 ) );
residual_Q10[ i ] = (opus_int16)silk_SAT16( silk_SMULWW( exc_buf_Q10[ idx ], Gain_Q16 ) );
}
*rand_seed = seed;
}
......@@ -83,7 +83,7 @@ void silk_CNG(
opus_int length /* I Length of residual */
)
{
opus_int i, j, subfr;
opus_int i, subfr;
opus_int32 sum_Q6, max_Gain_Q16;
opus_int16 A_Q12[ MAX_LPC_ORDER ];
opus_int32 CNG_sig_Q10[ MAX_FRAME_LENGTH + MAX_LPC_ORDER ];
......@@ -133,7 +133,7 @@ void silk_CNG(
/* Generate CNG signal, by synthesis filtering */
silk_memcpy( CNG_sig_Q10, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) );
for( i = 0; i < length; i++ ) {
/* Partially unrolled */
silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
sum_Q6 = silk_SMULWB( CNG_sig_Q10[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
......@@ -144,8 +144,13 @@ void silk_CNG(
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
for( j = 10; j < psDec->LPC_order; j++ ) {
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
if( psDec->LPC_order == 16 ) {
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] );
}
/* Update states */
......
......@@ -77,7 +77,7 @@ void silk_LPC_analysis_filter(
out32 = silk_RSHIFT_ROUND( out32_Q12, 12 );
/* Saturate output */
out[ ix ] = ( opus_int16 )silk_SAT16( out32 );
out[ ix ] = (opus_int16)silk_SAT16( out32 );
}
/* Set first d output samples to zero */
......
......@@ -38,24 +38,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* Compute inverse of LPC prediction gain, and */
/* test if LPC coefficients are stable (all poles within unit circle) */
static opus_int LPC_inverse_pred_gain_QA( /* O Returns 1 if unstable, otherwise 0 */
opus_int32 *invGain_Q30, /* O Inverse prediction gain, Q30 energy domain */
opus_int32 A_QA[ 2 ][ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */
const opus_int order /* I Prediction order */
static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inverse prediction gain in energy domain, Q30 */
opus_int32 A_QA[ 2 ][ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */
const opus_int order /* I Prediction order */
)
{
opus_int k, n, mult2Q;
opus_int32 rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
opus_int32 *Aold_QA, *Anew_QA;
Anew_QA = A_QA[ order & 1 ];
*invGain_Q30 = ( 1 << 30 );
invGain_Q30 = 1 << 30;
for( k = order - 1; k > 0; k-- ) {
/* Check for stability */
if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) {
*invGain_Q30 = 0;
return 1;
return 0;
}
/* Set RC equal to negated AR coef */
......@@ -72,9 +70,9 @@ static opus_int LPC_inverse_pred_gain_QA( /* O Returns 1 if
/* Update inverse gain */
/* invGain_Q30 range: [ 0 : 2^30 ] */
*invGain_Q30 = silk_LSHIFT( silk_SMMUL( *invGain_Q30, rc_mult1_Q30 ), 2 );
silk_assert( *invGain_Q30 >= 0 );
silk_assert( *invGain_Q30 <= ( 1 << 30 ) );
invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
silk_assert( invGain_Q30 >= 0 );
silk_assert( invGain_Q30 <= ( 1 << 30 ) );
/* Swap pointers */
Aold_QA = Anew_QA;
......@@ -89,8 +87,7 @@ static opus_int LPC_inverse_pred_gain_QA( /* O Returns 1 if
/* Check for stability */
if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) {
*invGain_Q30 = 0;
return 1;
return 0;
}
/* Set RC equal to negated AR coef */
......@@ -101,16 +98,15 @@ static opus_int LPC_inverse_pred_gain_QA( /* O Returns 1 if
/* Update inverse gain */
/* Range: [ 0 : 2^30 ] */
*invGain_Q30 = silk_LSHIFT( silk_SMMUL( *invGain_Q30, rc_mult1_Q30 ), 2 );
silk_assert( *invGain_Q30 >= 0 );
silk_assert( *invGain_Q30 <= 1<<30 );
invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
silk_assert( invGain_Q30 >= 0 );
silk_assert( invGain_Q30 <= 1<<30 );
return 0;
return invGain_Q30;
}
/* For input in Q12 domain */
opus_int silk_LPC_inverse_pred_gain( /* O Returns 1 if unstable, otherwise 0 */
opus_int32 *invGain_Q30, /* O Inverse prediction gain, Q30 energy domain */
opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */
const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */
const opus_int order /* I Prediction order */
)
......@@ -118,30 +114,27 @@ opus_int silk_LPC_inverse_pred_gain( /* O Returns 1 if unstable
opus_int k;
opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
opus_int32 *Anew_QA;
opus_int32 DC_resp=0;
opus_int32 DC_resp = 0;
Anew_QA = Atmp_QA[ order & 1 ];
/* Increase Q domain of the AR coefficients */
for( k = 0; k < order; k++ ) {
DC_resp += (opus_int32)A_Q12[ k ];
Anew_QA[ k ] = silk_LSHIFT( (opus_int32)A_Q12[ k ], QA - 12 );
Anew_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 );
}
/* If the DC is unstable, we don't even need to do the full calculations */
if( DC_resp >= 4096 ) {
*invGain_Q30 = 0;
return 1;
return 0;
}
return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order );
return LPC_inverse_pred_gain_QA( Atmp_QA, order );
}
#ifdef FIXED_POINT
/* For input in Q24 domain */
/* This function is only used by the fixed-point build */
opus_int silk_LPC_inverse_pred_gain_Q24( /* O Returns 1 if unstable, otherwise 0 */
opus_int32 *invGain_Q30, /* O Inverse prediction gain, Q30 energy domain */
const opus_int32 *A_Q24, /* I Prediction coefficients, Q24 [order] */
opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */
const opus_int32 *A_Q24, /* I Prediction coefficients [order] */
const opus_int order /* I Prediction order */
)
{
......@@ -153,9 +146,9 @@ opus_int silk_LPC_inverse_pred_gain_Q24( /* O Returns 1 if unstabl
/* Increase Q domain of the AR coefficients */
for( k = 0; k < order; k++ ) {
Anew_QA[ k ] = silk_RSHIFT( A_Q24[ k ], 24 - QA );
Anew_QA[ k ] = silk_RSHIFT32( A_Q24[ k ], 24 - QA );
}
return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order );
return LPC_inverse_pred_gain_QA( Atmp_QA, order );
}
#endif
......@@ -91,24 +91,24 @@ static inline opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){
static inline opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) {
opus_int16 res;
res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) );
silk_assert( res == silk_SAT16( ( opus_int32 )a16 + ( opus_int32 )b16 ) );
silk_assert( res == silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) );
return res;
}
#undef silk_ADD_SAT32
static inline opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){
opus_int32 res;
res = ((((a32) + (b32)) & 0x80000000) == 0 ? \
res = ((((a32) + (b32)) & 0x80000000) == 0 ? \
((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \
((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) );
silk_assert( res == silk_SAT32( ( opus_int64 )a32 + ( opus_int64 )b32 ) );
silk_assert( res == silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) );
return res;
}
#undef silk_ADD_SAT64
static inline opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) {
opus_int64 res;
res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \
res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \
((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \
((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) );
if( res != a64 + b64 ) {
......@@ -126,24 +126,24 @@ static inline opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) {
static inline opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) {
opus_int16 res;
res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) );
silk_assert( res == silk_SAT16( ( opus_int32 )a16 - ( opus_int32 )b16 ) );
silk_assert( res == silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) );
return res;
}
#undef silk_SUB_SAT32
static inline opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) {
opus_int32 res;
res = ((((a32)-(b32)) & 0x80000000) == 0 ? \
res = ((((a32)-(b32)) & 0x80000000) == 0 ? \
(( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \
((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) );
silk_assert( res == silk_SAT32( ( opus_int64 )a32 - ( opus_int64 )b32 ) );
silk_assert( res == silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) );
return res;
}
#undef silk_SUB_SAT64
static inline opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) {
opus_int64 res;
res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \
res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \
(( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \
((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) );
......
......@@ -83,7 +83,7 @@ void silk_NLSF2A(
opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
opus_int32 maxabs, absval, idx=0, sc_Q16, invGain_Q30;
opus_int32 maxabs, absval, idx=0, sc_Q16;
silk_assert( LSF_COS_TAB_SZ_FIX == 128 );
silk_assert( d==10||d==16 );
......@@ -162,8 +162,8 @@ void silk_NLSF2A(
}
}
for( i = 1; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) {
if( silk_LPC_inverse_pred_gain( &invGain_Q30, a_Q12, d ) == 1 ) {
for( i = 1; i <= MAX_LPC_STABILIZE_ITERATIONS; i++ ) {
if( silk_LPC_inverse_pred_gain( a_Q12, d ) < SILK_FIX_CONST( 1.0 / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
/* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */
/* on the unscaled coefficients, convert to Q12 and measure again */
silk_bwexpander_32( a32_QA1, d, 65536 - silk_SMULBB( 9 + i, i ) ); /* 10_Q16 = 0.00015 */
......@@ -175,7 +175,7 @@ void silk_NLSF2A(
}
}
if( i == MAX_LPC_STABILIZE_ITERATIONS ) {
if( i > MAX_LPC_STABILIZE_ITERATIONS ) {
/* Reached the last iteration, set coefficients to zero */
for( k = 0; k < d; k++ ) {
a_Q12[ k ] = 0;
......
......@@ -51,11 +51,11 @@ void silk_NLSF_VQ(
sum_error_Q26 = 0;
for( m = 0; m < LPC_order; m += 2 ) {
/* Compute weighted squared quantization error for index m */
diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], ( opus_int32 )*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
sum_error_Q30 = silk_SMULBB( diff_Q15, diff_Q15 );
/* Compute weighted squared quantization error for index m + 1 */
diff_Q15 = silk_SUB_LSHIFT32( in_Q15[m + 1], ( opus_int32 )*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
diff_Q15 = silk_SUB_LSHIFT32( in_Q15[m + 1], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
sum_error_Q30 = silk_SMLABB( sum_error_Q30, diff_Q15, diff_Q15 );
sum_error_Q26 = silk_ADD_RSHIFT32( sum_error_Q26, sum_error_Q30, 4 );
......
......@@ -77,7 +77,7 @@ void silk_NLSF_decode(
/* Decode first stage */
pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ];
for( i = 0; i < psNLSF_CB->order; i++ ) {
pNLSF_Q15[ i ] = silk_LSHIFT( ( opus_int16 )pCB_element[ i ], 7 );
pNLSF_Q15[ i ] = silk_LSHIFT( (opus_int16)pCB_element[ i ], 7 );
}
/* Unpack entropy table indices and predictor for current CB1 index */
......@@ -91,8 +91,8 @@ void silk_NLSF_decode(
/* Apply inverse square-rooted weights and add to output */
for( i = 0; i < psNLSF_CB->order; i++ ) {
W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( ( opus_int32 )W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
NLSF_Q15_tmp = silk_ADD32( pNLSF_Q15[ i ], silk_DIV32_16( silk_LSHIFT( ( opus_int32 )res_Q10[ i ], 14 ), W_tmp_Q9 ) );
W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
NLSF_Q15_tmp = silk_ADD32( pNLSF_Q15[ i ], silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), W_tmp_Q9 ) );
pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 );
}
......
......@@ -79,7 +79,7 @@ opus_int32 silk_NLSF_encode( /* O Returns
/* Residual after first stage */
pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ];
for( i = 0; i < psNLSF_CB->order; i++ ) {
NLSF_tmp_Q15[ i ] = silk_LSHIFT16( ( opus_int16 )pCB_element[ i ], 7 );
NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 );
res_Q15[ i ] = pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ];
}
......@@ -88,13 +88,13 @@ opus_int32 silk_NLSF_encode( /* O Returns
/* Apply square-rooted weights */
for( i = 0; i < psNLSF_CB->order; i++ ) {
W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( ( opus_int32 )W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
res_Q10[ i ] = ( opus_int16 )silk_RSHIFT( silk_SMULBB( res_Q15[ i ], W_tmp_Q9 ), 14 );
W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( res_Q15[ i ], W_tmp_Q9 ), 14 );
}
/* Modify input weights accordingly */
for( i = 0; i < psNLSF_CB->order; i++ ) {
W_adj_Q5[ i ] = silk_DIV32_16( silk_LSHIFT( ( opus_int32 )pW_QW[ i ], 5 ), W_tmp_QW[ i ] );
W_adj_Q5[ i ] = silk_DIV32_16( silk_LSHIFT( (opus_int32)pW_QW[ i ], 5 ), W_tmp_QW[ i ] );
}
/* Unpack entropy table indices and predictor for current CB1 index */
......@@ -118,7 +118,7 @@ opus_int32 silk_NLSF_encode( /* O Returns
/* Find the lowest rate-distortion error */
silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 );
NLSFIndices[ 0 ] = ( opus_int8 )tempIndices1[ bestIndex ];
NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ];
silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) );
/* Decode */
......
......@@ -34,10 +34,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
static inline void silk_nsq_scale_states(
const silk_encoder_state *psEncC, /* I Encoder State */
silk_nsq_state *NSQ, /* I/O NSQ state */
const opus_int16 x[], /* I input in Q0 */
const opus_int32 x_Q10[], /* I input in Q0 */
opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
opus_int32 sLTP_Q16[], /* O LTP state matching scaled input */
opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
opus_int subfr, /* I subframe number */
const opus_int LTP_scale_Q14, /* I */
const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
......@@ -51,7 +51,7 @@ static inline void silk_noise_shape_quantizer(
const opus_int32 x_sc_Q10[], /* I */
opus_int8 pulses[], /* O */
opus_int16 xq[], /* O */
opus_int32 sLTP_Q16[], /* I/O LTP state */
opus_int32 sLTP_Q15[], /* I/O LTP state */
const opus_int16 a_Q12[], /* I Short term prediction coefs */
const opus_int16 b_Q14[], /* I Long term prediction coefs */
const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
......@@ -71,7 +71,7 @@ void silk_NSQ(
const silk_encoder_state *psEncC, /* I/O Encoder State */
silk_nsq_state *NSQ, /* I/O NSQ state */
SideInfoIndices *psIndices, /* I/O Quantization Indices */
const opus_int16 x[], /* I Prefiltered input signal */
const opus_int32 x_Q10[], /* I Prefiltered input signal */
opus_int8 pulses[], /* O Quantized pulse signal */
const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
......@@ -85,14 +85,14 @@ void silk_NSQ(
const opus_int LTP_scale_Q14 /* I LTP state scaling */
)
{
opus_int k, lag, start_idx, LSF_interpolation_flag;
const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
opus_int16 *pxq;
opus_int32 sLTP_Q16[ 2 * MAX_FRAME_LENGTH ];
opus_int16 sLTP[ 2 * MAX_FRAME_LENGTH ];
opus_int32 HarmShapeFIRPacked_Q14;
opus_int offset_Q10;
opus_int32 x_sc_Q10[ MAX_FRAME_LENGTH / MAX_NB_SUBFR ];
opus_int k, lag, start_idx, LSF_interpolation_flag;
const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
opus_int16 *pxq;
opus_int32 sLTP_Q15[ 2 * MAX_FRAME_LENGTH ];
opus_int16 sLTP[ 2 * MAX_FRAME_LENGTH ];
opus_int32 HarmShapeFIRPacked_Q14;
opus_int offset_Q10;
opus_int32 x_sc_Q10[ MAX_SUB_FRAME_LENGTH ];
NSQ->rand_seed = psIndices->Seed;
......@@ -109,7 +109,7 @@ void silk_NSQ(
LSF_interpolation_flag = 1;
}
/* Setup pointers to start of sub frame */
/* Set up pointers to start of sub frame */
NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
......@@ -121,7 +121,7 @@ void silk_NSQ(
/* Noise shape parameters */
silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
HarmShapeFIRPacked_Q14 |= silk_LSHIFT( ( opus_int32 )silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
NSQ->rewhite_flag = 0;
if( psIndices->signalType == TYPE_VOICED ) {
......@@ -142,13 +142,13 @@ void silk_NSQ(
}
}
silk_nsq_scale_states( psEncC, NSQ, x, x_sc_Q10, sLTP, sLTP_Q16, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType );
silk_nsq_scale_states( psEncC, NSQ, x_Q10, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType );
silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q16, A_Q12, B_Q14,
silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14,
AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10,
offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder );
x += psEncC->subfr_length;
x_Q10 += psEncC->subfr_length;
pulses += psEncC->subfr_length;
pxq += psEncC->subfr_length;
}
......@@ -170,7 +170,7 @@ static inline void silk_noise_shape_quantizer(
const opus_int32 x_sc_Q10[], /* I */
opus_int8 pulses[], /* O */
opus_int16 xq[], /* O */
opus_int32 sLTP_Q16[], /* I/O LTP state */
opus_int32 sLTP_Q15[], /* I/O LTP state */
const opus_int16 a_Q12[], /* I Short term prediction coefs */
const opus_int16 b_Q14[], /* I Long term prediction coefs */
const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
......@@ -187,16 +187,16 @@ static inline void silk_noise_shape_quantizer(
)
{
opus_int i, j;
opus_int32 LTP_pred_Q14, LPC_pred_Q10, n_AR_Q10, n_LTP_Q14;
opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q10, n_LTP_Q14;
opus_int32 n_LF_Q10, r_Q10, rr_Q10, q1_Q10, q2_Q10, rd1_Q10, rd2_Q10;
opus_int32 dither, exc_Q10, LPC_exc_Q10, xq_Q10;
opus_int32 tmp1, tmp2, sLF_AR_shp_Q10;
opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr;
shp_lag_ptr = &NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
pred_lag_ptr = &sLTP_Q16[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
/* Setup short term AR state */
/* Set up short term AR state */
psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ];
for( i = 0; i < length; i++ ) {
......@@ -207,11 +207,7 @@ static inline void silk_noise_shape_quantizer(
dither = silk_RSHIFT( NSQ->rand_seed, 31 );
/* Short-term prediction */
silk_assert( ( predictLPCOrder & 1 ) == 0 ); /* check that order is even */
silk_assert( ( (opus_int64)a_Q12 & 3 ) == 0 ); /* check that array starts at 4-byte aligned address */
silk_assert( predictLPCOrder >= 10 ); /* check that unrolling works */
/* Partially unrolled */
silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 );
LPC_pred_Q10 = silk_SMULWB( psLPC_Q14[ 0 ], a_Q12[ 0 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -1 ], a_Q12[ 1 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], a_Q12[ 2 ] );
......@@ -222,21 +218,26 @@ static inline void silk_noise_shape_quantizer(
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -7 ], a_Q12[ 7 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], a_Q12[ 8 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -9 ], a_Q12[ 9 ] );
for( j = 10; j < predictLPCOrder; j ++ ) {
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -j ], a_Q12[ j ] );
if( predictLPCOrder == 16 ) {
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -10 ], a_Q12[ 10 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -11 ], a_Q12[ 11 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -12 ], a_Q12[ 12 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -13 ], a_Q12[ 13 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -14 ], a_Q12[ 14 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -15 ], a_Q12[ 15 ] );
}
/* Long-term prediction */
if( signalType == TYPE_VOICED ) {
/* Unrolled loop */
LTP_pred_Q14 = silk_SMULWB( pred_lag_ptr[ 0 ], b_Q14[ 0 ] );
LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
LTP_pred_Q13 = silk_SMULWB( pred_lag_ptr[ 0 ], b_Q14[ 0 ] );
LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
pred_lag_ptr++;
} else {
LTP_pred_Q14 = 0;
LTP_pred_Q13 = 0;
}
/* Noise shape feedback */
......@@ -268,11 +269,11 @@ static inline void silk_noise_shape_quantizer(
if( lag > 0 ) {
/* Symmetric, packed FIR coefficients */
n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
n_LTP_Q14 = silk_LSHIFT( n_LTP_Q14, 6 );
shp_lag_ptr++;
tmp1 = silk_SUB32( LTP_pred_Q14, n_LTP_Q14 ); /* Add Q14 stuff */
tmp1 = silk_SUB32( LTP_pred_Q13 << 1, n_LTP_Q14 ); /* Add Q14 stuff */
tmp1 = silk_RSHIFT( tmp1, 4 ); /* convert to Q10 */
tmp1 = silk_ADD32( tmp1, LPC_pred_Q10 ); /* add Q10 stuff */
tmp1 = silk_SUB32( tmp1, n_AR_Q10 ); /* subtract Q10 stuff */
......@@ -324,18 +325,19 @@ static inline void silk_noise_shape_quantizer(
q1_Q10 = q2_Q10;
}
pulses[ i ] = ( opus_int8 )silk_RSHIFT_ROUND( q1_Q10, 10 );
pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 );
/* Excitation */
exc_Q10 = q1_Q10 ^ dither;
/* Add predictions */
LPC_exc_Q10 = silk_ADD32( exc_Q10, silk_RSHIFT_ROUND( LTP_pred_Q14, 4 ) );
LPC_exc_Q10 = silk_ADD32( exc_Q10, silk_RSHIFT_ROUND( LTP_pred_Q13, 3 ) );
xq_Q10 = silk_ADD32( LPC_exc_Q10, LPC_pred_Q10 );
/* Scale XQ back to normal level before saving */
xq[ i ] = ( opus_int16 )silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q10, Gain_Q16 ), 10 ) );
/* DEBUG_STORE_DATA( enc.pcm, &xq[i], sizeof( opus_int16 ) ) */
/* Update states */
psLPC_Q14++;
*psLPC_Q14 = silk_LSHIFT( xq_Q10, 4 );
......@@ -343,7 +345,7 @@ static inline void silk_noise_shape_quantizer(
NSQ->sLF_AR_shp_Q12 = silk_LSHIFT( sLF_AR_shp_Q10, 2 );
NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx ] = silk_SUB32( sLF_AR_shp_Q10, n_LF_Q10 );
sLTP_Q16[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q10, 6 );
sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q10, 5 );
NSQ->sLTP_shp_buf_idx++;
NSQ->sLTP_buf_idx++;
......@@ -358,10 +360,10 @@ static inline void silk_noise_shape_quantizer(
static inline void silk_nsq_scale_states(
const silk_encoder_state *psEncC, /* I Encoder State */
silk_nsq_state *NSQ, /* I/O NSQ state */
const opus_int16 x[], /* I input in Q0 */
const opus_int32 x_Q10[], /* I input in Q0 */
opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
opus_int32 sLTP_Q16[], /* O LTP state matching scaled input */
opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
opus_int subfr, /* I subframe number */
const opus_int LTP_scale_Q14, /* I */
const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
......@@ -370,22 +372,21 @@ static inline void silk_nsq_scale_states(
)
{
opus_int i, lag;
opus_int32 inv_gain_Q16, gain_adj_Q16, inv_gain_Q32;
opus_int32 inv_gain_Q16, gain_adj_Q16, inv_gain_Q31;
inv_gain_Q16 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 32 );
inv_gain_Q16 = silk_min( inv_gain_Q16, silk_int16_MAX );
lag = pitchL[ subfr ];
/* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
if( NSQ->rewhite_flag ) {
inv_gain_Q32 = silk_LSHIFT( inv_gain_Q16, 16 );
inv_gain_Q31 = silk_LSHIFT( inv_gain_Q16, 15 );
if( subfr == 0 ) {
/* Do LTP downscaling */
inv_gain_Q32 = silk_LSHIFT( silk_SMULWB( inv_gain_Q32, LTP_scale_Q14 ), 2 );
inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
}
for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
silk_assert( i < MAX_FRAME_LENGTH );
sLTP_Q16[ i ] = silk_SMULWB( inv_gain_Q32, sLTP[ i ] );
sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
}
}
......@@ -401,7 +402,7 @@ static inline void silk_nsq_scale_states(
/* Scale long-term prediction state */
if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
sLTP_Q16[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q16[ i ] );
sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
}
}
......@@ -418,10 +419,10 @@ static inline void silk_nsq_scale_states(
/* Scale input */
for( i = 0; i < psEncC->subfr_length; i++ ) {
x_sc_Q10[ i ] = silk_RSHIFT( silk_SMULBB( x[ i ], ( opus_int16 )inv_gain_Q16 ), 6 );
x_sc_Q10[ i ] = silk_SMULWW( x_Q10[ i ], inv_gain_Q16 );
}
/* save inv_gain */
/* Save inv_gain */
silk_assert( inv_gain_Q16 != 0 );
NSQ->prev_inv_gain_Q16 = inv_gain_Q16;