From c7deab77a95335312c2d4f66af0634d44bec2f37 Mon Sep 17 00:00:00 2001 From: Koen Vos Date: Thu, 2 Jun 2016 21:19:16 +0800 Subject: bias in LSF quantization towards previously quantized LSFs --- silk/LPC_fit.c | 4 +- silk/NLSF_del_dec_quant.c | 28 ++--- silk/NLSF_encode.c | 311 ++++++++++++++++++++++++++++------------------ silk/main.h | 6 +- silk/process_NLSFs.c | 2 +- silk/tuning_parameters.h | 5 +- 6 files changed, 205 insertions(+), 151 deletions(-) diff --git a/silk/LPC_fit.c b/silk/LPC_fit.c index cdea4f3a..ac68dedf 100644 --- a/silk/LPC_fit.c +++ b/silk/LPC_fit.c @@ -34,14 +34,14 @@ POSSIBILITY OF SUCH DAMAGE. /* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */ void silk_LPC_fit( opus_int16 *a_QOUT, /* O Output signal */ - opus_int32 *a_QIN, /* I/O Input signal */ + opus_int32 *a_QIN, /* I/O Input signal */ const opus_int QOUT, /* I Input Q domain */ const opus_int QIN, /* I Input Q domain */ const opus_int d /* I Filter order */ ) { opus_int i, k, idx = 0; - opus_int32 maxabs, absval, chirp_Q16; + opus_int32 maxabs, absval, chirp_Q16; /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */ for( i = 0; i < 10; i++ ) { diff --git a/silk/NLSF_del_dec_quant.c b/silk/NLSF_del_dec_quant.c index 3895749b..b541e1fc 100644 --- a/silk/NLSF_del_dec_quant.c +++ b/silk/NLSF_del_dec_quant.c @@ -32,8 +32,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "main.h" /* Delayed-decision quantizer for NLSF residuals */ -opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ - opus_int8 indices[], /* O Quantization indices [ order ] */ +void silk_NLSF_del_dec_quant( + opus_int32 RD_out_Q25[], /* O RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices */ const opus_int16 x_Q10[], /* I Input [ order ] */ const opus_int16 w_Q5[], /* I Weights [ order ] */ const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ @@ -47,7 +48,7 @@ opus_int32 silk_NLSF_del_dec_quant( /* O Returns { opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10; opus_int pred_Q10, diff_Q10, out0_Q10, out1_Q10, rate0_Q5, rate1_Q5; - opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25, pred_coef_Q16; + opus_int32 RD_tmp_Q25, min_max_Q25, max_min_Q25, pred_coef_Q16; opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ]; opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ]; opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; @@ -194,22 +195,7 @@ opus_int32 silk_NLSF_del_dec_quant( /* O Returns } } - /* last sample: find winner, copy indices and return RD value */ - ind_tmp = 0; - min_Q25 = silk_int32_MAX; - for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) { - if( min_Q25 > RD_Q25[ j ] ) { - min_Q25 = RD_Q25[ j ]; - ind_tmp = j; - } - } - for( j = 0; j < order; j++ ) { - indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ]; - silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT ); - silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); - } - indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 ); - silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); - silk_assert( min_Q25 >= 0 ); - return min_Q25; + /* copy indices and RD values */ + silk_memcpy( indices, ind, NLSF_QUANT_DEL_DEC_STATES * MAX_LPC_ORDER * sizeof( opus_int8 ) ); + silk_memcpy( RD_out_Q25, RD_Q25, NLSF_QUANT_DEL_DEC_STATES * sizeof( opus_int32 ) ); } diff --git a/silk/NLSF_encode.c b/silk/NLSF_encode.c index 268b9a19..e0768ae5 100644 --- a/silk/NLSF_encode.c +++ b/silk/NLSF_encode.c @@ -1,124 +1,187 @@ -/*********************************************************************** -Copyright (c) 2006-2011, Skype Limited. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -- Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -- Neither the name of Internet Society, IETF or IETF Trust, nor the -names of specific contributors, may be used to endorse or promote -products derived from this software without specific prior written -permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -***********************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "main.h" -#include "stack_alloc.h" - -/***********************/ -/* NLSF vector encoder */ -/***********************/ -opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ - opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ - opus_int16 *pNLSF_Q15, /* I/O (Un)quantized NLSF vector [ LPC_ORDER ] */ - const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ - const opus_int16 *pW_Q2, /* I NLSF weight vector [ LPC_ORDER ] */ - const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ - const opus_int nSurvivors, /* I Max survivors after first stage */ - const opus_int signalType /* I Signal type: 0/1/2 */ -) -{ - opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7; - opus_int32 W_tmp_Q9, ret; - VARDECL( opus_int32, err_Q24 ); - VARDECL( opus_int32, RD_Q25 ); - VARDECL( opus_int, tempIndices1 ); - VARDECL( opus_int8, tempIndices2 ); - opus_int16 res_Q10[ MAX_LPC_ORDER ]; - opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ]; - opus_int16 W_adj_Q5[ MAX_LPC_ORDER ]; - opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; - opus_int16 ec_ix[ MAX_LPC_ORDER ]; - const opus_uint8 *pCB_element, *iCDF_ptr; - const opus_int16 *pCB_Wght_Q9; - SAVE_STACK; - - silk_assert( signalType >= 0 && signalType <= 2 ); - silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 ); - - /* NLSF stabilization */ - silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); - - /* First stage: VQ */ - ALLOC( err_Q24, psNLSF_CB->nVectors, opus_int32 ); - silk_NLSF_VQ( err_Q24, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->CB1_Wght_Q9, psNLSF_CB->nVectors, psNLSF_CB->order ); - - /* Sort the quantization errors */ - ALLOC( tempIndices1, nSurvivors, opus_int ); - silk_insertion_sort_increasing( err_Q24, tempIndices1, psNLSF_CB->nVectors, nSurvivors ); - - ALLOC( RD_Q25, nSurvivors, opus_int32 ); - ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 ); - - /* Loop over survivors */ - for( s = 0; s < nSurvivors; s++ ) { - ind1 = tempIndices1[ s ]; - - /* Residual after first stage */ - pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ]; - pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ ind1 * psNLSF_CB->order ]; - for( i = 0; i < psNLSF_CB->order; i++ ) { - NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 ); - W_tmp_Q9 = pCB_Wght_Q9[ i ]; - res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ], W_tmp_Q9 ), 14 ); - W_adj_Q5[ i ] = silk_DIV32_varQ( (opus_int32)pW_Q2[ i ], silk_SMULBB( W_tmp_Q9, W_tmp_Q9 ), 21 ); - } - - /* Unpack entropy table indices and predictor for current CB1 index */ - silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 ); - - /* Trellis quantizer */ - RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix, - psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order ); - - /* Add rate for first stage */ - iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ]; - if( ind1 == 0 ) { - prob_Q8 = 256 - iCDF_ptr[ ind1 ]; - } else { - prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ]; - } - bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 ); - RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) ); - } - - /* Find the lowest rate-distortion error */ - silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 ); - - NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ]; - silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) ); - - /* Decode */ - silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB ); - - ret = RD_Q25[ 0 ]; - RESTORE_STACK; - return ret; -} +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" +#include "stack_alloc.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O (Un)quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_Q2, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int16 *pNLSF_Q15_prev, /* I Previous Quantized NLSFs[ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +) +{ + opus_int i, s, ind1, prob_Q8, bits_q7; + opus_int32 W_tmp_Q9, R_Q25, ret; + VARDECL( opus_int32, err_Q24 ); + VARDECL( opus_int32, RD_Q25 ); + VARDECL( opus_int, tempIndices1 ); + VARDECL( opus_int8, tempIndices2 ); + VARDECL( opus_int, tempIndices3 ); + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ]; + opus_int16 W_adj_Q5[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + const opus_uint8 *pCB_element, *iCDF_ptr; + const opus_int16 *pCB_Wght_Q9; + SAVE_STACK; + + silk_assert( signalType >= 0 && signalType <= 2 ); + silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 ); + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); + + /* First stage: VQ */ + ALLOC( err_Q24, psNLSF_CB->nVectors, opus_int32 ); + silk_NLSF_VQ( err_Q24, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->CB1_Wght_Q9, psNLSF_CB->nVectors, psNLSF_CB->order ); + + /* Sort the quantization errors */ + ALLOC( tempIndices1, nSurvivors, opus_int ); + silk_insertion_sort_increasing( err_Q24, tempIndices1, psNLSF_CB->nVectors, nSurvivors ); + + ALLOC( RD_Q25, nSurvivors * NLSF_QUANT_DEL_DEC_STATES, opus_int32 ); + ALLOC( tempIndices2, nSurvivors * NLSF_QUANT_DEL_DEC_STATES * MAX_LPC_ORDER, opus_int8 ); + + /* Loop over survivors */ + for( s = 0; s < nSurvivors; s++ ) { + ind1 = tempIndices1[ s ]; + + /* Residual after first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ ind1 * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 ); + W_tmp_Q9 = pCB_Wght_Q9[ i ]; + res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ], W_tmp_Q9 ), 14 ); + W_adj_Q5[ i ] = silk_DIV32_varQ( (opus_int32)pW_Q2[ i ], silk_SMULBB( W_tmp_Q9, W_tmp_Q9 ), 21 ); + } + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 ); + + /* Trellis quantizer */ + silk_NLSF_del_dec_quant( &RD_Q25[ s * NLSF_QUANT_DEL_DEC_STATES ], &tempIndices2[ s * NLSF_QUANT_DEL_DEC_STATES * MAX_LPC_ORDER ], res_Q10, + W_adj_Q5, pred_Q8, ec_ix, psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order ); + + /* Add rate for first stage */ + iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ]; + if( ind1 == 0 ) { + prob_Q8 = 256 - iCDF_ptr[ ind1 ]; + } else { + prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ]; + } + bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 ); + R_Q25 = silk_SMULBB( bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) ); + for( i = 0; i < NLSF_QUANT_DEL_DEC_STATES; i++ ) { + RD_Q25[ s * NLSF_QUANT_DEL_DEC_STATES + i ] = silk_ADD32( RD_Q25[ s * NLSF_QUANT_DEL_DEC_STATES + i ], R_Q25 ); + } + } + + /* Find the lowest rate-distortion error */ + opus_int nSurvivors2 = nSurvivors; + ALLOC( tempIndices3, nSurvivors2, opus_int ); + silk_insertion_sort_increasing( RD_Q25, tempIndices3, nSurvivors * NLSF_QUANT_DEL_DEC_STATES, nSurvivors2 ); + + /* Loop over final survivors and copy indices */ + if( nSurvivors2 > 1 ) { + /* Bias quantizer towards previous quantized coefficients */ + opus_int16 pNLSF_Q15_best[ MAX_LPC_ORDER ]; + opus_int8 NLSFIndices_tmp[ MAX_LPC_ORDER + 1 ]; + opus_int16 pNLSF_Q15_tmp[ MAX_LPC_ORDER ]; + opus_int32 RD_Q25_best = silk_int32_MAX; + opus_int32 pNLSF_Q15_diff[ MAX_LPC_ORDER ], pNLSF_Q15_err[ MAX_LPC_ORDER ]; + opus_int32 sum_sqrd_Q22_prev, sum_sqrd_Q22, inv_norm_Q16, inner_prod_Q26, adj_Q16; + opus_int64 acc; + acc = 0; + for( i = 0; i < psNLSF_CB->order; i++ ) { + pNLSF_Q15_diff[ i ] = pNLSF_Q15[ i ] - pNLSF_Q15_prev[ i ]; + acc += (opus_int64)silk_MUL( pNLSF_Q15_diff[ i ], pNLSF_Q15_diff[ i ] ) * pW_Q2[ i ]; + } + sum_sqrd_Q22_prev = (opus_int32)silk_RSHIFT64( acc, 10 ); + silk_assert( sum_sqrd_Q22_prev >= 0 ); + inv_norm_Q16 = silk_INVERSE32_varQ( silk_SQRT_APPROX(sum_sqrd_Q22_prev + 1), 24 ); + for( i = 0; i < psNLSF_CB->order; i++ ) { + pNLSF_Q15_diff[ i ] = silk_SMULWW( inv_norm_Q16, pNLSF_Q15_diff[ i ] ); + } + for( s = 0; s < nSurvivors2; s++ ) { + NLSFIndices_tmp[ 0 ] = (opus_int8)tempIndices1[ tempIndices3[ s ] >> NLSF_QUANT_DEL_DEC_STATES_LOG2 ]; + silk_memcpy( &NLSFIndices_tmp[ 1 ], &tempIndices2[ tempIndices3[ s ] * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) ); + silk_NLSF_decode( pNLSF_Q15_tmp, NLSFIndices_tmp, psNLSF_CB ); + acc = 0; + for( i = 0; i < psNLSF_CB->order; i++ ) { + pNLSF_Q15_err[ i ] = pNLSF_Q15[ i ] - pNLSF_Q15_tmp[ i ]; + acc += (opus_int64)silk_MUL( pNLSF_Q15_err[ i ], pNLSF_Q15_err[ i ] ) * pW_Q2[ i ]; + } + sum_sqrd_Q22 = (opus_int32)silk_RSHIFT64( acc, 10 ); + silk_assert( sum_sqrd_Q22 >= 0 ); + inv_norm_Q16 = silk_INVERSE32_varQ( silk_SQRT_APPROX(sum_sqrd_Q22 + 1), 24 ); + + /* compute normalized inner product between quantization error and (difference between unquantized LSFs and previous quantized ones) */ + inner_prod_Q26 = 0; + for( i = 0; i < psNLSF_CB->order; i++ ) { + pNLSF_Q15_err[ i ] = silk_SMULWW( inv_norm_Q16, pNLSF_Q15_err[ i ] ); + inner_prod_Q26 += pNLSF_Q15_err[ i ] * pNLSF_Q15_diff[ i ] * pW_Q2[ i ]; + } + if( sum_sqrd_Q22_prev < sum_sqrd_Q22 ) { + inner_prod_Q26 = ( (opus_int64)inner_prod_Q26 * sum_sqrd_Q22_prev ) / sum_sqrd_Q22; + } + /* reduce RD value if quantization error is towards previous quantized LSFs; increase on the other side */ + adj_Q16 = silk_SMULWB( inner_prod_Q26, SILK_FIX_CONST(-LSF_QUANT_BIAS_TO_PREVIOUS, 6) ); + RD_Q25[ s ] = silk_SMLAWW( RD_Q25[ s ], RD_Q25[ s ], adj_Q16 ); + + if( RD_Q25[ s ] <= RD_Q25_best ) { + RD_Q25_best = RD_Q25[ s ]; + silk_memcpy( NLSFIndices, NLSFIndices_tmp, ( psNLSF_CB->order + 1 ) * sizeof( opus_int8 ) ); + silk_memcpy( pNLSF_Q15_best, pNLSF_Q15_tmp, psNLSF_CB->order * sizeof( opus_int16 ) ); + } + } + silk_memcpy( pNLSF_Q15, pNLSF_Q15_best, psNLSF_CB->order * sizeof( opus_int16 ) ); + ret = RD_Q25_best; + } else { + NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ tempIndices3[ 0 ] >> NLSF_QUANT_DEL_DEC_STATES_LOG2 ]; + silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ tempIndices3[ 0 ] * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) ); + silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB ); + ret = RD_Q25[ 0 ]; + } + + RESTORE_STACK; + return ret; +} diff --git a/silk/main.h b/silk/main.h index 94315b47..0587c0e3 100644 --- a/silk/main.h +++ b/silk/main.h @@ -332,6 +332,7 @@ opus_int32 silk_NLSF_encode( /* O Returns opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int16 *pNLSF_Q15_prev, /* I Prevoius quantized NLSFs [ LPC_ORDER ] */ const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ const opus_int nSurvivors, /* I Max survivors after first stage */ const opus_int signalType /* I Signal type: 0/1/2 */ @@ -348,8 +349,9 @@ void silk_NLSF_VQ( ); /* Delayed-decision quantizer for NLSF residuals */ -opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ - opus_int8 indices[], /* O Quantization indices [ order ] */ +void silk_NLSF_del_dec_quant( + opus_int32 RD_out_Q25[], /* O RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices */ const opus_int16 x_Q10[], /* I Input [ order ] */ const opus_int16 w_Q5[], /* I Weights [ order ] */ const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ diff --git a/silk/process_NLSFs.c b/silk/process_NLSFs.c index c27cf030..3ca2ddde 100644 --- a/silk/process_NLSFs.c +++ b/silk/process_NLSFs.c @@ -84,7 +84,7 @@ void silk_process_NLSFs( } } - silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW, + silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW, prev_NLSFq_Q15, NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType ); /* Convert quantized NLSFs back to LPC coefficients */ diff --git a/silk/tuning_parameters.h b/silk/tuning_parameters.h index cbf68bac..22a2df1f 100644 --- a/silk/tuning_parameters.h +++ b/silk/tuning_parameters.h @@ -50,7 +50,7 @@ extern "C" /* Linear prediction */ /*********************/ -/* LPC analysis defines: regularization and bandwidth expansion */ +/* LPC analysis regularization */ #define FIND_LPC_COND_FAC 1e-5f /***********************/ @@ -128,6 +128,9 @@ extern "C" /* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */ #define SUBFR_SMTH_COEF 0.4f +/* bias in LSF quantization towards previous quantized LSFs (0.0...1.0) */ +#define LSF_QUANT_BIAS_TO_PREVIOUS 0.3f + /* parameters defining the R/D tradeoff in the residual quantizer */ #define LAMBDA_OFFSET 1.2f #define LAMBDA_SPEECH_ACT -0.2f -- cgit v1.2.1