summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoen Vos <koenvos@users.noreply.github.com>2016-06-02 21:19:16 +0800
committerKoen Vos <koenvos@users.noreply.github.com>2016-06-02 21:19:16 +0800
commitc7deab77a95335312c2d4f66af0634d44bec2f37 (patch)
tree63d49b035bf9373ce4ae034d68043547a2c17a3e
parentcce3d894215e16b6cc6abeb2cf194c771ac48a92 (diff)
downloadopus-silk_lsf_quant_with_hysteresis.tar.gz
bias in LSF quantization towards previously quantized LSFssilk_lsf_quant_with_hysteresis
-rw-r--r--silk/LPC_fit.c4
-rw-r--r--silk/NLSF_del_dec_quant.c28
-rw-r--r--silk/NLSF_encode.c311
-rw-r--r--silk/main.h6
-rw-r--r--silk/process_NLSFs.c2
-rw-r--r--silk/tuning_parameters.h5
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