Commit f6e781ab authored by Jean-Marc Valin's avatar Jean-Marc Valin
Browse files

Addressing multiple LSF-related issues

- Merged the LPC stabilization from NLSF2A_stable.c into NLSF2A.c
- The bandwidth expansion in NLSF2A() now operates on int32 LPC coefficients in
Q17 domain (instead of int16 Q12 coefficients)
- The function bwexpander_32() has a more precise way of updating the chirp
variable (round to nearest, instead of round down)
- Changed a few variables in NLSF_stabilize() from int16 to int32 to avoid signed
wrap-around (no difference in results as the wrap-around would always be reversed
later)
- The LSF codebook for WB speech has a quantization stepsize of 0.15 (was 0.16).
This doesn't break the bitstream, although it slightly limits quality of signals
encoded with the old version and decoded with the new one (I can't really hear it
and PESQ gives high scores as well).  I does improve handling of tonal signals.
- As discussed: the Q-domain of the poly function is now in Q16 (was Q20)
- As discussed: limiting the LSFs in NLSF_decode() to 0...32767
- The silk_NLSF_DELTA_MIN values were lowered to deal with a possible future situation with less or no input HP filtering.
parent 8019e4e3
......@@ -97,7 +97,7 @@ void silk_find_LPC_FIX(
silk_interpolate( NLSF0_Q15, prev_NLSFq_Q15, NLSF_Q15, k, LPC_order );
/* Convert to LPC for residual energy evaluation */
silk_NLSF2A_stable( a_tmp_Q12, NLSF0_Q15, LPC_order );
silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, LPC_order );
/* Calculate residual energy with NLSF interpolation */
silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, LPC_order );
......
......@@ -79,7 +79,7 @@ void silk_find_LPC_FLP(
silk_interpolate( NLSF0_Q15, prev_NLSFq_Q15, NLSF_Q15, k, LPC_order );
/* Convert to LPC for residual energy evaluation */
silk_NLSF2A_stable_FLP( a_tmp, NLSF0_Q15, LPC_order );
silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, LPC_order );
/* Calculate residual energy with LSF interpolation */
silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, LPC_order );
......
......@@ -291,7 +291,7 @@ void silk_apply_sine_window_FLP(
const SKP_int length /* I Window length, multiple of 4 */
);
/* Wrappers. Calls flp / fix code */
/* Wrapper functions. Call flp / fix code */
/* Convert AR filter coefficients to NLSF parameters */
void silk_A2NLSF_FLP(
......@@ -301,7 +301,7 @@ void silk_A2NLSF_FLP(
);
/* Convert NLSF parameters to AR prediction filter coefficients */
void silk_NLSF2A_stable_FLP(
void silk_NLSF2A_FLP(
SKP_float *pAR, /* O LPC coefficients [ LPC_order ] */
const SKP_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */
const SKP_int LPC_order /* I LPC order */
......
......@@ -47,7 +47,7 @@ void silk_A2NLSF_FLP(
}
/* Convert LSF parameters to AR prediction filter coefficients */
void silk_NLSF2A_stable_FLP(
void silk_NLSF2A_FLP(
SKP_float *pAR, /* O LPC coefficients [ LPC_order ] */
const SKP_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */
const SKP_int LPC_order /* I LPC order */
......@@ -56,7 +56,7 @@ void silk_NLSF2A_stable_FLP(
SKP_int i;
SKP_int16 a_fix_Q12[ MAX_LPC_ORDER ];
silk_NLSF2A_stable( a_fix_Q12, NLSF_Q15, LPC_order );
silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order );
for( i = 0; i < LPC_order; i++ ) {
pAR[ i ] = ( SKP_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f );
......
......@@ -29,7 +29,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* Generates excitation for CNG LPC synthesis */
SKP_INLINE void silk_CNG_exc(
SKP_int16 residual[], /* O CNG residual signal Q0 */
SKP_int32 residual_Q10[], /* O CNG residual signal Q10 */
SKP_int32 exc_buf_Q10[], /* I Random samples buffer Q10 */
SKP_int32 Gain_Q16, /* I Gain to apply */
SKP_int length, /* I Length */
......@@ -50,7 +50,7 @@ SKP_INLINE void silk_CNG_exc(
idx = ( SKP_int )( SKP_RSHIFT( seed, 24 ) & exc_mask );
SKP_assert( idx >= 0 );
SKP_assert( idx <= CNG_BUF_MASK_MAX );
residual[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( exc_buf_Q10[ idx ], Gain_Q16 ), 10 ) );
residual_Q10[ i ] = ( SKP_int16 )SKP_SAT16( SKP_SMULWW( exc_buf_Q10[ idx ], Gain_Q16 ) );
}
*rand_seed = seed;
}
......@@ -73,18 +73,17 @@ void silk_CNG_Reset(
/* Updates CNG estimate, and applies the CNG when packet was lost */
void silk_CNG(
silk_decoder_state *psDec, /* I/O Decoder state */
silk_decoder_control *psDecCtrl, /* I/O Decoder control */
silk_decoder_state *psDec, /* I/O Decoder state */
silk_decoder_control *psDecCtrl, /* I/O Decoder control */
SKP_int16 signal[], /* I/O Signal */
SKP_int length /* I Length of residual */
)
{
SKP_int i, subfr;
SKP_int32 tmp_32, Gain_Q26, max_Gain_Q16;
SKP_int16 LPC_buf[ MAX_LPC_ORDER ];
SKP_int16 CNG_sig[ MAX_FRAME_LENGTH ];
silk_CNG_struct *psCNG;
psCNG = &psDec->sCNG;
SKP_int i, j, subfr;
SKP_int32 sum_Q6, max_Gain_Q16;
SKP_int16 A_Q12[ MAX_LPC_ORDER ];
SKP_int32 CNG_sig_Q10[ MAX_FRAME_LENGTH + MAX_LPC_ORDER ];
silk_CNG_struct *psCNG = &psDec->sCNG;
if( psDec->fs_kHz != psCNG->fs_kHz ) {
/* Reset state */
......@@ -118,31 +117,39 @@ void silk_CNG(
}
}
/* Add CNG when packet is lost and / or when low speech activity */
/* Add CNG when packet is lost or during DTX */
if( psDec->lossCnt ) {
/* Generate CNG excitation */
silk_CNG_exc( CNG_sig, psCNG->CNG_exc_buf_Q10,
psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed );
silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q10, psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed );
/* Convert CNG NLSF to filter representation */
silk_NLSF2A_stable( LPC_buf, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
Gain_Q26 = ( SKP_int32 )1 << 26; /* 1.0 */
/* Generate CNG signal, by synthesis filtering */
if( psDec->LPC_order == 16 ) {
silk_LPC_synthesis_order16( CNG_sig, LPC_buf,
Gain_Q26, psCNG->CNG_synth_state, CNG_sig, length );
} else {
silk_LPC_synthesis_filter( CNG_sig, LPC_buf,
Gain_Q26, psCNG->CNG_synth_state, CNG_sig, length, psDec->LPC_order );
}
/* Mix with signal */
SKP_memcpy( CNG_sig_Q10, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( SKP_int32 ) );
for( i = 0; i < length; i++ ) {
tmp_32 = signal[ i ] + CNG_sig[ i ];
signal[ i ] = SKP_SAT16( tmp_32 );
/* Partially unrolled */
sum_Q6 = SKP_SMULWB( CNG_sig_Q10[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] );
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] );
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
for( j = 10; j < psDec->LPC_order; j++ ) {
sum_Q6 = SKP_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
}
/* Update states */
CNG_sig_Q10[ MAX_LPC_ORDER + i ] = SKP_ADD_LSHIFT( CNG_sig_Q10[ MAX_LPC_ORDER + i ], sum_Q6, 4 );
signal[ i ] = SKP_ADD_SAT16( signal[ i ], SKP_RSHIFT_ROUND( sum_Q6, 6 ) );
}
SKP_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q10[ length ], MAX_LPC_ORDER * sizeof( SKP_int32 ) );
} else {
SKP_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( SKP_int32 ) );
}
......
......@@ -103,7 +103,7 @@ static SKP_int LPC_inverse_pred_gain_QA( /* O: Returns 1 if unstable, o
}
/* For input in Q12 domain */
SKP_int silk_LPC_inverse_pred_gain( /* O: Returns 1 if unstable, otherwise 0 */
SKP_int silk_LPC_inverse_pred_gain( /* O: Returns 1 if unstable, otherwise 0 */
SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */
const SKP_int16 *A_Q12, /* I: Prediction coefficients, Q12 [order] */
const SKP_int order /* I: Prediction order */
......@@ -123,29 +123,8 @@ SKP_int silk_LPC_inverse_pred_gain( /* O: Returns 1 if unstable, otherwi
return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order );
}
/* For input in Q13 domain */
SKP_int silk_LPC_inverse_pred_gain_Q13( /* O: Returns 1 if unstable, otherwise 0 */
SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */
const SKP_int16 *A_Q13, /* I: Prediction coefficients, Q13 [order] */
const SKP_int order /* I: Prediction order */
)
{
SKP_int k;
SKP_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
SKP_int32 *Anew_QA;
Anew_QA = Atmp_QA[ order & 1 ];
/* Increase Q domain of the AR coefficients */
for( k = 0; k < order; k++ ) {
Anew_QA[ k ] = SKP_LSHIFT( (SKP_int32)A_Q13[ k ], QA - 13 );
}
return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order );
}
/* For input in Q24 domain */
SKP_int silk_LPC_inverse_pred_gain_Q24( /* O: Returns 1 if unstable, otherwise 0 */
SKP_int silk_LPC_inverse_pred_gain_Q24( /* O: Returns 1 if unstable, otherwise 0 */
SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */
const SKP_int32 *A_Q24, /* I: Prediction coefficients, Q24 [order] */
const SKP_int order /* I: Prediction order */
......
/***********************************************************************
Copyright (c) 2006-2011, Skype Limited. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, (subject to the limitations in the disclaimer below)
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 Skype Limited, nor the names of specific
contributors, may be used to endorse or promote products derived from
this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
BY THIS LICENSE. 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.
***********************************************************************/
#include "silk_typedef.h"
#include "silk_SigProc_FIX.h"
#define LPC_STABILIZE_LPC_MAX_ABS_VALUE_Q16 ( ( (SKP_int32)SKP_int16_MAX ) << 4 )
/* LPC stabilizer, for a single input data vector */
void silk_LPC_stabilize(
SKP_int16 *a_Q12, /* O stabilized LPC vector [L] */
SKP_int32 *a_Q16, /* I LPC vector [L] */
const SKP_int32 bwe_Q16, /* I Bandwidth expansion factor */
const SKP_int L /* I Number of LPC parameters in the input vector */
)
{
SKP_int32 maxabs, absval, sc_Q16;
SKP_int i, idx = 0;
SKP_int32 invGain_Q30;
silk_bwexpander_32( a_Q16, L, bwe_Q16 );
/***************************/
/* Limit range of the LPCs */
/***************************/
/* Limit the maximum absolute value of the prediction coefficients */
while( SKP_TRUE ) {
/* Find maximum absolute value and its index */
maxabs = SKP_int32_MIN;
for( i = 0; i < L; i++ ) {
absval = SKP_abs( a_Q16[ i ] );
if( absval > maxabs ) {
maxabs = absval;
idx = i;
}
}
if( maxabs >= LPC_STABILIZE_LPC_MAX_ABS_VALUE_Q16 ) {
/* Reduce magnitude of prediction coefficients */
sc_Q16 = SKP_DIV32( SKP_int32_MAX, SKP_RSHIFT( maxabs, 4 ) );
sc_Q16 = 65536 - sc_Q16;
sc_Q16 = SKP_DIV32( sc_Q16, idx + 1 );
sc_Q16 = 65536 - sc_Q16;
sc_Q16 = SKP_LSHIFT( SKP_SMULWB( sc_Q16, 32604 ), 1 ); // 0.995 in Q16
silk_bwexpander_32( a_Q16, L, sc_Q16 );
} else {
break;
}
}
/* Convert to 16 bit Q12 */
for( i = 0; i < L; i++ ) {
a_Q12[ i ] = (SKP_int16)SKP_RSHIFT_ROUND( a_Q16[ i ], 4 );
}
/**********************/
/* Ensure stable LPCs */
/**********************/
while( silk_LPC_inverse_pred_gain( &invGain_Q30, a_Q12, L ) == 1 ) {
silk_bwexpander( a_Q12, L, 65339 ); // 0.997 in Q16
}
}
void silk_LPC_fit(
SKP_int16 *a_QQ, /* O Stabilized LPC vector, Q(24-rshift) [L] */
SKP_int32 *a_Q24, /* I LPC vector [L] */
const SKP_int QQ, /* I Q domain of output LPC vector */
const SKP_int L /* I Number of LPC parameters in the input vector */
)
{
SKP_int i, rshift, idx = 0;
SKP_int32 maxabs, absval, sc_Q16;
rshift = 24 - QQ;
/***************************/
/* Limit range of the LPCs */
/***************************/
/* Limit the maximum absolute value of the prediction coefficients */
while( SKP_TRUE ) {
/* Find maximum absolute value and its index; assumes stable coefficients */
/* so that only the first half need to be tested */
maxabs = SKP_int32_MIN;
for( i = 1; i < L / 2; i++ ) {
absval = SKP_abs( a_Q24[ i ] );
if( absval > maxabs ) {
maxabs = absval;
idx = i;
}
}
maxabs = SKP_RSHIFT( maxabs, rshift );
if( maxabs >= SKP_int16_MAX ) {
/* Reduce magnitude of prediction coefficients */
maxabs = SKP_min( maxabs, 98369 ); // ( SKP_int32_MAX / ( 65470 >> 2 ) ) + SKP_int16_MAX = 98369
sc_Q16 = 65470 - SKP_DIV32( SKP_MUL( 65470 >> 2, maxabs - SKP_int16_MAX ),
SKP_RSHIFT32( SKP_MUL( maxabs, idx + 1), 2 ) );
silk_bwexpander_32( a_Q24, L, sc_Q16 );
} else {
break;
}
}
/* Convert to 16 bit Q(24-rshift) */
SKP_assert( rshift > 0 );
SKP_assert( rshift < 31 );
for( i = 0; i < L; i++ ) {
a_QQ[ i ] = (SKP_int16)SKP_RSHIFT_ROUND( a_Q24[ i ], rshift );
}
}
/***********************************************************************
Copyright (c) 2006-2011, Skype Limited. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, (subject to the limitations in the disclaimer below)
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 Skype Limited, nor the names of specific
contributors, may be used to endorse or promote products derived from
this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
BY THIS LICENSE. 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.
***********************************************************************/
/* *
* silk_LPC_synthesis_filter.c *
* Coefficients are in Q12 *
* *
* even order AR filter *
* */
#include "silk_SigProc_FIX.h"
/* even order AR filter */
void silk_LPC_synthesis_filter(
const SKP_int16 *in, /* I: excitation signal */
const SKP_int16 *A_Q12, /* I: AR coefficients [Order], between -8_Q0 and 8_Q0 */
const SKP_int32 Gain_Q26, /* I: gain */
SKP_int32 *S, /* I/O: state vector [Order] */
SKP_int16 *out, /* O: output signal */
const SKP_int32 len, /* I: signal length */
const SKP_int Order /* I: filter order, must be even */
)
{
SKP_int k, j, idx, Order_half = SKP_RSHIFT( Order, 1 );
SKP_int32 SA, SB, out32_Q10, out32;
/* Order must be even */
SKP_assert( 2 * Order_half == Order );
/* S[] values are in Q14 */
for( k = 0; k < len; k++ ) {
SA = S[ Order - 1 ];
out32_Q10 = 0;
for( j = 0; j < ( Order_half - 1 ); j++ ) {
idx = SKP_SMULBB( 2, j ) + 1;
SB = S[ Order - 1 - idx ];
S[ Order - 1 - idx ] = SA;
out32_Q10 = SKP_SMLAWB( out32_Q10, SA, A_Q12[ ( j << 1 ) ] );
out32_Q10 = SKP_SMLAWB( out32_Q10, SB, A_Q12[ ( j << 1 ) + 1 ] );
SA = S[ Order - 2 - idx ];
S[ Order - 2 - idx ] = SB;
}
/* unrolled loop: epilog */
SB = S[ 0 ];
S[ 0 ] = SA;
out32_Q10 = SKP_SMLAWB( out32_Q10, SA, A_Q12[ Order - 2 ] );
out32_Q10 = SKP_SMLAWB( out32_Q10, SB, A_Q12[ Order - 1 ] );
/* apply gain to excitation signal and add to prediction */
out32_Q10 = SKP_ADD_SAT32( out32_Q10, SKP_SMULWB( Gain_Q26, in[ k ] ) );
/* scale to Q0 */
out32 = SKP_RSHIFT_ROUND( out32_Q10, 10 );
/* saturate output */
out[ k ] = ( SKP_int16 )SKP_SAT16( out32 );
/* move result into delay line */
S[ Order - 1 ] = SKP_LSHIFT_SAT32( out32_Q10, 4 );
}
}
/***********************************************************************
Copyright (c) 2006-2011, Skype Limited. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, (subject to the limitations in the disclaimer below)
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 Skype Limited, nor the names of specific
contributors, may be used to endorse or promote products derived from
this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
BY THIS LICENSE. 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.
***********************************************************************/
/* *
* silk_LPC_synthesis_order16.c *
* Coefficients are in Q12 *
* *
* 16th order AR filter *
* */
#include "silk_SigProc_FIX.h"
/* 16th order AR filter */
void silk_LPC_synthesis_order16(const SKP_int16 *in, /* I: excitation signal */
const SKP_int16 *A_Q12, /* I: AR coefficients [16], between -8_Q0 and 8_Q0 */
const SKP_int32 Gain_Q26, /* I: gain */
SKP_int32 *S, /* I/O: state vector [16] */
SKP_int16 *out, /* O: output signal */
const SKP_int32 len /* I: signal length, must be multiple of 16 */
)
{
SKP_int k;
SKP_int32 SA, SB, out32_Q10, out32;
for( k = 0; k < len; k++ ) {
/* unrolled loop: prolog */
/* multiply-add two prediction coefficients per iteration */
SA = S[ 15 ];
SB = S[ 14 ];
S[ 14 ] = SA;
out32_Q10 = SKP_SMULWB( SA, A_Q12[ 0 ] );
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 1 ] );
SA = S[ 13 ];
S[ 13 ] = SB;
/* unrolled loop: main loop */
SB = S[ 12 ];
S[ 12 ] = SA;
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 2 ] );
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 3 ] );
SA = S[ 11 ];
S[ 11 ] = SB;
SB = S[ 10 ];
S[ 10 ] = SA;
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 4 ] );
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 5 ] );
SA = S[ 9 ];
S[ 9 ] = SB;
SB = S[ 8 ];
S[ 8 ] = SA;
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 6 ] );
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 7 ] );
SA = S[ 7 ];
S[ 7 ] = SB;
SB = S[ 6 ];
S[ 6 ] = SA;
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 8 ] );
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 9 ] );
SA = S[ 5 ];
S[ 5 ] = SB;
SB = S[ 4 ];
S[ 4 ] = SA;
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 10 ] );
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 11 ] );
SA = S[ 3 ];
S[ 3 ] = SB;
SB = S[ 2 ];
S[ 2 ] = SA;
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 12 ] );
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 13 ] );
SA = S[ 1 ];
S[ 1 ] = SB;
/* unrolled loop: epilog */
SB = S[ 0 ];
S[ 0 ] = SA;
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 14 ] );
out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 15 ] );
/* unrolled loop: end */
/* apply gain to excitation signal and add to prediction */
out32_Q10 = SKP_ADD_SAT32( out32_Q10, SKP_SMULWB( Gain_Q26, in[ k ] ) );
/* scale to Q0 */
out32 = SKP_RSHIFT_ROUND( out32_Q10, 10 );
/* saturate output */
out[ k ] = ( SKP_int16 )SKP_SAT16( out32 );
/* move result into delay line */
S[ 15 ] = SKP_LSHIFT_SAT32( out32_Q10, 4 );
}
}
......@@ -34,23 +34,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "silk_SigProc_FIX.h"
#include "silk_tables.h"
#define QA 16
/* helper function for NLSF2A(..) */
SKP_INLINE void silk_NLSF2A_find_poly(
SKP_int32 *out, /* o intermediate polynomial, Q20 */
const SKP_int32 *cLSF, /* i vector of interleaved 2*cos(LSFs), Q20 */
SKP_int dd /* i polynomial order (= 1/2 * filter order) */
SKP_int32 *out, /* O intermediate polynomial, QA [dd+1] */
const SKP_int32 *cLSF, /* I vector of interleaved 2*cos(LSFs), QA [d] */
SKP_int dd /* I polynomial order (= 1/2 * filter order) */
)
{
SKP_int k, n;
SKP_int32 ftmp;
SKP_int k, n;
SKP_int32 ftmp;
out[0] = SKP_LSHIFT( 1, 20 );
out[0] = SKP_LSHIFT( 1, QA );
out[1] = -cLSF[0];
for( k = 1; k < dd; k++ ) {
ftmp = cLSF[2*k]; // Q20
out[k+1] = SKP_LSHIFT( out[k-1], 1 ) - (SKP_int32)SKP_RSHIFT_ROUND64( SKP_SMULL( ftmp, out[k] ), 20 );
ftmp = cLSF[2*k]; // QA
out[k+1] = SKP_LSHIFT( out[k-1], 1 ) - (SKP_int32)SKP_RSHIFT_ROUND64( SKP_SMULL( ftmp, out[k] ), QA );
for( n = k; n > 1; n-- ) {
out[n] += out[n-2] - (SKP_int32)SKP_RSHIFT_ROUND64( SKP_SMULL( ftmp, out[n-1] ), 20 );
out[n] += out[n-2] - (SKP_int32)SKP_RSHIFT_ROUND64( SKP_SMULL( ftmp, out[n-1] ), QA );
}
out[1] -= ftmp;
}
......@@ -58,24 +60,21 @@ SKP_INLINE void silk_NLSF2A_find_poly(
/* compute whitening filter coefficients from normalized line spectral frequencies */
void silk_NLSF2A(
SKP_int16 *a, /* o monic whitening filter coefficients in Q12, [d] */
const SKP_int16 *NLSF, /* i normalized line spectral frequencies in Q15, [d] */
const SKP_int d /* i filter order (should be even) */
SKP_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */
const SKP_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */
const SKP_int d /* I filter order (should be even) */
)
{
SKP_int k, i, dd;
SKP_int32 cos_LSF_Q20[SILK_MAX_ORDER_LPC];
SKP_int32 P[SILK_MAX_ORDER_LPC/2+1], Q[SILK_MAX_ORDER_LPC/2+1];
SKP_int32 Ptmp, Qtmp;
SKP_int32 f_int;
SKP_int32 f_frac;
SKP_int32 cos_val, delta;
SKP_int32 a_int32[SILK_MAX_ORDER_LPC];
SKP_int32 maxabs, absval, idx=0, sc_Q16;
SKP_int k, i, dd;
SKP_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ];
SKP_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
SKP_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
SKP_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
SKP_int32 maxabs, absval, idx=0, sc_Q16, invGain_Q30;
SKP_assert( LSF_COS_TAB_SZ_FIX == 128 );