mirror of
https://github.com/xiph/opus.git
synced 2025-06-02 16:47:42 +00:00
cng exitation signal can saturate. Use same scaling as PLC and normal decoding
This commit is contained in:
parent
e40df01625
commit
fab6397ae6
1 changed files with 32 additions and 29 deletions
61
silk/CNG.c
61
silk/CNG.c
|
@ -34,9 +34,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
/* Generates excitation for CNG LPC synthesis */
|
/* Generates excitation for CNG LPC synthesis */
|
||||||
static OPUS_INLINE void silk_CNG_exc(
|
static OPUS_INLINE void silk_CNG_exc(
|
||||||
opus_int32 exc_Q10[], /* O CNG excitation signal Q10 */
|
opus_int32 exc_Q14[], /* O CNG excitation signal Q10 */
|
||||||
opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */
|
opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */
|
||||||
opus_int32 Gain_Q16, /* I Gain to apply */
|
|
||||||
opus_int length, /* I Length */
|
opus_int length, /* I Length */
|
||||||
opus_int32 *rand_seed /* I/O Seed to random index generator */
|
opus_int32 *rand_seed /* I/O Seed to random index generator */
|
||||||
)
|
)
|
||||||
|
@ -55,7 +54,7 @@ static OPUS_INLINE void silk_CNG_exc(
|
||||||
idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask );
|
idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask );
|
||||||
silk_assert( idx >= 0 );
|
silk_assert( idx >= 0 );
|
||||||
silk_assert( idx <= CNG_BUF_MASK_MAX );
|
silk_assert( idx <= CNG_BUF_MASK_MAX );
|
||||||
exc_Q10[ i ] = (opus_int16)silk_SAT16( silk_SMULWW( exc_buf_Q14[ idx ], Gain_Q16 >> 4 ) );
|
exc_Q14[ i ] = exc_buf_Q14[ idx ];
|
||||||
}
|
}
|
||||||
*rand_seed = seed;
|
*rand_seed = seed;
|
||||||
}
|
}
|
||||||
|
@ -85,7 +84,7 @@ void silk_CNG(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
opus_int i, subfr;
|
opus_int i, subfr;
|
||||||
opus_int32 sum_Q6, max_Gain_Q16, gain_Q16;
|
opus_int32 LPC_pred_Q10, max_Gain_Q16, gain_Q16, gain_Q10;
|
||||||
opus_int16 A_Q12[ MAX_LPC_ORDER ];
|
opus_int16 A_Q12[ MAX_LPC_ORDER ];
|
||||||
silk_CNG_struct *psCNG = &psDec->sCNG;
|
silk_CNG_struct *psCNG = &psDec->sCNG;
|
||||||
SAVE_STACK;
|
SAVE_STACK;
|
||||||
|
@ -124,8 +123,8 @@ void silk_CNG(
|
||||||
|
|
||||||
/* Add CNG when packet is lost or during DTX */
|
/* Add CNG when packet is lost or during DTX */
|
||||||
if( psDec->lossCnt ) {
|
if( psDec->lossCnt ) {
|
||||||
VARDECL( opus_int32, CNG_sig_Q10 );
|
VARDECL( opus_int32, CNG_sig_Q14 );
|
||||||
ALLOC( CNG_sig_Q10, length + MAX_LPC_ORDER, opus_int32 );
|
ALLOC( CNG_sig_Q14, length + MAX_LPC_ORDER, opus_int32 );
|
||||||
|
|
||||||
/* Generate CNG excitation */
|
/* Generate CNG excitation */
|
||||||
gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] );
|
gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] );
|
||||||
|
@ -138,42 +137,46 @@ void silk_CNG(
|
||||||
gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 );
|
gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 );
|
||||||
gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 8 );
|
gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 8 );
|
||||||
}
|
}
|
||||||
silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, gain_Q16, length, &psCNG->rand_seed );
|
gain_Q10 = silk_RSHIFT( gain_Q16, 6 );
|
||||||
|
|
||||||
|
silk_CNG_exc( CNG_sig_Q14 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, length, &psCNG->rand_seed );
|
||||||
|
|
||||||
/* Convert CNG NLSF to filter representation */
|
/* Convert CNG NLSF to filter representation */
|
||||||
silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
|
silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
|
||||||
|
|
||||||
/* Generate CNG signal, by synthesis filtering */
|
/* Generate CNG signal, by synthesis filtering */
|
||||||
silk_memcpy( CNG_sig_Q10, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) );
|
silk_memcpy( CNG_sig_Q14, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) );
|
||||||
for( i = 0; i < length; i++ ) {
|
for( i = 0; i < length; i++ ) {
|
||||||
silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
|
silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
|
||||||
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
|
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
|
||||||
sum_Q6 = silk_RSHIFT( psDec->LPC_order, 1 );
|
LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
|
||||||
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ 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 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ 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 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
|
||||||
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
|
||||||
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
|
||||||
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
|
||||||
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
|
||||||
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ 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 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ 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 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
|
||||||
if( psDec->LPC_order == 16 ) {
|
if( psDec->LPC_order == 16 ) {
|
||||||
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ 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 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ 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 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ 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 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ 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 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ 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 ] );
|
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update states */
|
/* Update states */
|
||||||
CNG_sig_Q10[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q10[ MAX_LPC_ORDER + i ], sum_Q6, 4 );
|
CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q14[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
|
||||||
|
|
||||||
frame[ i ] = silk_ADD_SAT16( frame[ i ], silk_RSHIFT_ROUND( CNG_sig_Q10[ MAX_LPC_ORDER + i ], 10 ) );
|
/* Scale with Gain and add to input signal */
|
||||||
|
frame[ i ] = (opus_int16)silk_ADD_SAT16( frame[ i ], silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( CNG_sig_Q14[ MAX_LPC_ORDER + i ], gain_Q10 ), 8 ) ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q10[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
|
silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q14[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
|
||||||
} else {
|
} else {
|
||||||
silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) );
|
silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue