1
0
Fork 0
forked from len0rd/rockbox

Sync opus codec to upstream git

Change-Id: I0cfcc0005c4ad7bfbb1aaf454188ce70fb043dc1
This commit is contained in:
William Wilgus 2019-01-04 02:01:18 -06:00 committed by Solomon Peachy
parent 75d9393796
commit 14c6bb798d
286 changed files with 48931 additions and 1278 deletions

View file

@ -0,0 +1,267 @@
/***********************************************************************
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.
***********************************************************************/
/* Conversion between prediction filter coefficients and NLSFs */
/* Requires the order to be an even number */
/* A piecewise linear approximation maps LSF <-> cos(LSF) */
/* Therefore the result is not accurate NLSFs, but the two */
/* functions are accurate inverses of each other */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "SigProc_FIX.h"
#include "tables.h"
/* Number of binary divisions, when not in low complexity mode */
#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */
#define MAX_ITERATIONS_A2NLSF_FIX 16
/* Helper function for A2NLSF(..) */
/* Transforms polynomials from cos(n*f) to cos(f)^n */
static OPUS_INLINE void silk_A2NLSF_trans_poly(
opus_int32 *p, /* I/O Polynomial */
const opus_int dd /* I Polynomial order (= filter order / 2 ) */
)
{
opus_int k, n;
for( k = 2; k <= dd; k++ ) {
for( n = dd; n > k; n-- ) {
p[ n - 2 ] -= p[ n ];
}
p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 );
}
}
/* Helper function for A2NLSF(..) */
/* Polynomial evaluation */
static OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */
opus_int32 *p, /* I Polynomial, Q16 */
const opus_int32 x, /* I Evaluation point, Q12 */
const opus_int dd /* I Order */
)
{
opus_int n;
opus_int32 x_Q16, y32;
y32 = p[ dd ]; /* Q16 */
x_Q16 = silk_LSHIFT( x, 4 );
if ( opus_likely( 8 == dd ) )
{
y32 = silk_SMLAWW( p[ 7 ], y32, x_Q16 );
y32 = silk_SMLAWW( p[ 6 ], y32, x_Q16 );
y32 = silk_SMLAWW( p[ 5 ], y32, x_Q16 );
y32 = silk_SMLAWW( p[ 4 ], y32, x_Q16 );
y32 = silk_SMLAWW( p[ 3 ], y32, x_Q16 );
y32 = silk_SMLAWW( p[ 2 ], y32, x_Q16 );
y32 = silk_SMLAWW( p[ 1 ], y32, x_Q16 );
y32 = silk_SMLAWW( p[ 0 ], y32, x_Q16 );
}
else
{
for( n = dd - 1; n >= 0; n-- ) {
y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */
}
}
return y32;
}
static OPUS_INLINE void silk_A2NLSF_init(
const opus_int32 *a_Q16,
opus_int32 *P,
opus_int32 *Q,
const opus_int dd
)
{
opus_int k;
/* Convert filter coefs to even and odd polynomials */
P[dd] = silk_LSHIFT( 1, 16 );
Q[dd] = silk_LSHIFT( 1, 16 );
for( k = 0; k < dd; k++ ) {
P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */
Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */
}
/* Divide out zeros as we have that for even filter orders, */
/* z = 1 is always a root in Q, and */
/* z = -1 is always a root in P */
for( k = dd; k > 0; k-- ) {
P[ k - 1 ] -= P[ k ];
Q[ k - 1 ] += Q[ k ];
}
/* Transform polynomials from cos(n*f) to cos(f)^n */
silk_A2NLSF_trans_poly( P, dd );
silk_A2NLSF_trans_poly( Q, dd );
}
/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */
/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */
void silk_A2NLSF(
opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */
opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */
const opus_int d /* I Filter order (must be even) */
)
{
opus_int i, k, m, dd, root_ix, ffrac;
opus_int32 xlo, xhi, xmid;
opus_int32 ylo, yhi, ymid, thr;
opus_int32 nom, den;
opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ];
opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
opus_int32 *PQ[ 2 ];
opus_int32 *p;
/* Store pointers to array */
PQ[ 0 ] = P;
PQ[ 1 ] = Q;
dd = silk_RSHIFT( d, 1 );
silk_A2NLSF_init( a_Q16, P, Q, dd );
/* Find roots, alternating between P and Q */
p = P; /* Pointer to polynomial */
xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
if( ylo < 0 ) {
/* Set the first NLSF to zero and move on to the next */
NLSF[ 0 ] = 0;
p = Q; /* Pointer to polynomial */
ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
root_ix = 1; /* Index of current root */
} else {
root_ix = 0; /* Index of current root */
}
k = 1; /* Loop counter */
i = 0; /* Counter for bandwidth expansions applied */
thr = 0;
while( 1 ) {
/* Evaluate polynomial */
xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */
yhi = silk_A2NLSF_eval_poly( p, xhi, dd );
/* Detect zero crossing */
if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) {
if( yhi == 0 ) {
/* If the root lies exactly at the end of the current */
/* interval, look for the next root in the next interval */
thr = 1;
} else {
thr = 0;
}
/* Binary division */
ffrac = -256;
for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) {
/* Evaluate polynomial */
xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 );
ymid = silk_A2NLSF_eval_poly( p, xmid, dd );
/* Detect zero crossing */
if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) {
/* Reduce frequency */
xhi = xmid;
yhi = ymid;
} else {
/* Increase frequency */
xlo = xmid;
ylo = ymid;
ffrac = silk_ADD_RSHIFT( ffrac, 128, m );
}
}
/* Interpolate */
if( silk_abs( ylo ) < 65536 ) {
/* Avoid dividing by zero */
den = ylo - yhi;
nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 );
if( den != 0 ) {
ffrac += silk_DIV32( nom, den );
}
} else {
/* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */
ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) );
}
NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX );
silk_assert( NLSF[ root_ix ] >= 0 );
root_ix++; /* Next root */
if( root_ix >= d ) {
/* Found all roots */
break;
}
/* Alternate pointer to polynomial */
p = PQ[ root_ix & 1 ];
/* Evaluate polynomial */
xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/
ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 );
} else {
/* Increment loop counter */
k++;
xlo = xhi;
ylo = yhi;
thr = 0;
if( k > LSF_COS_TAB_SZ_FIX ) {
i++;
if( i > MAX_ITERATIONS_A2NLSF_FIX ) {
/* Set NLSFs to white spectrum and exit */
NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 );
for( k = 1; k < d; k++ ) {
NLSF[ k ] = (opus_int16)silk_ADD16( NLSF[ k-1 ], NLSF[ 0 ] );
}
return;
}
/* Error: Apply progressively more bandwidth expansion and run again */
silk_bwexpander_32( a_Q16, d, 65536 - silk_LSHIFT( 1, i ) );
silk_A2NLSF_init( a_Q16, P, Q, dd );
p = P; /* Pointer to polynomial */
xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
if( ylo < 0 ) {
/* Set the first NLSF to zero and move on to the next */
NLSF[ 0 ] = 0;
p = Q; /* Pointer to polynomial */
ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
root_ix = 1; /* Index of current root */
} else {
root_ix = 0; /* Index of current root */
}
k = 1; /* Reset loop counter */
}
}
}
}

View file

@ -80,7 +80,8 @@ opus_int silk_Encode( /* O Returns error co
opus_int nSamplesIn, /* I Number of samples in input vector */
ec_enc *psRangeEnc, /* I/O Compressor data structure */
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */
int activity /* I Decision of Opus voice activity detector */
);
/****************************************/
@ -111,7 +112,8 @@ opus_int silk_Decode( /* O Returns error co
opus_int newPacketFlag, /* I Indicates first decoder call for this packet */
ec_dec *psRangeDec, /* I/O Compressor data structure */
opus_int16 *samplesOut, /* O Decoded output speech vector */
opus_int32 *nSamplesOut /* O Number of samples decoded */
opus_int32 *nSamplesOut, /* O Number of samples decoded */
int arch /* I Run-time architecture */
);
#if 0

View file

@ -34,9 +34,8 @@ POSSIBILITY OF SUCH DAMAGE.
/* Generates excitation for CNG LPC synthesis */
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 Gain_Q16, /* I Gain to apply */
opus_int length, /* I Length */
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 );
silk_assert( idx >= 0 );
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;
}
@ -85,7 +84,7 @@ void silk_CNG(
)
{
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 ];
silk_CNG_struct *psCNG = &psDec->sCNG;
SAVE_STACK;
@ -124,56 +123,60 @@ void silk_CNG(
/* Add CNG when packet is lost or during DTX */
if( psDec->lossCnt ) {
VARDECL( opus_int32, CNG_sig_Q10 );
ALLOC( CNG_sig_Q10, length + MAX_LPC_ORDER, opus_int32 );
VARDECL( opus_int32, CNG_sig_Q14 );
ALLOC( CNG_sig_Q14, length + MAX_LPC_ORDER, opus_int32 );
/* Generate CNG excitation */
gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] );
if( gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23) ) {
gain_Q16 = silk_SMULTT( gain_Q16, gain_Q16 );
gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 );
gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 16 );
} else {
gain_Q16 = silk_SMULWW( gain_Q16, gain_Q16 );
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 );
}
silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, gain_Q16, length, &psCNG->rand_seed );
gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] );
if( gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23) ) {
gain_Q16 = silk_SMULTT( gain_Q16, gain_Q16 );
gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 );
gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 16 );
} else {
gain_Q16 = silk_SMULWW( gain_Q16, gain_Q16 );
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_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 */
silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order, psDec->arch );
/* 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 ) );
celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
for( i = 0; i < length; i++ ) {
silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
sum_Q6 = silk_RSHIFT( psDec->LPC_order, 1 );
sum_Q6 = silk_SMLAWB( sum_Q6, 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 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ 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 ] );
sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ 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 ] );
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 ] );
LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
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 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] );
}
/* 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_SAT32( CNG_sig_Q14[ MAX_LPC_ORDER + i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) );
/* 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 ) ) );
frame[ i ] = silk_ADD_SAT16( frame[ i ], silk_RSHIFT_ROUND( CNG_sig_Q10[ MAX_LPC_ORDER + i ], 10 ) );
}
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 {
silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) );
}

View file

@ -0,0 +1,77 @@
/***********************************************************************
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
#ifdef FIXED_POINT
#include "main_FIX.h"
#else
#include "main_FLP.h"
#endif
#include "tuning_parameters.h"
/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
void silk_HP_variable_cutoff(
silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
)
{
opus_int quality_Q15;
opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7;
silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn;
/* Adaptive cutoff frequency: estimate low end of pitch frequency range */
if( psEncC1->prevSignalType == TYPE_VOICED ) {
/* difference, in log domain */
pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag );
pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 );
/* adjustment based on quality */
quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ];
pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ),
pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) );
/* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */
delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->variable_HP_smth1_Q15, 8 );
if( delta_freq_Q7 < 0 ) {
/* less smoothing for decreasing pitch frequency, to track something close to the minimum */
delta_freq_Q7 = silk_MUL( delta_freq_Q7, 3 );
}
/* limit delta, to reduce impact of outliers in pitch estimation */
delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) );
/* update smoother */
psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15,
silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) );
/* limit frequency range */
psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15,
silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ),
silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) );
}
}

View file

@ -39,17 +39,24 @@ POSSIBILITY OF SUCH DAMAGE.
/* first d output samples are set to zero */
/*******************************************/
/* OPT: Using celt_fir() for this function should be faster, but it may cause
integer overflows in intermediate values (not final results), which the
current implementation silences by casting to unsigned. Enabling
this should be safe in pretty much all cases, even though it is not technically
C89-compliant. */
#define USE_CELT_FIR 0
void silk_LPC_analysis_filter(
opus_int16 *out, /* O Output signal */
const opus_int16 *in, /* I Input signal */
const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
const opus_int32 len, /* I Signal length */
const opus_int32 d /* I Filter order */
const opus_int32 d, /* I Filter order */
int arch /* I Run-time architecture */
)
{
opus_int j;
#ifdef FIXED_POINT
opus_int16 mem[SILK_MAX_ORDER_LPC];
#if defined(FIXED_POINT) && USE_CELT_FIR
opus_int16 num[SILK_MAX_ORDER_LPC];
#else
int ix;
@ -57,23 +64,21 @@ void silk_LPC_analysis_filter(
const opus_int16 *in_ptr;
#endif
silk_assert( d >= 6 );
silk_assert( (d & 1) == 0 );
silk_assert( d <= len );
celt_assert( d >= 6 );
celt_assert( (d & 1) == 0 );
celt_assert( d <= len );
#ifdef FIXED_POINT
silk_assert( d <= SILK_MAX_ORDER_LPC );
#if defined(FIXED_POINT) && USE_CELT_FIR
celt_assert( d <= SILK_MAX_ORDER_LPC );
for ( j = 0; j < d; j++ ) {
num[ j ] = -B[ j ];
}
for (j=0;j<d;j++) {
mem[ j ] = in[ d - j - 1 ];
}
celt_fir( in + d, num, out + d, len - d, d, mem );
celt_fir( in + d, num, out + d, len - d, d, arch );
for ( j = 0; j < d; j++ ) {
out[ j ] = 0;
}
#else
(void)arch;
for( ix = d; ix < len; ix++ ) {
in_ptr = &in[ ix - 1 ];

View file

@ -0,0 +1,81 @@
/***********************************************************************
Copyright (c) 2013, Koen Vos. 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 "SigProc_FIX.h"
/* 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 */
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;
/* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */
for( i = 0; i < 10; i++ ) {
/* Find maximum absolute value and its index */
maxabs = 0;
for( k = 0; k < d; k++ ) {
absval = silk_abs( a_QIN[k] );
if( absval > maxabs ) {
maxabs = absval;
idx = k;
}
}
maxabs = silk_RSHIFT_ROUND( maxabs, QIN - QOUT );
if( maxabs > silk_int16_MAX ) {
/* Reduce magnitude of prediction coefficients */
maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */
chirp_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ),
silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) );
silk_bwexpander_32( a_QIN, d, chirp_Q16 );
} else {
break;
}
}
if( i == 10 ) {
/* Reached the last iteration, clip the coefficients */
for( k = 0; k < d; k++ ) {
a_QOUT[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ) );
a_QIN[ k ] = silk_LSHIFT( (opus_int32)a_QOUT[ k ], QIN - QOUT );
}
} else {
for( k = 0; k < d; k++ ) {
a_QOUT[ k ] = (opus_int16)silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT );
}
}
}

View file

@ -30,6 +30,7 @@ POSSIBILITY OF SUCH DAMAGE.
#endif
#include "SigProc_FIX.h"
#include "define.h"
#define QA 24
#define A_LIMIT SILK_FIX_CONST( 0.99975, QA )
@ -38,119 +39,103 @@ POSSIBILITY OF SUCH DAMAGE.
/* Compute inverse of LPC prediction gain, and */
/* test if LPC coefficients are stable (all poles within unit circle) */
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 */
static opus_int32 LPC_inverse_pred_gain_QA_c( /* O Returns inverse prediction gain in energy domain, Q30 */
opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */
const opus_int order /* I Prediction order */
)
{
opus_int k, n, mult2Q;
opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
opus_int32 *Aold_QA, *Anew_QA;
opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2;
Anew_QA = A_QA[ order & 1 ];
invGain_Q30 = (opus_int32)1 << 30;
invGain_Q30 = SILK_FIX_CONST( 1, 30 );
for( k = order - 1; k > 0; k-- ) {
/* Check for stability */
if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) {
if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) {
return 0;
}
/* Set RC equal to negated AR coef */
rc_Q31 = -silk_LSHIFT( Anew_QA[ k ], 31 - QA );
rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA );
/* rc_mult1_Q30 range: [ 1 : 2^30 ] */
rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) );
silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */
silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) );
/* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) );
rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 );
/* 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 ) );
if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
return 0;
}
/* Swap pointers */
Aold_QA = Anew_QA;
Anew_QA = A_QA[ k & 1 ];
/* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) );
rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 );
/* Update AR coefficient */
for( n = 0; n < k; n++ ) {
tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 );
Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q );
for( n = 0; n < (k + 1) >> 1; n++ ) {
opus_int64 tmp64;
tmp1 = A_QA[ n ];
tmp2 = A_QA[ k - n - 1 ];
tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1,
MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q);
if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) {
return 0;
}
A_QA[ n ] = ( opus_int32 )tmp64;
tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2,
MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q);
if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) {
return 0;
}
A_QA[ k - n - 1 ] = ( opus_int32 )tmp64;
}
}
/* Check for stability */
if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) {
if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) {
return 0;
}
/* Set RC equal to negated AR coef */
rc_Q31 = -silk_LSHIFT( Anew_QA[ 0 ], 31 - QA );
rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA );
/* Range: [ 1 : 2^30 ] */
rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) );
/* 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 );
silk_assert( invGain_Q30 >= 0 );
silk_assert( invGain_Q30 <= ( 1 << 30 ) );
if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
return 0;
}
return invGain_Q30;
}
/* For input in Q12 domain */
opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */
opus_int32 silk_LPC_inverse_pred_gain_c( /* 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 */
)
{
opus_int k;
opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
opus_int32 *Anew_QA;
opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ];
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_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 );
Atmp_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 ) {
return 0;
}
return LPC_inverse_pred_gain_QA( Atmp_QA, order );
return LPC_inverse_pred_gain_QA_c( Atmp_QA, order );
}
#ifdef FIXED_POINT
#if 0
/* For input in Q24 domain */
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 */
)
{
opus_int k;
opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
opus_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 ] = silk_RSHIFT32( A_Q24[ k ], 24 - QA );
}
return LPC_inverse_pred_gain_QA( Atmp_QA, order );
}
#endif
#endif

View file

@ -0,0 +1,135 @@
/***********************************************************************
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
/*
Elliptic/Cauer filters designed with 0.1 dB passband ripple,
80 dB minimum stopband attenuation, and
[0.95 : 0.15 : 0.35] normalized cut off frequencies.
*/
#include "main.h"
/* Helper function, interpolates the filter taps */
static OPUS_INLINE void silk_LP_interpolate_filter_taps(
opus_int32 B_Q28[ TRANSITION_NB ],
opus_int32 A_Q28[ TRANSITION_NA ],
const opus_int ind,
const opus_int32 fac_Q16
)
{
opus_int nb, na;
if( ind < TRANSITION_INT_NUM - 1 ) {
if( fac_Q16 > 0 ) {
if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */
/* Piece-wise linear interpolation of B and A */
for( nb = 0; nb < TRANSITION_NB; nb++ ) {
B_Q28[ nb ] = silk_SMLAWB(
silk_Transition_LP_B_Q28[ ind ][ nb ],
silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] -
silk_Transition_LP_B_Q28[ ind ][ nb ],
fac_Q16 );
}
for( na = 0; na < TRANSITION_NA; na++ ) {
A_Q28[ na ] = silk_SMLAWB(
silk_Transition_LP_A_Q28[ ind ][ na ],
silk_Transition_LP_A_Q28[ ind + 1 ][ na ] -
silk_Transition_LP_A_Q28[ ind ][ na ],
fac_Q16 );
}
} else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */
silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) );
/* Piece-wise linear interpolation of B and A */
for( nb = 0; nb < TRANSITION_NB; nb++ ) {
B_Q28[ nb ] = silk_SMLAWB(
silk_Transition_LP_B_Q28[ ind + 1 ][ nb ],
silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] -
silk_Transition_LP_B_Q28[ ind ][ nb ],
fac_Q16 - ( (opus_int32)1 << 16 ) );
}
for( na = 0; na < TRANSITION_NA; na++ ) {
A_Q28[ na ] = silk_SMLAWB(
silk_Transition_LP_A_Q28[ ind + 1 ][ na ],
silk_Transition_LP_A_Q28[ ind + 1 ][ na ] -
silk_Transition_LP_A_Q28[ ind ][ na ],
fac_Q16 - ( (opus_int32)1 << 16 ) );
}
}
} else {
silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) );
silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) );
}
} else {
silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) );
silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) );
}
}
/* Low-pass filter with variable cutoff frequency based on */
/* piece-wise linear interpolation between elliptic filters */
/* Start by setting psEncC->mode <> 0; */
/* Deactivate by setting psEncC->mode = 0; */
void silk_LP_variable_cutoff(
silk_LP_state *psLP, /* I/O LP filter state */
opus_int16 *frame, /* I/O Low-pass filtered output signal */
const opus_int frame_length /* I Frame length */
)
{
opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0;
opus_int ind = 0;
silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES );
/* Run filter if needed */
if( psLP->mode != 0 ) {
/* Calculate index and interpolation factor for interpolation */
#if( TRANSITION_INT_STEPS == 64 )
fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 );
#else
fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES );
#endif
ind = silk_RSHIFT( fac_Q16, 16 );
fac_Q16 -= silk_LSHIFT( ind, 16 );
silk_assert( ind >= 0 );
silk_assert( ind < TRANSITION_INT_NUM );
/* Interpolate filter coefficients */
silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 );
/* Update transition frame number for next frame */
psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES );
/* ARMA low-pass filtering */
silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 );
silk_biquad_alt_stride1( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length);
}
}

View file

@ -319,14 +319,6 @@ static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){
return(tmp);
}
#undef silk_ADD_POS_SAT64
static OPUS_INLINE opus_int64 silk_ADD_POS_SAT64(opus_int64 a, opus_int64 b){
opus_int64 tmp;
ops_count += 1;
tmp = ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b)));
return(tmp);
}
#undef silk_LSHIFT8
static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){
opus_int8 ret;
@ -699,7 +691,7 @@ return(ret);
#undef silk_LIMIT_32
static OPUS_INLINE opus_int silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2)
static OPUS_INLINE opus_int32 silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2)
{
opus_int32 ret;
ops_count += 6;

View file

@ -539,8 +539,7 @@ static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, cha
no checking needed for silk_POS_SAT32
no checking needed for silk_ADD_POS_SAT8
no checking needed for silk_ADD_POS_SAT16
no checking needed for silk_ADD_POS_SAT32
no checking needed for silk_ADD_POS_SAT64 */
no checking needed for silk_ADD_POS_SAT32 */
#undef silk_LSHIFT8
#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__)

View file

@ -66,7 +66,8 @@ static OPUS_INLINE void silk_NLSF2A_find_poly(
void silk_NLSF2A(
opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */
const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */
const opus_int d /* I filter order (should be even) */
const opus_int d, /* I filter order (should be even) */
int arch /* I Run-time architecture */
)
{
/* This ordering was found to maximize quality. It improves numerical accuracy of
@ -83,15 +84,14 @@ 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;
silk_assert( LSF_COS_TAB_SZ_FIX == 128 );
silk_assert( d==10||d==16 );
celt_assert( d==10 || d==16 );
/* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */
ordering = d == 16 ? ordering16 : ordering10;
for( k = 0; k < d; k++ ) {
silk_assert(NLSF[k] >= 0 );
silk_assert( NLSF[k] >= 0 );
/* f_int on a scale 0-127 (rounded down) */
f_int = silk_RSHIFT( NLSF[k], 15 - 7 );
@ -126,52 +126,15 @@ void silk_NLSF2A(
a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */
}
/* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */
for( i = 0; i < 10; i++ ) {
/* Find maximum absolute value and its index */
maxabs = 0;
for( k = 0; k < d; k++ ) {
absval = silk_abs( a32_QA1[k] );
if( absval > maxabs ) {
maxabs = absval;
idx = k;
}
}
maxabs = silk_RSHIFT_ROUND( maxabs, QA + 1 - 12 ); /* QA+1 -> Q12 */
/* Convert int32 coefficients to Q12 int16 coefs */
silk_LPC_fit( a_Q12, a32_QA1, 12, QA + 1, d );
if( maxabs > silk_int16_MAX ) {
/* Reduce magnitude of prediction coefficients */
maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */
sc_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ),
silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) );
silk_bwexpander_32( a32_QA1, d, sc_Q16 );
} else {
break;
}
}
if( i == 10 ) {
/* Reached the last iteration, clip the coefficients */
for( i = 0; silk_LPC_inverse_pred_gain( a_Q12, d, arch ) == 0 && i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) {
/* 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_LSHIFT( 2, i ) );
for( k = 0; k < d; k++ ) {
a_Q12[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ) ); /* QA+1 -> Q12 */
a32_QA1[ k ] = silk_LSHIFT( (opus_int32)a_Q12[ k ], QA + 1 - 12 );
}
} else {
for( k = 0; k < d; k++ ) {
a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
}
}
for( i = 0; 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_LSHIFT( 2, i ) );
for( k = 0; k < d; k++ ) {
a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
}
} else {
break;
a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
}
}
}

View file

@ -0,0 +1,76 @@
/***********************************************************************
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"
/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */
void silk_NLSF_VQ(
opus_int32 err_Q24[], /* O Quantization errors [K] */
const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */
const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */
const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */
const opus_int K, /* I Number of codebook vectors */
const opus_int LPC_order /* I Number of LPCs */
)
{
opus_int i, m;
opus_int32 diff_Q15, diffw_Q24, sum_error_Q24, pred_Q24;
const opus_int16 *w_Q9_ptr;
const opus_uint8 *cb_Q8_ptr;
celt_assert( ( LPC_order & 1 ) == 0 );
/* Loop over codebook */
cb_Q8_ptr = pCB_Q8;
w_Q9_ptr = pWght_Q9;
for( i = 0; i < K; i++ ) {
sum_error_Q24 = 0;
pred_Q24 = 0;
for( m = LPC_order-2; m >= 0; m -= 2 ) {
/* Compute weighted absolute predictive quantization error for index m + 1 */
diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m + 1 ], (opus_int32)cb_Q8_ptr[ m + 1 ], 7 ); /* range: [ -32767 : 32767 ]*/
diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m + 1 ] );
sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) );
pred_Q24 = diffw_Q24;
/* Compute weighted absolute predictive quantization error for index m */
diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)cb_Q8_ptr[ m ], 7 ); /* range: [ -32767 : 32767 ]*/
diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m ] );
sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) );
pred_Q24 = diffw_Q24;
silk_assert( sum_error_Q24 >= 0 );
}
err_Q24[ i ] = sum_error_Q24;
cb_Q8_ptr += LPC_order;
w_Q9_ptr += LPC_order;
}
}

View file

@ -48,8 +48,8 @@ void silk_NLSF_VQ_weights_laroia(
opus_int k;
opus_int32 tmp1_int, tmp2_int;
silk_assert( D > 0 );
silk_assert( ( D & 1 ) == 0 );
celt_assert( D > 0 );
celt_assert( ( D & 1 ) == 0 );
/* First value */
tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 );

View file

@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "main.h"
/* Predictive dequantizer for NLSF residuals */
static OPUS_INLINE void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */
static OPUS_INLINE void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */
opus_int16 x_Q10[], /* O Output [ order ] */
const opus_int8 indices[], /* I Quantization indices [ order ] */
const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */
@ -70,15 +70,9 @@ void silk_NLSF_decode(
opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
opus_int16 ec_ix[ MAX_LPC_ORDER ];
opus_int16 res_Q10[ MAX_LPC_ORDER ];
opus_int16 W_tmp_QW[ MAX_LPC_ORDER ];
opus_int32 W_tmp_Q9, NLSF_Q15_tmp;
opus_int32 NLSF_Q15_tmp;
const opus_uint8 *pCB_element;
/* 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 );
}
const opus_int16 *pCB_Wght_Q9;
/* Unpack entropy table indices and predictor for current CB1 index */
silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] );
@ -86,13 +80,11 @@ void silk_NLSF_decode(
/* Predictive residual dequantizer */
silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order );
/* Weights from codebook vector */
silk_NLSF_VQ_weights_laroia( W_tmp_QW, pNLSF_Q15, psNLSF_CB->order );
/* Apply inverse square-rooted weights and add to output */
/* Apply inverse square-rooted weights to first stage and add to output */
pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ];
pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ NLSFIndices[ 0 ] * psNLSF_CB->order ];
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 ) );
NLSF_Q15_tmp = silk_ADD_LSHIFT32( silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), pCB_Wght_Q9[ i ] ), (opus_int16)pCB_element[ i ], 7 );
pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 );
}

View file

@ -0,0 +1,215 @@
/***********************************************************************
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"
/* 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 ] */
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 ] */
const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */
const opus_uint8 ec_rates_Q5[], /* I Rates [] */
const opus_int quant_step_size_Q16, /* I Quantization step size */
const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */
const opus_int32 mu_Q20, /* I R/D tradeoff */
const opus_int16 order /* I Number of input values */
)
{
opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10;
opus_int pred_Q10, diff_Q10, rate0_Q5, rate1_Q5;
opus_int16 out0_Q10, out1_Q10;
opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25;
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 ];
opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ];
opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ];
opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ];
const opus_uint8 *rates_Q5;
opus_int out0_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT];
opus_int out1_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT];
for (i = -NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= NLSF_QUANT_MAX_AMPLITUDE_EXT-1; i++)
{
out0_Q10 = silk_LSHIFT( i, 10 );
out1_Q10 = silk_ADD16( out0_Q10, 1024 );
if( i > 0 ) {
out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
} else if( i == 0 ) {
out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
} else if( i == -1 ) {
out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
} else {
out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
}
out0_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out0_Q10, quant_step_size_Q16 ), 16 );
out1_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out1_Q10, quant_step_size_Q16 ), 16 );
}
silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */
nStates = 1;
RD_Q25[ 0 ] = 0;
prev_out_Q10[ 0 ] = 0;
for( i = order - 1; i >= 0; i-- ) {
rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ];
in_Q10 = x_Q10[ i ];
for( j = 0; j < nStates; j++ ) {
pred_Q10 = silk_RSHIFT( silk_SMULBB( (opus_int16)pred_coef_Q8[ i ], prev_out_Q10[ j ] ), 8 );
res_Q10 = silk_SUB16( in_Q10, pred_Q10 );
ind_tmp = silk_RSHIFT( silk_SMULBB( inv_quant_step_size_Q6, res_Q10 ), 16 );
ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 );
ind[ j ][ i ] = (opus_int8)ind_tmp;
/* compute outputs for ind_tmp and ind_tmp + 1 */
out0_Q10 = out0_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ];
out1_Q10 = out1_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ];
out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 );
out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 );
prev_out_Q10[ j ] = out0_Q10;
prev_out_Q10[ j + nStates ] = out1_Q10;
/* compute RD for ind_tmp and ind_tmp + 1 */
if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) {
if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) {
rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ];
rate1_Q5 = 280;
} else {
rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp );
rate1_Q5 = silk_ADD16( rate0_Q5, 43 );
}
} else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) {
if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) {
rate0_Q5 = 280;
rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
} else {
rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp );
rate1_Q5 = silk_SUB16( rate0_Q5, 43 );
}
} else {
rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ];
rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
}
RD_tmp_Q25 = RD_Q25[ j ];
diff_Q10 = silk_SUB16( in_Q10, out0_Q10 );
RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 );
diff_Q10 = silk_SUB16( in_Q10, out1_Q10 );
RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 );
}
if( nStates <= NLSF_QUANT_DEL_DEC_STATES/2 ) {
/* double number of states and copy */
for( j = 0; j < nStates; j++ ) {
ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1;
}
nStates = silk_LSHIFT( nStates, 1 );
for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
ind[ j ][ i ] = ind[ j - nStates ][ i ];
}
} else {
/* sort lower and upper half of RD_Q25, pairwise */
for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) {
RD_max_Q25[ j ] = RD_Q25[ j ];
RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
RD_Q25[ j ] = RD_min_Q25[ j ];
RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ];
/* swap prev_out values */
out0_Q10 = prev_out_Q10[ j ];
prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ];
prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10;
ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES;
} else {
RD_min_Q25[ j ] = RD_Q25[ j ];
RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
ind_sort[ j ] = j;
}
}
/* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */
/* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */
while( 1 ) {
min_max_Q25 = silk_int32_MAX;
max_min_Q25 = 0;
ind_min_max = 0;
ind_max_min = 0;
for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
if( min_max_Q25 > RD_max_Q25[ j ] ) {
min_max_Q25 = RD_max_Q25[ j ];
ind_min_max = j;
}
if( max_min_Q25 < RD_min_Q25[ j ] ) {
max_min_Q25 = RD_min_Q25[ j ];
ind_max_min = j;
}
}
if( min_max_Q25 >= max_min_Q25 ) {
break;
}
/* copy ind_min_max to ind_max_min */
ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES;
RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
RD_min_Q25[ ind_max_min ] = 0;
RD_max_Q25[ ind_min_max ] = silk_int32_MAX;
silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) );
}
/* increment index if it comes from the upper half */
for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 );
}
}
}
/* 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;
}

View file

@ -0,0 +1,124 @@
/***********************************************************************
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;
celt_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;
}

View file

@ -130,7 +130,7 @@ void silk_NLSF_stabilize(
/* Keep delta_min distance between the NLSFs */
for( i = 1; i < L; i++ )
NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], NLSF_Q15[i-1] + NDeltaMin_Q15[i] );
NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) );
/* Last NLSF should be no higher than 1 - NDeltaMin[L] */
NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] );

View file

@ -0,0 +1,437 @@
/***********************************************************************
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"
#include "NSQ.h"
static OPUS_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 x16[], /* I input */
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_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 */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
const opus_int signal_type /* I Signal type */
);
#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
static OPUS_INLINE void silk_noise_shape_quantizer(
silk_nsq_state *NSQ, /* I/O NSQ state */
opus_int signalType, /* I Signal type */
const opus_int32 x_sc_Q10[], /* I */
opus_int8 pulses[], /* O */
opus_int16 xq[], /* O */
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 */
opus_int lag, /* I Pitch lag */
opus_int32 HarmShapeFIRPacked_Q14, /* I */
opus_int Tilt_Q14, /* I Spectral tilt */
opus_int32 LF_shp_Q14, /* I */
opus_int32 Gain_Q16, /* I */
opus_int Lambda_Q10, /* I */
opus_int offset_Q10, /* I */
opus_int length, /* I Input length */
opus_int shapingLPCOrder, /* I Noise shaping AR filter order */
opus_int predictLPCOrder, /* I Prediction filter order */
int arch /* I Architecture */
);
#endif
void silk_NSQ_c
(
const silk_encoder_state *psEncC, /* I Encoder State */
silk_nsq_state *NSQ, /* I/O NSQ state */
SideInfoIndices *psIndices, /* I/O Quantization Indices */
const opus_int16 x16[], /* I Input */
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 */
const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
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;
VARDECL( opus_int32, sLTP_Q15 );
VARDECL( opus_int16, sLTP );
opus_int32 HarmShapeFIRPacked_Q14;
opus_int offset_Q10;
VARDECL( opus_int32, x_sc_Q10 );
SAVE_STACK;
NSQ->rand_seed = psIndices->Seed;
/* Set unvoiced lag to the previous one, overwrite later for voiced */
lag = NSQ->lagPrev;
silk_assert( NSQ->prev_gain_Q16 != 0 );
offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
LSF_interpolation_flag = 0;
} else {
LSF_interpolation_flag = 1;
}
ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
/* 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 ];
for( k = 0; k < psEncC->nb_subfr; k++ ) {
A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ];
B_Q14 = &LTPCoef_Q14[ k * LTP_ORDER ];
AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ];
/* 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 );
NSQ->rewhite_flag = 0;
if( psIndices->signalType == TYPE_VOICED ) {
/* Voiced */
lag = pitchL[ k ];
/* Re-whitening */
if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
/* Rewhiten with new A coefs */
start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
celt_assert( start_idx > 0 );
silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
NSQ->rewhite_flag = 1;
NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
}
}
silk_nsq_scale_states( psEncC, NSQ, x16, 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_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, psEncC->arch );
x16 += psEncC->subfr_length;
pulses += psEncC->subfr_length;
pxq += psEncC->subfr_length;
}
/* Update lagPrev for next frame */
NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
/* Save quantized speech and noise shaping signals */
silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
RESTORE_STACK;
}
/***********************************/
/* silk_noise_shape_quantizer */
/***********************************/
#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
static OPUS_INLINE
#endif
void silk_noise_shape_quantizer(
silk_nsq_state *NSQ, /* I/O NSQ state */
opus_int signalType, /* I Signal type */
const opus_int32 x_sc_Q10[], /* I */
opus_int8 pulses[], /* O */
opus_int16 xq[], /* O */
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 */
opus_int lag, /* I Pitch lag */
opus_int32 HarmShapeFIRPacked_Q14, /* I */
opus_int Tilt_Q14, /* I Spectral tilt */
opus_int32 LF_shp_Q14, /* I */
opus_int32 Gain_Q16, /* I */
opus_int Lambda_Q10, /* I */
opus_int offset_Q10, /* I */
opus_int length, /* I Input length */
opus_int shapingLPCOrder, /* I Noise shaping AR filter order */
opus_int predictLPCOrder, /* I Prediction filter order */
int arch /* I Architecture */
)
{
opus_int i;
opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr;
#ifdef silk_short_prediction_create_arch_coef
opus_int32 a_Q12_arch[MAX_LPC_ORDER];
#endif
shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
/* Set up short term AR state */
psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ];
#ifdef silk_short_prediction_create_arch_coef
silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder);
#endif
for( i = 0; i < length; i++ ) {
/* Generate dither */
NSQ->rand_seed = silk_RAND( NSQ->rand_seed );
/* Short-term prediction */
LPC_pred_Q10 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch);
/* Long-term prediction */
if( signalType == TYPE_VOICED ) {
/* Unrolled loop */
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
LTP_pred_Q13 = 2;
LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, 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_Q13 = 0;
}
/* Noise shape feedback */
celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(&NSQ->sDiff_shp_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch);
n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 );
n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 );
n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 );
celt_assert( lag > 0 || signalType != TYPE_VOICED );
/* Combine prediction and noise shaping signals */
tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */
tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */
if( lag > 0 ) {
/* Symmetric, packed FIR coefficients */
n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 );
shp_lag_ptr++;
tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */
tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */
tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */
} else {
tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */
}
r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */
/* Flip sign depending on dither */
if( NSQ->rand_seed < 0 ) {
r_Q10 = -r_Q10;
}
r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
/* Find two quantization level candidates and measure their rate-distortion */
q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
if (Lambda_Q10 > 2048) {
/* For aggressive RDO, the bias becomes more than one pulse. */
int rdo_offset = Lambda_Q10/2 - 512;
if (q1_Q10 > rdo_offset) {
q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 );
} else if (q1_Q10 < -rdo_offset) {
q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 );
} else if (q1_Q10 < 0) {
q1_Q0 = -1;
} else {
q1_Q0 = 0;
}
}
if( q1_Q0 > 0 ) {
q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
q2_Q10 = silk_ADD32( q1_Q10, 1024 );
rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
} else if( q1_Q0 == 0 ) {
q1_Q10 = offset_Q10;
q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
} else if( q1_Q0 == -1 ) {
q2_Q10 = offset_Q10;
q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
} else { /* Q1_Q0 < -1 */
q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
q2_Q10 = silk_ADD32( q1_Q10, 1024 );
rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
}
rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 );
rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 );
if( rd2_Q20 < rd1_Q20 ) {
q1_Q10 = q2_Q10;
}
pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 );
/* Excitation */
exc_Q14 = silk_LSHIFT( q1_Q10, 4 );
if ( NSQ->rand_seed < 0 ) {
exc_Q14 = -exc_Q14;
}
/* Add predictions */
LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 );
xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 );
/* Scale XQ back to normal level before saving */
xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) );
/* Update states */
psLPC_Q14++;
*psLPC_Q14 = xq_Q14;
NSQ->sDiff_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_sc_Q10[ i ], 4 );
sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( NSQ->sDiff_shp_Q14, n_AR_Q12, 2 );
NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14;
NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 );
sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 );
NSQ->sLTP_shp_buf_idx++;
NSQ->sLTP_buf_idx++;
/* Make dither dependent on quantized signal */
NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] );
}
/* Update LPC synth buffer */
silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
}
static OPUS_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 x16[], /* I input */
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_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 */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
const opus_int signal_type /* I Signal type */
)
{
opus_int i, lag;
opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26;
lag = pitchL[ subfr ];
inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
silk_assert( inv_gain_Q31 != 0 );
/* Scale input */
inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 );
for( i = 0; i < psEncC->subfr_length; i++ ) {
x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 );
}
/* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
if( NSQ->rewhite_flag ) {
if( subfr == 0 ) {
/* Do LTP downscaling */
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_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
}
}
/* Adjust for changing gain */
if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
/* Scale long-term shaping state */
for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
}
/* 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_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
}
}
NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 );
NSQ->sDiff_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sDiff_shp_Q14 );
/* Scale short-term prediction and shaping states */
for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] );
}
for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] );
}
/* Save inverse gain */
NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
}
}

View file

@ -0,0 +1,101 @@
/***********************************************************************
Copyright (c) 2014 Vidyo.
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.
***********************************************************************/
#ifndef SILK_NSQ_H
#define SILK_NSQ_H
#include "SigProc_FIX.h"
#undef silk_short_prediction_create_arch_coef
static OPUS_INLINE opus_int32 silk_noise_shape_quantizer_short_prediction_c(const opus_int32 *buf32, const opus_int16 *coef16, opus_int order)
{
opus_int32 out;
silk_assert( order == 10 || order == 16 );
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
out = silk_RSHIFT( order, 1 );
out = silk_SMLAWB( out, buf32[ 0 ], coef16[ 0 ] );
out = silk_SMLAWB( out, buf32[ -1 ], coef16[ 1 ] );
out = silk_SMLAWB( out, buf32[ -2 ], coef16[ 2 ] );
out = silk_SMLAWB( out, buf32[ -3 ], coef16[ 3 ] );
out = silk_SMLAWB( out, buf32[ -4 ], coef16[ 4 ] );
out = silk_SMLAWB( out, buf32[ -5 ], coef16[ 5 ] );
out = silk_SMLAWB( out, buf32[ -6 ], coef16[ 6 ] );
out = silk_SMLAWB( out, buf32[ -7 ], coef16[ 7 ] );
out = silk_SMLAWB( out, buf32[ -8 ], coef16[ 8 ] );
out = silk_SMLAWB( out, buf32[ -9 ], coef16[ 9 ] );
if( order == 16 )
{
out = silk_SMLAWB( out, buf32[ -10 ], coef16[ 10 ] );
out = silk_SMLAWB( out, buf32[ -11 ], coef16[ 11 ] );
out = silk_SMLAWB( out, buf32[ -12 ], coef16[ 12 ] );
out = silk_SMLAWB( out, buf32[ -13 ], coef16[ 13 ] );
out = silk_SMLAWB( out, buf32[ -14 ], coef16[ 14 ] );
out = silk_SMLAWB( out, buf32[ -15 ], coef16[ 15 ] );
}
return out;
}
#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) ((void)arch,silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
static OPUS_INLINE opus_int32 silk_NSQ_noise_shape_feedback_loop_c(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order)
{
opus_int32 out;
opus_int32 tmp1, tmp2;
opus_int j;
tmp2 = data0[0];
tmp1 = data1[0];
data1[0] = tmp2;
out = silk_RSHIFT(order, 1);
out = silk_SMLAWB(out, tmp2, coef[0]);
for (j = 2; j < order; j += 2) {
tmp2 = data1[j - 1];
data1[j - 1] = tmp1;
out = silk_SMLAWB(out, tmp1, coef[j - 1]);
tmp1 = data1[j + 0];
data1[j + 0] = tmp2;
out = silk_SMLAWB(out, tmp2, coef[j]);
}
data1[order - 1] = tmp1;
out = silk_SMLAWB(out, tmp1, coef[order - 1]);
/* Q11 -> Q12 */
out = silk_LSHIFT32( out, 1 );
return out;
}
#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order))
#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
#include "arm/NSQ_neon.h"
#endif
#endif /* SILK_NSQ_H */

View file

@ -0,0 +1,733 @@
/***********************************************************************
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"
#include "NSQ.h"
typedef struct {
opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
opus_int32 RandState[ DECISION_DELAY ];
opus_int32 Q_Q10[ DECISION_DELAY ];
opus_int32 Xq_Q14[ DECISION_DELAY ];
opus_int32 Pred_Q15[ DECISION_DELAY ];
opus_int32 Shape_Q14[ DECISION_DELAY ];
opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
opus_int32 LF_AR_Q14;
opus_int32 Diff_Q14;
opus_int32 Seed;
opus_int32 SeedInit;
opus_int32 RD_Q10;
} NSQ_del_dec_struct;
typedef struct {
opus_int32 Q_Q10;
opus_int32 RD_Q10;
opus_int32 xq_Q14;
opus_int32 LF_AR_Q14;
opus_int32 Diff_Q14;
opus_int32 sLTP_shp_Q14;
opus_int32 LPC_exc_Q14;
} NSQ_sample_struct;
typedef NSQ_sample_struct NSQ_sample_pair[ 2 ];
#if defined(MIPSr1_ASM)
#include "mips/NSQ_del_dec_mipsr1.h"
#endif
static OPUS_INLINE void silk_nsq_del_dec_scale_states(
const silk_encoder_state *psEncC, /* I Encoder State */
silk_nsq_state *NSQ, /* I/O NSQ state */
NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
const opus_int16 x16[], /* I Input */
opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
opus_int subfr, /* I Subframe number */
opus_int nStatesDelayedDecision, /* I Number of del dec states */
const opus_int LTP_scale_Q14, /* I LTP state scaling */
const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
const opus_int signal_type, /* I Signal type */
const opus_int decisionDelay /* I Decision delay */
);
/******************************************/
/* Noise shape quantizer for one subframe */
/******************************************/
static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
silk_nsq_state *NSQ, /* I/O NSQ state */
NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
opus_int signalType, /* I Signal type */
const opus_int32 x_Q10[], /* I */
opus_int8 pulses[], /* O */
opus_int16 xq[], /* O */
opus_int32 sLTP_Q15[], /* I/O LTP filter state */
opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
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 coefs */
opus_int lag, /* I Pitch lag */
opus_int32 HarmShapeFIRPacked_Q14, /* I */
opus_int Tilt_Q14, /* I Spectral tilt */
opus_int32 LF_shp_Q14, /* I */
opus_int32 Gain_Q16, /* I */
opus_int Lambda_Q10, /* I */
opus_int offset_Q10, /* I */
opus_int length, /* I Input length */
opus_int subfr, /* I Subframe number */
opus_int shapingLPCOrder, /* I Shaping LPC filter order */
opus_int predictLPCOrder, /* I Prediction filter order */
opus_int warping_Q16, /* I */
opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */
opus_int decisionDelay, /* I */
int arch /* I */
);
void silk_NSQ_del_dec_c(
const silk_encoder_state *psEncC, /* I Encoder State */
silk_nsq_state *NSQ, /* I/O NSQ state */
SideInfoIndices *psIndices, /* I/O Quantization Indices */
const opus_int16 x16[], /* I Input */
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 */
const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
const opus_int LTP_scale_Q14 /* I LTP state scaling */
)
{
opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr;
opus_int last_smple_idx, smpl_buf_idx, decisionDelay;
const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
opus_int16 *pxq;
VARDECL( opus_int32, sLTP_Q15 );
VARDECL( opus_int16, sLTP );
opus_int32 HarmShapeFIRPacked_Q14;
opus_int offset_Q10;
opus_int32 RDmin_Q10, Gain_Q10;
VARDECL( opus_int32, x_sc_Q10 );
VARDECL( opus_int32, delayedGain_Q10 );
VARDECL( NSQ_del_dec_struct, psDelDec );
NSQ_del_dec_struct *psDD;
SAVE_STACK;
/* Set unvoiced lag to the previous one, overwrite later for voiced */
lag = NSQ->lagPrev;
silk_assert( NSQ->prev_gain_Q16 != 0 );
/* Initialize delayed decision states */
ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct );
silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) );
for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) {
psDD = &psDelDec[ k ];
psDD->Seed = ( k + psIndices->Seed ) & 3;
psDD->SeedInit = psDD->Seed;
psDD->RD_Q10 = 0;
psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14;
psDD->Diff_Q14 = NSQ->sDiff_shp_Q14;
psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ];
silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) );
}
offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
smpl_buf_idx = 0; /* index of oldest samples */
decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length );
/* For voiced frames limit the decision delay to lower than the pitch lag */
if( psIndices->signalType == TYPE_VOICED ) {
for( k = 0; k < psEncC->nb_subfr; k++ ) {
decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 );
}
} else {
if( lag > 0 ) {
decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 );
}
}
if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
LSF_interpolation_flag = 0;
} else {
LSF_interpolation_flag = 1;
}
ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 );
/* Set up pointers to start of sub frame */
pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
subfr = 0;
for( k = 0; k < psEncC->nb_subfr; k++ ) {
A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ];
B_Q14 = &LTPCoef_Q14[ k * LTP_ORDER ];
AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ];
/* 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 );
NSQ->rewhite_flag = 0;
if( psIndices->signalType == TYPE_VOICED ) {
/* Voiced */
lag = pitchL[ k ];
/* Re-whitening */
if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
if( k == 2 ) {
/* RESET DELAYED DECISIONS */
/* Find winner */
RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
Winner_ind = 0;
for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) {
if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) {
RDmin_Q10 = psDelDec[ i ].RD_Q10;
Winner_ind = i;
}
}
for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) {
if( i != Winner_ind ) {
psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 );
silk_assert( psDelDec[ i ].RD_Q10 >= 0 );
}
}
/* Copy final part of signals from winner state to output and long-term filter states */
psDD = &psDelDec[ Winner_ind ];
last_smple_idx = smpl_buf_idx + decisionDelay;
for( i = 0; i < decisionDelay; i++ ) {
last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY;
if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY;
pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) );
NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
}
subfr = 0;
}
/* Rewhiten with new A coefs */
start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
celt_assert( start_idx > 0 );
silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
NSQ->rewhite_flag = 1;
}
}
silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k,
psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay );
silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15,
delayedGain_Q10, 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, subfr++, psEncC->shapingLPCOrder,
psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay, psEncC->arch );
x16 += psEncC->subfr_length;
pulses += psEncC->subfr_length;
pxq += psEncC->subfr_length;
}
/* Find winner */
RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
Winner_ind = 0;
for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) {
if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) {
RDmin_Q10 = psDelDec[ k ].RD_Q10;
Winner_ind = k;
}
}
/* Copy final part of signals from winner state to output and long-term filter states */
psDD = &psDelDec[ Winner_ind ];
psIndices->Seed = psDD->SeedInit;
last_smple_idx = smpl_buf_idx + decisionDelay;
Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 );
for( i = 0; i < decisionDelay; i++ ) {
last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY;
if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY;
pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) );
NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
}
silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) );
/* Update states */
NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14;
NSQ->sDiff_shp_Q14 = psDD->Diff_Q14;
NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
/* Save quantized speech signal */
silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
RESTORE_STACK;
}
/******************************************/
/* Noise shape quantizer for one subframe */
/******************************************/
#ifndef OVERRIDE_silk_noise_shape_quantizer_del_dec
static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
silk_nsq_state *NSQ, /* I/O NSQ state */
NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
opus_int signalType, /* I Signal type */
const opus_int32 x_Q10[], /* I */
opus_int8 pulses[], /* O */
opus_int16 xq[], /* O */
opus_int32 sLTP_Q15[], /* I/O LTP filter state */
opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
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 coefs */
opus_int lag, /* I Pitch lag */
opus_int32 HarmShapeFIRPacked_Q14, /* I */
opus_int Tilt_Q14, /* I Spectral tilt */
opus_int32 LF_shp_Q14, /* I */
opus_int32 Gain_Q16, /* I */
opus_int Lambda_Q10, /* I */
opus_int offset_Q10, /* I */
opus_int length, /* I Input length */
opus_int subfr, /* I Subframe number */
opus_int shapingLPCOrder, /* I Shaping LPC filter order */
opus_int predictLPCOrder, /* I Prediction filter order */
opus_int warping_Q16, /* I */
opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */
opus_int decisionDelay, /* I */
int arch /* I */
)
{
opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
opus_int32 Winner_rand_state;
opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14;
#ifdef silk_short_prediction_create_arch_coef
opus_int32 a_Q12_arch[MAX_LPC_ORDER];
#endif
VARDECL( NSQ_sample_pair, psSampleState );
NSQ_del_dec_struct *psDD;
NSQ_sample_struct *psSS;
SAVE_STACK;
celt_assert( nStatesDelayedDecision > 0 );
ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair );
shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
#ifdef silk_short_prediction_create_arch_coef
silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder);
#endif
for( i = 0; i < length; i++ ) {
/* Perform common calculations used in all states */
/* Long-term prediction */
if( signalType == TYPE_VOICED ) {
/* Unrolled loop */
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
LTP_pred_Q14 = 2;
LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, 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_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */
pred_lag_ptr++;
} else {
LTP_pred_Q14 = 0;
}
/* Long-term shaping */
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_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */
shp_lag_ptr++;
} else {
n_LTP_Q14 = 0;
}
for( k = 0; k < nStatesDelayedDecision; k++ ) {
/* Delayed decision state */
psDD = &psDelDec[ k ];
/* Sample state */
psSS = psSampleState[ k ];
/* Generate dither */
psDD->Seed = silk_RAND( psDD->Seed );
/* Pointer used in short term prediction and shaping */
psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ];
/* Short-term prediction */
LPC_pred_Q14 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch);
LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */
/* Noise shape feedback */
celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
/* Output of lowpass section */
tmp2 = silk_SMLAWB( psDD->Diff_Q14, psDD->sAR2_Q14[ 0 ], warping_Q16 );
/* Output of allpass section */
tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 );
psDD->sAR2_Q14[ 0 ] = tmp2;
n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 );
n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] );
/* Loop over allpass sections */
for( j = 2; j < shapingLPCOrder; j += 2 ) {
/* Output of allpass section */
tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 );
psDD->sAR2_Q14[ j - 1 ] = tmp1;
n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] );
/* Output of allpass section */
tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 );
psDD->sAR2_Q14[ j + 0 ] = tmp2;
n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] );
}
psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */
n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */
n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */
n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */
n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */
n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */
/* Input minus prediction plus noise feedback */
/* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */
tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */
tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */
tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */
tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */
r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */
/* Flip sign depending on dither */
if ( psDD->Seed < 0 ) {
r_Q10 = -r_Q10;
}
r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
/* Find two quantization level candidates and measure their rate-distortion */
q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
if (Lambda_Q10 > 2048) {
/* For aggressive RDO, the bias becomes more than one pulse. */
int rdo_offset = Lambda_Q10/2 - 512;
if (q1_Q10 > rdo_offset) {
q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 );
} else if (q1_Q10 < -rdo_offset) {
q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 );
} else if (q1_Q10 < 0) {
q1_Q0 = -1;
} else {
q1_Q0 = 0;
}
}
if( q1_Q0 > 0 ) {
q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
q2_Q10 = silk_ADD32( q1_Q10, 1024 );
rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
} else if( q1_Q0 == 0 ) {
q1_Q10 = offset_Q10;
q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
} else if( q1_Q0 == -1 ) {
q2_Q10 = offset_Q10;
q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
} else { /* q1_Q0 < -1 */
q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
q2_Q10 = silk_ADD32( q1_Q10, 1024 );
rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
}
rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 );
rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 );
if( rd1_Q10 < rd2_Q10 ) {
psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
psSS[ 0 ].Q_Q10 = q1_Q10;
psSS[ 1 ].Q_Q10 = q2_Q10;
} else {
psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
psSS[ 0 ].Q_Q10 = q2_Q10;
psSS[ 1 ].Q_Q10 = q1_Q10;
}
/* Update states for best quantization */
/* Quantized excitation */
exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 );
if ( psDD->Seed < 0 ) {
exc_Q14 = -exc_Q14;
}
/* Add predictions */
LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
/* Update states */
psSS[ 0 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 );
sLF_AR_shp_Q14 = silk_SUB32( psSS[ 0 ].Diff_Q14, n_AR_Q14 );
psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14;
psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14;
psSS[ 0 ].xq_Q14 = xq_Q14;
/* Update states for second best quantization */
/* Quantized excitation */
exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 );
if ( psDD->Seed < 0 ) {
exc_Q14 = -exc_Q14;
}
/* Add predictions */
LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
/* Update states */
psSS[ 1 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 );
sLF_AR_shp_Q14 = silk_SUB32( psSS[ 1 ].Diff_Q14, n_AR_Q14 );
psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14;
psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14;
psSS[ 1 ].xq_Q14 = xq_Q14;
}
*smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY;
if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY;
last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY;
/* Find winner */
RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
Winner_ind = 0;
for( k = 1; k < nStatesDelayedDecision; k++ ) {
if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) {
RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
Winner_ind = k;
}
}
/* Increase RD values of expired states */
Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ];
for( k = 0; k < nStatesDelayedDecision; k++ ) {
if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) {
psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 );
psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 );
silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 );
}
}
/* Find worst in first set and best in second set */
RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10;
RDmax_ind = 0;
RDmin_ind = 0;
for( k = 1; k < nStatesDelayedDecision; k++ ) {
/* find worst in first set */
if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) {
RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
RDmax_ind = k;
}
/* find best in second set */
if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) {
RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10;
RDmin_ind = k;
}
}
/* Replace a state if best from second set outperforms worst in first set */
if( RDmin_Q10 < RDmax_Q10 ) {
silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i,
( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) );
silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) );
}
/* Write samples from winner to output and long-term filter states */
psDD = &psDelDec[ Winner_ind ];
if( subfr > 0 || i >= decisionDelay ) {
pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) );
NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ];
sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ];
}
NSQ->sLTP_shp_buf_idx++;
NSQ->sLTP_buf_idx++;
/* Update states */
for( k = 0; k < nStatesDelayedDecision; k++ ) {
psDD = &psDelDec[ k ];
psSS = &psSampleState[ k ][ 0 ];
psDD->LF_AR_Q14 = psSS->LF_AR_Q14;
psDD->Diff_Q14 = psSS->Diff_Q14;
psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14;
psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14;
psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10;
psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 );
psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14;
psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) );
psDD->RandState[ *smpl_buf_idx ] = psDD->Seed;
psDD->RD_Q10 = psSS->RD_Q10;
}
delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10;
}
/* Update LPC states */
for( k = 0; k < nStatesDelayedDecision; k++ ) {
psDD = &psDelDec[ k ];
silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
}
RESTORE_STACK;
}
#endif /* OVERRIDE_silk_noise_shape_quantizer_del_dec */
static OPUS_INLINE void silk_nsq_del_dec_scale_states(
const silk_encoder_state *psEncC, /* I Encoder State */
silk_nsq_state *NSQ, /* I/O NSQ state */
NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
const opus_int16 x16[], /* I Input */
opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
opus_int subfr, /* I Subframe number */
opus_int nStatesDelayedDecision, /* I Number of del dec states */
const opus_int LTP_scale_Q14, /* I LTP state scaling */
const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
const opus_int signal_type, /* I Signal type */
const opus_int decisionDelay /* I Decision delay */
)
{
opus_int i, k, lag;
opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26;
NSQ_del_dec_struct *psDD;
lag = pitchL[ subfr ];
inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
silk_assert( inv_gain_Q31 != 0 );
/* Scale input */
inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 );
for( i = 0; i < psEncC->subfr_length; i++ ) {
x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 );
}
/* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
if( NSQ->rewhite_flag ) {
if( subfr == 0 ) {
/* Do LTP downscaling */
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_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
}
}
/* Adjust for changing gain */
if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
/* Scale long-term shaping state */
for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
}
/* 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 - decisionDelay; i++ ) {
sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
}
}
for( k = 0; k < nStatesDelayedDecision; k++ ) {
psDD = &psDelDec[ k ];
/* Scale scalar states */
psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 );
psDD->Diff_Q14 = silk_SMULWW( gain_adj_Q16, psDD->Diff_Q14 );
/* Scale short-term prediction and shaping states */
for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] );
}
for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] );
}
for( i = 0; i < DECISION_DELAY; i++ ) {
psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] );
psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] );
}
}
/* Save inverse gain */
NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
}
}

View file

@ -46,7 +46,8 @@ static OPUS_INLINE void silk_PLC_update(
static OPUS_INLINE void silk_PLC_conceal(
silk_decoder_state *psDec, /* I/O Decoder state */
silk_decoder_control *psDecCtrl, /* I/O Decoder control */
opus_int16 frame[] /* O LPC residual signal */
opus_int16 frame[], /* O LPC residual signal */
int arch /* I Run-time architecture */
);
@ -65,7 +66,8 @@ void silk_PLC(
silk_decoder_state *psDec, /* I/O Decoder state */
silk_decoder_control *psDecCtrl, /* I/O Decoder control */
opus_int16 frame[], /* I/O signal */
opus_int lost /* I Loss flag */
opus_int lost, /* I Loss flag */
int arch /* I Run-time architecture */
)
{
/* PLC control function */
@ -78,7 +80,7 @@ void silk_PLC(
/****************************/
/* Generate Signal */
/****************************/
silk_PLC_conceal( psDec, psDecCtrl, frame );
silk_PLC_conceal( psDec, psDecCtrl, frame, arch );
psDec->lossCnt++;
} else {
@ -192,7 +194,8 @@ static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, o
static OPUS_INLINE void silk_PLC_conceal(
silk_decoder_state *psDec, /* I/O Decoder state */
silk_decoder_control *psDecCtrl, /* I/O Decoder control */
opus_int16 frame[] /* O LPC residual signal */
opus_int16 frame[], /* O LPC residual signal */
int arch /* I Run-time architecture */
)
{
opus_int i, j, k;
@ -272,7 +275,7 @@ static OPUS_INLINE void silk_PLC_conceal(
/* Reduce random noise for unvoiced frames with high LPC gain */
opus_int32 invGain_Q30, down_scale_Q30;
invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order );
invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch );
down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
@ -288,8 +291,8 @@ static OPUS_INLINE void silk_PLC_conceal(
/* Rewhiten LTP state */
idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
silk_assert( idx > 0 );
silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order );
celt_assert( idx > 0 );
silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch );
/* Scale LTP state */
inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
@ -325,8 +328,10 @@ static OPUS_INLINE void silk_PLC_conceal(
for( j = 0; j < LTP_ORDER; j++ ) {
B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
}
/* Gradually reduce excitation gain */
rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
if ( psDec->indices.signalType != TYPE_NO_VOICE_ACTIVITY ) {
/* Gradually reduce excitation gain */
rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
}
/* Slowly increase pitch lag */
psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
@ -342,7 +347,7 @@ static OPUS_INLINE void silk_PLC_conceal(
/* Copy LPC state */
silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
for( i = 0; i < psDec->frame_length; i++ ) {
/* partly unrolled */
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
@ -362,7 +367,8 @@ static OPUS_INLINE void silk_PLC_conceal(
}
/* Add prediction to LPC excitation */
sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ],
silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ));
/* Scale with Gain */
frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) );

View file

@ -48,7 +48,8 @@ void silk_PLC(
silk_decoder_state *psDec, /* I/O Decoder state */
silk_decoder_control *psDecCtrl, /* I/O Decoder control */
opus_int16 frame[], /* I/O signal */
opus_int lost /* I Loss flag */
opus_int lost, /* I Loss flag */
int arch /* I Run-time architecture */
);
void silk_PLC_glue_frames(

View file

@ -35,13 +35,22 @@ extern "C"
/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */
#define SILK_MAX_ORDER_LPC 16 /* max order of the LPC analysis in schur() and k2a() */
#define SILK_MAX_ORDER_LPC 24 /* max order of the LPC analysis in schur() and k2a() */
#include <string.h> /* for memset(), memcpy(), memmove() */
#include "typedef.h"
#include "resampler_structs.h"
#include "macros.h"
#include "cpu_support.h"
#if defined(OPUS_X86_MAY_HAVE_SSE4_1)
#include "x86/SigProc_FIX_sse.h"
#endif
#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
#include "arm/biquad_alt_arm.h"
#include "arm/LPC_inv_pred_gain_arm.h"
#endif
/********************************************************************/
/* SIGNAL PROCESSING FUNCTIONS */
@ -92,14 +101,22 @@ void silk_resampler_down2_3(
* slower than biquad() but uses more precise coefficients
* can handle (slowly) varying coefficients
*/
void silk_biquad_alt(
void silk_biquad_alt_stride1(
const opus_int16 *in, /* I input signal */
const opus_int32 *B_Q28, /* I MA coefficients [3] */
const opus_int32 *A_Q28, /* I AR coefficients [2] */
opus_int32 *S, /* I/O State vector [2] */
opus_int16 *out, /* O output signal */
const opus_int32 len, /* I signal length (must be even) */
opus_int stride /* I Operate on interleaved signal if > 1 */
const opus_int32 len /* I signal length (must be even) */
);
void silk_biquad_alt_stride2_c(
const opus_int16 *in, /* I input signal */
const opus_int32 *B_Q28, /* I MA coefficients [3] */
const opus_int32 *A_Q28, /* I AR coefficients [2] */
opus_int32 *S, /* I/O State vector [4] */
opus_int16 *out, /* O output signal */
const opus_int32 len /* I signal length (must be even) */
);
/* Variable order MA prediction error filter. */
@ -108,7 +125,8 @@ void silk_LPC_analysis_filter(
const opus_int16 *in, /* I Input signal */
const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
const opus_int32 len, /* I Signal length */
const opus_int32 d /* I Filter order */
const opus_int32 d, /* I Filter order */
int arch /* I Run-time architecture */
);
/* Chirp (bandwidth expand) LP AR filter */
@ -127,17 +145,11 @@ void silk_bwexpander_32(
/* Compute inverse of LPC prediction gain, and */
/* test if LPC coefficients are stable (all poles within unit circle) */
opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */
opus_int32 silk_LPC_inverse_pred_gain_c( /* 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 */
);
/* For input in Q24 domain */
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 */
);
/* Split signal in two decimated bands using first-order allpass filters */
void silk_ana_filt_bank_1(
const opus_int16 *in, /* I Input signal [N] */
@ -147,6 +159,14 @@ void silk_ana_filt_bank_1(
const opus_int32 N /* I Number of input samples */
);
#if !defined(OVERRIDE_silk_biquad_alt_stride2)
#define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), silk_biquad_alt_stride2_c(in, B_Q28, A_Q28, S, out, len))
#endif
#if !defined(OVERRIDE_silk_LPC_inverse_pred_gain)
#define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), silk_LPC_inverse_pred_gain_c(A_Q12, order))
#endif
/********************************************************************/
/* SCALAR FUNCTIONS */
/********************************************************************/
@ -266,7 +286,17 @@ void silk_A2NLSF(
void silk_NLSF2A(
opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */
const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */
const opus_int d /* I filter order (should be even) */
const opus_int d, /* I filter order (should be even) */
int arch /* I Run-time architecture */
);
/* 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 */
const opus_int QOUT, /* I Input Q domain */
const opus_int QIN, /* I Input Q domain */
const opus_int d /* I Filter order */
);
void silk_insertion_sort_increasing(
@ -303,7 +333,7 @@ void silk_NLSF_VQ_weights_laroia(
);
/* Compute reflection coefficients from input signal */
void silk_burg_modified(
void silk_burg_modified_c(
opus_int32 *res_nrg, /* O Residual energy */
opus_int *res_nrg_Q, /* O Residual energy Q value */
opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
@ -335,12 +365,15 @@ void silk_scale_vector32_Q26_lshift_18(
/********************************************************************/
/* return sum( inVec1[i] * inVec2[i] ) */
opus_int32 silk_inner_prod_aligned(
const opus_int16 *const inVec1, /* I input vector 1 */
const opus_int16 *const inVec2, /* I input vector 2 */
const opus_int len /* I vector lengths */
const opus_int len, /* I vector lengths */
int arch /* I Run-time architecture */
);
opus_int32 silk_inner_prod_aligned_scale(
const opus_int16 *const inVec1, /* I input vector 1 */
const opus_int16 *const inVec2, /* I input vector 2 */
@ -348,7 +381,7 @@ opus_int32 silk_inner_prod_aligned_scale(
const opus_int len /* I vector lengths */
);
opus_int64 silk_inner_prod16_aligned_64(
opus_int64 silk_inner_prod16_aligned_64_c(
const opus_int16 *inVec1, /* I input vector 1 */
const opus_int16 *inVec2, /* I input vector 2 */
const opus_int len /* I vector lengths */
@ -463,8 +496,7 @@ static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot )
/* Add with saturation for positive input values */
#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b)))
#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b)))
#define silk_ADD_POS_SAT32(a, b) ((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b)))
#define silk_ADD_POS_SAT64(a, b) ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b)))
#define silk_ADD_POS_SAT32(a, b) ((((opus_uint32)(a)+(opus_uint32)(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b)))
#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */
#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */
@ -564,7 +596,9 @@ static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b)
/* Make sure to store the result as the seed for the next call (also in between */
/* frames), otherwise result won't be random at all. When only using some of the */
/* bits, take the most significant bits by right-shifting. */
#define silk_RAND(seed) (silk_MLA_ovflw(907633515, (seed), 196314165))
#define RAND_MULTIPLIER 196314165
#define RAND_INCREMENT 907633515
#define silk_RAND(seed) (silk_MLA_ovflw((RAND_INCREMENT), (seed), (RAND_MULTIPLIER)))
/* Add some multiplication functions that can be easily mapped to ARM. */
@ -575,6 +609,14 @@ static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b)
/* the following seems faster on x86 */
#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32)
#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \
((void)(arch), silk_burg_modified_c(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch))
#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \
((void)(arch),silk_inner_prod16_aligned_64_c(inVec1, inVec2, len))
#endif
#include "Inlines.h"
#include "MacroCount.h"
#include "MacroDebug.h"

View file

@ -0,0 +1,360 @@
/***********************************************************************
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"
/* Silk VAD noise level estimation */
# if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
static OPUS_INLINE void silk_VAD_GetNoiseLevels(
const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */
silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
);
#endif
/**********************************/
/* Initialization of the Silk VAD */
/**********************************/
opus_int silk_VAD_Init( /* O Return value, 0 if success */
silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
)
{
opus_int b, ret = 0;
/* reset state memory */
silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) );
/* init noise levels */
/* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */
for( b = 0; b < VAD_N_BANDS; b++ ) {
psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 );
}
/* Initialize state */
for( b = 0; b < VAD_N_BANDS; b++ ) {
psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] );
psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] );
}
psSilk_VAD->counter = 15;
/* init smoothed energy-to-noise ratio*/
for( b = 0; b < VAD_N_BANDS; b++ ) {
psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */
}
return( ret );
}
/* Weighting factors for tilt measure */
static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 };
/***************************************/
/* Get the speech activity level in Q8 */
/***************************************/
opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */
silk_encoder_state *psEncC, /* I/O Encoder state */
const opus_int16 pIn[] /* I PCM input */
)
{
opus_int SA_Q15, pSNR_dB_Q7, input_tilt;
opus_int decimated_framelength1, decimated_framelength2;
opus_int decimated_framelength;
opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s;
opus_int32 sumSquared, smooth_coef_Q16;
opus_int16 HPstateTmp;
VARDECL( opus_int16, X );
opus_int32 Xnrg[ VAD_N_BANDS ];
opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ];
opus_int32 speech_nrg, x_tmp;
opus_int X_offset[ VAD_N_BANDS ];
opus_int ret = 0;
silk_VAD_state *psSilk_VAD = &psEncC->sVAD;
SAVE_STACK;
/* Safety checks */
silk_assert( VAD_N_BANDS == 4 );
celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length );
celt_assert( psEncC->frame_length <= 512 );
celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) );
/***********************/
/* Filter and Decimate */
/***********************/
decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 );
decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 );
decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 );
/* Decimate into 4 bands:
0 L 3L L 3L 5L
- -- - -- --
8 8 2 4 4
[0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz |
They're arranged to allow the minimal ( frame_length / 4 ) extra
scratch space during the downsampling process */
X_offset[ 0 ] = 0;
X_offset[ 1 ] = decimated_framelength + decimated_framelength2;
X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength;
X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2;
ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 );
/* 0-8 kHz to 0-4 kHz and 4-8 kHz */
silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ],
X, &X[ X_offset[ 3 ] ], psEncC->frame_length );
/* 0-4 kHz to 0-2 kHz and 2-4 kHz */
silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ],
X, &X[ X_offset[ 2 ] ], decimated_framelength1 );
/* 0-2 kHz to 0-1 kHz and 1-2 kHz */
silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ],
X, &X[ X_offset[ 1 ] ], decimated_framelength2 );
/*********************************************/
/* HP filter on lowest band (differentiator) */
/*********************************************/
X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 );
HPstateTmp = X[ decimated_framelength - 1 ];
for( i = decimated_framelength - 1; i > 0; i-- ) {
X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 );
X[ i ] -= X[ i - 1 ];
}
X[ 0 ] -= psSilk_VAD->HPstate;
psSilk_VAD->HPstate = HPstateTmp;
/*************************************/
/* Calculate the energy in each band */
/*************************************/
for( b = 0; b < VAD_N_BANDS; b++ ) {
/* Find the decimated framelength in the non-uniformly divided bands */
decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) );
/* Split length into subframe lengths */
dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 );
dec_subframe_offset = 0;
/* Compute energy per sub-frame */
/* initialize with summed energy of last subframe */
Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ];
for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) {
sumSquared = 0;
for( i = 0; i < dec_subframe_length; i++ ) {
/* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */
/* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */
x_tmp = silk_RSHIFT(
X[ X_offset[ b ] + i + dec_subframe_offset ], 3 );
sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp );
/* Safety check */
silk_assert( sumSquared >= 0 );
}
/* Add/saturate summed energy of current subframe */
if( s < VAD_INTERNAL_SUBFRAMES - 1 ) {
Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared );
} else {
/* Look-ahead subframe */
Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) );
}
dec_subframe_offset += dec_subframe_length;
}
psSilk_VAD->XnrgSubfr[ b ] = sumSquared;
}
/********************/
/* Noise estimation */
/********************/
silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD );
/***********************************************/
/* Signal-plus-noise to noise ratio estimation */
/***********************************************/
sumSquared = 0;
input_tilt = 0;
for( b = 0; b < VAD_N_BANDS; b++ ) {
speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ];
if( speech_nrg > 0 ) {
/* Divide, with sufficient resolution */
if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) {
NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 );
} else {
NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 );
}
/* Convert to log domain */
SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128;
/* Sum-of-squares */
sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */
/* Tilt measure */
if( speech_nrg < ( (opus_int32)1 << 20 ) ) {
/* Scale down SNR value for small subband speech energies */
SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 );
}
input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 );
} else {
NrgToNoiseRatio_Q8[ b ] = 256;
}
}
/* Mean-of-squares */
sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */
/* Root-mean-square approximation, scale to dBs, and write to output pointer */
pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */
/*********************************/
/* Speech Probability Estimation */
/*********************************/
SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 );
/**************************/
/* Frequency Tilt Measure */
/**************************/
psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 );
/**************************************************/
/* Scale the sigmoid output based on power levels */
/**************************************************/
speech_nrg = 0;
for( b = 0; b < VAD_N_BANDS; b++ ) {
/* Accumulate signal-without-noise energies, higher frequency bands have more weight */
speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 );
}
if( psEncC->frame_length == 20 * psEncC->fs_kHz ) {
speech_nrg = silk_RSHIFT32( speech_nrg, 1 );
}
/* Power scaling */
if( speech_nrg <= 0 ) {
SA_Q15 = silk_RSHIFT( SA_Q15, 1 );
} else if( speech_nrg < 16384 ) {
speech_nrg = silk_LSHIFT32( speech_nrg, 16 );
/* square-root */
speech_nrg = silk_SQRT_APPROX( speech_nrg );
SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 );
}
/* Copy the resulting speech activity in Q8 */
psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX );
/***********************************/
/* Energy Level and SNR estimation */
/***********************************/
/* Smoothing coefficient */
smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) );
if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
smooth_coef_Q16 >>= 1;
}
for( b = 0; b < VAD_N_BANDS; b++ ) {
/* compute smoothed energy-to-noise ratio per band */
psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ],
NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 );
/* signal to noise ratio in dB per band */
SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 );
/* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */
psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) );
}
RESTORE_STACK;
return( ret );
}
/**************************/
/* Noise level estimation */
/**************************/
# if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
static OPUS_INLINE
#endif
void silk_VAD_GetNoiseLevels(
const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */
silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
)
{
opus_int k;
opus_int32 nl, nrg, inv_nrg;
opus_int coef, min_coef;
/* Initially faster smoothing */
if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */
min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 );
/* Increment frame counter */
psSilk_VAD->counter++;
} else {
min_coef = 0;
}
for( k = 0; k < VAD_N_BANDS; k++ ) {
/* Get old noise level estimate for current band */
nl = psSilk_VAD->NL[ k ];
silk_assert( nl >= 0 );
/* Add bias */
nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] );
silk_assert( nrg > 0 );
/* Invert energies */
inv_nrg = silk_DIV32( silk_int32_MAX, nrg );
silk_assert( inv_nrg >= 0 );
/* Less update when subband energy is high */
if( nrg > silk_LSHIFT( nl, 3 ) ) {
coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3;
} else if( nrg < nl ) {
coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16;
} else {
coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 );
}
/* Initially faster smoothing */
coef = silk_max_int( coef, min_coef );
/* Smooth inverse energies */
psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef );
silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 );
/* Compute noise level by inverting again */
nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] );
silk_assert( nl >= 0 );
/* Limit noise levels (guarantee 7 bits of head room) */
nl = silk_min( nl, 0x00FFFFFF );
/* Store as part of state */
psSilk_VAD->NL[ k ] = nl;
}
}

View file

@ -0,0 +1,131 @@
/***********************************************************************
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"
/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
void silk_VQ_WMat_EC_c(
opus_int8 *ind, /* O index of best codebook vector */
opus_int32 *res_nrg_Q15, /* O best residual energy */
opus_int32 *rate_dist_Q8, /* O best total bitrate */
opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
const opus_int32 *XX_Q17, /* I correlation matrix */
const opus_int32 *xX_Q17, /* I correlation vector */
const opus_int8 *cb_Q7, /* I codebook */
const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
const opus_int subfr_len, /* I number of samples per subframe */
const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
const opus_int L /* I number of vectors in codebook */
)
{
opus_int k, gain_tmp_Q7;
const opus_int8 *cb_row_Q7;
opus_int32 neg_xX_Q24[ 5 ];
opus_int32 sum1_Q15, sum2_Q24;
opus_int32 bits_res_Q8, bits_tot_Q8;
/* Negate and convert to new Q domain */
neg_xX_Q24[ 0 ] = -silk_LSHIFT32( xX_Q17[ 0 ], 7 );
neg_xX_Q24[ 1 ] = -silk_LSHIFT32( xX_Q17[ 1 ], 7 );
neg_xX_Q24[ 2 ] = -silk_LSHIFT32( xX_Q17[ 2 ], 7 );
neg_xX_Q24[ 3 ] = -silk_LSHIFT32( xX_Q17[ 3 ], 7 );
neg_xX_Q24[ 4 ] = -silk_LSHIFT32( xX_Q17[ 4 ], 7 );
/* Loop over codebook */
*rate_dist_Q8 = silk_int32_MAX;
*res_nrg_Q15 = silk_int32_MAX;
cb_row_Q7 = cb_Q7;
/* In things go really bad, at least *ind is set to something safe. */
*ind = 0;
for( k = 0; k < L; k++ ) {
opus_int32 penalty;
gain_tmp_Q7 = cb_gain_Q7[k];
/* Weighted rate */
/* Quantization error: 1 - 2 * xX * cb + cb' * XX * cb */
sum1_Q15 = SILK_FIX_CONST( 1.001, 15 );
/* Penalty for too large gain */
penalty = silk_LSHIFT32( silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 11 );
/* first row of XX_Q17 */
sum2_Q24 = silk_MLA( neg_xX_Q24[ 0 ], XX_Q17[ 1 ], cb_row_Q7[ 1 ] );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 2 ], cb_row_Q7[ 2 ] );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 3 ], cb_row_Q7[ 3 ] );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 4 ], cb_row_Q7[ 4 ] );
sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 0 ], cb_row_Q7[ 0 ] );
sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 0 ] );
/* second row of XX_Q17 */
sum2_Q24 = silk_MLA( neg_xX_Q24[ 1 ], XX_Q17[ 7 ], cb_row_Q7[ 2 ] );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 8 ], cb_row_Q7[ 3 ] );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 9 ], cb_row_Q7[ 4 ] );
sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 6 ], cb_row_Q7[ 1 ] );
sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 1 ] );
/* third row of XX_Q17 */
sum2_Q24 = silk_MLA( neg_xX_Q24[ 2 ], XX_Q17[ 13 ], cb_row_Q7[ 3 ] );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 14 ], cb_row_Q7[ 4 ] );
sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 12 ], cb_row_Q7[ 2 ] );
sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 2 ] );
/* fourth row of XX_Q17 */
sum2_Q24 = silk_MLA( neg_xX_Q24[ 3 ], XX_Q17[ 19 ], cb_row_Q7[ 4 ] );
sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 18 ], cb_row_Q7[ 3 ] );
sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 3 ] );
/* last row of XX_Q17 */
sum2_Q24 = silk_LSHIFT32( neg_xX_Q24[ 4 ], 1 );
sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 24 ], cb_row_Q7[ 4 ] );
sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 4 ] );
/* find best */
if( sum1_Q15 >= 0 ) {
/* Translate residual energy to bits using high-rate assumption (6 dB ==> 1 bit/sample) */
bits_res_Q8 = silk_SMULBB( subfr_len, silk_lin2log( sum1_Q15 + penalty) - (15 << 7) );
/* In the following line we reduce the codelength component by half ("-1"); seems to slghtly improve quality */
bits_tot_Q8 = silk_ADD_LSHIFT32( bits_res_Q8, cl_Q5[ k ], 3-1 );
if( bits_tot_Q8 <= *rate_dist_Q8 ) {
*rate_dist_Q8 = bits_tot_Q8;
*res_nrg_Q15 = sum1_Q15 + penalty;
*ind = (opus_int8)k;
*gain_Q7 = gain_tmp_Q7;
}
}
/* Go to next cbk vector */
cb_row_Q7 += LTP_ORDER;
}
}

View file

@ -0,0 +1,74 @@
/***********************************************************************
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 "SigProc_FIX.h"
/* Coefficients for 2-band filter bank based on first-order allpass filters */
static opus_int16 A_fb1_20 = 5394 << 1;
static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */
/* Split signal into two decimated bands using first-order allpass filters */
void silk_ana_filt_bank_1(
const opus_int16 *in, /* I Input signal [N] */
opus_int32 *S, /* I/O State vector [2] */
opus_int16 *outL, /* O Low band [N/2] */
opus_int16 *outH, /* O High band [N/2] */
const opus_int32 N /* I Number of input samples */
)
{
opus_int k, N2 = silk_RSHIFT( N, 1 );
opus_int32 in32, X, Y, out_1, out_2;
/* Internal variables and state are in Q10 format */
for( k = 0; k < N2; k++ ) {
/* Convert to Q10 */
in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 );
/* All-pass section for even input sample */
Y = silk_SUB32( in32, S[ 0 ] );
X = silk_SMLAWB( Y, Y, A_fb1_21 );
out_1 = silk_ADD32( S[ 0 ], X );
S[ 0 ] = silk_ADD32( in32, X );
/* Convert to Q10 */
in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 );
/* All-pass section for odd input sample, and add to output of previous section */
Y = silk_SUB32( in32, S[ 1 ] );
X = silk_SMULWB( Y, A_fb1_20 );
out_2 = silk_ADD32( S[ 1 ], X );
S[ 1 ] = silk_ADD32( in32, X );
/* Add/subtract, convert back to int16 and store to output */
outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) );
outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) );
}
}

View file

@ -0,0 +1,57 @@
/***********************************************************************
Copyright (c) 2017 Google Inc.
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.
***********************************************************************/
#ifndef SILK_LPC_INV_PRED_GAIN_ARM_H
# define SILK_LPC_INV_PRED_GAIN_ARM_H
# include "celt/arm/armcpu.h"
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
opus_int32 silk_LPC_inverse_pred_gain_neon( /* 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 */
);
# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON)
# define OVERRIDE_silk_LPC_inverse_pred_gain (1)
# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), PRESUME_NEON(silk_LPC_inverse_pred_gain)(A_Q12, order))
# endif
# endif
# if !defined(OVERRIDE_silk_LPC_inverse_pred_gain)
/*Is run-time CPU detection enabled on this platform?*/
# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
extern opus_int32 (*const SILK_LPC_INVERSE_PRED_GAIN_IMPL[OPUS_ARCHMASK+1])(const opus_int16 *A_Q12, const opus_int order);
# define OVERRIDE_silk_LPC_inverse_pred_gain (1)
# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((*SILK_LPC_INVERSE_PRED_GAIN_IMPL[(arch)&OPUS_ARCHMASK])(A_Q12, order))
# elif defined(OPUS_ARM_PRESUME_NEON_INTR)
# define OVERRIDE_silk_LPC_inverse_pred_gain (1)
# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), silk_LPC_inverse_pred_gain_neon(A_Q12, order))
# endif
# endif
#endif /* end SILK_LPC_INV_PRED_GAIN_ARM_H */

View file

@ -0,0 +1,280 @@
/***********************************************************************
Copyright (c) 2017 Google Inc.
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 <arm_neon.h>
#include "SigProc_FIX.h"
#include "define.h"
#define QA 24
#define A_LIMIT SILK_FIX_CONST( 0.99975, QA )
#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q)))
/* The difficulty is how to judge a 64-bit signed integer tmp64 is 32-bit overflowed,
* since NEON has no 64-bit min, max or comparison instructions.
* A failed idea is to compare the results of vmovn(tmp64) and vqmovn(tmp64) whether they are equal or not.
* However, this idea fails when the tmp64 is something like 0xFFFFFFF980000000.
* Here we know that mult2Q >= 1, so the highest bit (bit 63, sign bit) of tmp64 must equal to bit 62.
* tmp64 was shifted left by 1 and we got tmp64'. If high_half(tmp64') != 0 and high_half(tmp64') != -1,
* then we know that bit 31 to bit 63 of tmp64 can not all be the sign bit, and therefore tmp64 is 32-bit overflowed.
* That is, we judge if tmp64' > 0x00000000FFFFFFFF, or tmp64' <= 0xFFFFFFFF00000000.
* We use narrowing shift right 31 bits to tmp32' to save data bandwidth and instructions.
* That is, we judge if tmp32' > 0x00000000, or tmp32' <= 0xFFFFFFFF.
*/
/* Compute inverse of LPC prediction gain, and */
/* test if LPC coefficients are stable (all poles within unit circle) */
static OPUS_INLINE opus_int32 LPC_inverse_pred_gain_QA_neon( /* O Returns inverse prediction gain in energy domain, Q30 */
opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */
const opus_int order /* I Prediction order */
)
{
opus_int k, n, mult2Q;
opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2;
opus_int32 max, min;
int32x4_t max_s32x4, min_s32x4;
int32x2_t max_s32x2, min_s32x2;
max_s32x4 = vdupq_n_s32( silk_int32_MIN );
min_s32x4 = vdupq_n_s32( silk_int32_MAX );
invGain_Q30 = SILK_FIX_CONST( 1, 30 );
for( k = order - 1; k > 0; k-- ) {
int32x2_t rc_Q31_s32x2, rc_mult2_s32x2;
int64x2_t mult2Q_s64x2;
/* Check for stability */
if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) {
return 0;
}
/* Set RC equal to negated AR coef */
rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA );
/* rc_mult1_Q30 range: [ 1 : 2^30 ] */
rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) );
silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */
silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) );
/* 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 ) );
if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
return 0;
}
/* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) );
rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 );
/* Update AR coefficient */
rc_Q31_s32x2 = vdup_n_s32( rc_Q31 );
mult2Q_s64x2 = vdupq_n_s64( -mult2Q );
rc_mult2_s32x2 = vdup_n_s32( rc_mult2 );
for( n = 0; n < ( ( k + 1 ) >> 1 ) - 3; n += 4 ) {
/* We always calculate extra elements of A_QA buffer when ( k % 4 ) != 0, to take the advantage of SIMD parallelization. */
int32x4_t tmp1_s32x4, tmp2_s32x4, t0_s32x4, t1_s32x4, s0_s32x4, s1_s32x4, t_QA0_s32x4, t_QA1_s32x4;
int64x2_t t0_s64x2, t1_s64x2, t2_s64x2, t3_s64x2;
tmp1_s32x4 = vld1q_s32( A_QA + n );
tmp2_s32x4 = vld1q_s32( A_QA + k - n - 4 );
tmp2_s32x4 = vrev64q_s32( tmp2_s32x4 );
tmp2_s32x4 = vcombine_s32( vget_high_s32( tmp2_s32x4 ), vget_low_s32( tmp2_s32x4 ) );
t0_s32x4 = vqrdmulhq_lane_s32( tmp2_s32x4, rc_Q31_s32x2, 0 );
t1_s32x4 = vqrdmulhq_lane_s32( tmp1_s32x4, rc_Q31_s32x2, 0 );
t_QA0_s32x4 = vqsubq_s32( tmp1_s32x4, t0_s32x4 );
t_QA1_s32x4 = vqsubq_s32( tmp2_s32x4, t1_s32x4 );
t0_s64x2 = vmull_s32( vget_low_s32 ( t_QA0_s32x4 ), rc_mult2_s32x2 );
t1_s64x2 = vmull_s32( vget_high_s32( t_QA0_s32x4 ), rc_mult2_s32x2 );
t2_s64x2 = vmull_s32( vget_low_s32 ( t_QA1_s32x4 ), rc_mult2_s32x2 );
t3_s64x2 = vmull_s32( vget_high_s32( t_QA1_s32x4 ), rc_mult2_s32x2 );
t0_s64x2 = vrshlq_s64( t0_s64x2, mult2Q_s64x2 );
t1_s64x2 = vrshlq_s64( t1_s64x2, mult2Q_s64x2 );
t2_s64x2 = vrshlq_s64( t2_s64x2, mult2Q_s64x2 );
t3_s64x2 = vrshlq_s64( t3_s64x2, mult2Q_s64x2 );
t0_s32x4 = vcombine_s32( vmovn_s64( t0_s64x2 ), vmovn_s64( t1_s64x2 ) );
t1_s32x4 = vcombine_s32( vmovn_s64( t2_s64x2 ), vmovn_s64( t3_s64x2 ) );
s0_s32x4 = vcombine_s32( vshrn_n_s64( t0_s64x2, 31 ), vshrn_n_s64( t1_s64x2, 31 ) );
s1_s32x4 = vcombine_s32( vshrn_n_s64( t2_s64x2, 31 ), vshrn_n_s64( t3_s64x2, 31 ) );
max_s32x4 = vmaxq_s32( max_s32x4, s0_s32x4 );
min_s32x4 = vminq_s32( min_s32x4, s0_s32x4 );
max_s32x4 = vmaxq_s32( max_s32x4, s1_s32x4 );
min_s32x4 = vminq_s32( min_s32x4, s1_s32x4 );
t1_s32x4 = vrev64q_s32( t1_s32x4 );
t1_s32x4 = vcombine_s32( vget_high_s32( t1_s32x4 ), vget_low_s32( t1_s32x4 ) );
vst1q_s32( A_QA + n, t0_s32x4 );
vst1q_s32( A_QA + k - n - 4, t1_s32x4 );
}
for( ; n < (k + 1) >> 1; n++ ) {
opus_int64 tmp64;
tmp1 = A_QA[ n ];
tmp2 = A_QA[ k - n - 1 ];
tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1,
MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q);
if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) {
return 0;
}
A_QA[ n ] = ( opus_int32 )tmp64;
tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2,
MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q);
if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) {
return 0;
}
A_QA[ k - n - 1 ] = ( opus_int32 )tmp64;
}
}
/* Check for stability */
if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) {
return 0;
}
max_s32x2 = vmax_s32( vget_low_s32( max_s32x4 ), vget_high_s32( max_s32x4 ) );
min_s32x2 = vmin_s32( vget_low_s32( min_s32x4 ), vget_high_s32( min_s32x4 ) );
max_s32x2 = vmax_s32( max_s32x2, vreinterpret_s32_s64( vshr_n_s64( vreinterpret_s64_s32( max_s32x2 ), 32 ) ) );
min_s32x2 = vmin_s32( min_s32x2, vreinterpret_s32_s64( vshr_n_s64( vreinterpret_s64_s32( min_s32x2 ), 32 ) ) );
max = vget_lane_s32( max_s32x2, 0 );
min = vget_lane_s32( min_s32x2, 0 );
if( ( max > 0 ) || ( min < -1 ) ) {
return 0;
}
/* Set RC equal to negated AR coef */
rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA );
/* Range: [ 1 : 2^30 ] */
rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) );
/* 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 ) );
if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
return 0;
}
return invGain_Q30;
}
/* For input in Q12 domain */
opus_int32 silk_LPC_inverse_pred_gain_neon( /* 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 */
)
{
#ifdef OPUS_CHECK_ASM
const opus_int32 invGain_Q30_c = silk_LPC_inverse_pred_gain_c( A_Q12, order );
#endif
opus_int32 invGain_Q30;
if( ( SILK_MAX_ORDER_LPC != 24 ) || ( order & 1 )) {
invGain_Q30 = silk_LPC_inverse_pred_gain_c( A_Q12, order );
}
else {
opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ];
opus_int32 DC_resp;
int16x8_t t0_s16x8, t1_s16x8, t2_s16x8;
int32x4_t t0_s32x4;
const opus_int leftover = order & 7;
/* Increase Q domain of the AR coefficients */
t0_s16x8 = vld1q_s16( A_Q12 + 0 );
t1_s16x8 = vld1q_s16( A_Q12 + 8 );
t2_s16x8 = vld1q_s16( A_Q12 + 16 );
t0_s32x4 = vpaddlq_s16( t0_s16x8 );
switch( order - leftover )
{
case 24:
t0_s32x4 = vpadalq_s16( t0_s32x4, t2_s16x8 );
/* FALLTHROUGH */
case 16:
t0_s32x4 = vpadalq_s16( t0_s32x4, t1_s16x8 );
vst1q_s32( Atmp_QA + 16, vshll_n_s16( vget_low_s16 ( t2_s16x8 ), QA - 12 ) );
vst1q_s32( Atmp_QA + 20, vshll_n_s16( vget_high_s16( t2_s16x8 ), QA - 12 ) );
/* FALLTHROUGH */
case 8:
{
const int32x2_t t_s32x2 = vpadd_s32( vget_low_s32( t0_s32x4 ), vget_high_s32( t0_s32x4 ) );
const int64x1_t t_s64x1 = vpaddl_s32( t_s32x2 );
DC_resp = vget_lane_s32( vreinterpret_s32_s64( t_s64x1 ), 0 );
vst1q_s32( Atmp_QA + 8, vshll_n_s16( vget_low_s16 ( t1_s16x8 ), QA - 12 ) );
vst1q_s32( Atmp_QA + 12, vshll_n_s16( vget_high_s16( t1_s16x8 ), QA - 12 ) );
}
break;
default:
DC_resp = 0;
break;
}
A_Q12 += order - leftover;
switch( leftover )
{
case 6:
DC_resp += (opus_int32)A_Q12[ 5 ];
DC_resp += (opus_int32)A_Q12[ 4 ];
/* FALLTHROUGH */
case 4:
DC_resp += (opus_int32)A_Q12[ 3 ];
DC_resp += (opus_int32)A_Q12[ 2 ];
/* FALLTHROUGH */
case 2:
DC_resp += (opus_int32)A_Q12[ 1 ];
DC_resp += (opus_int32)A_Q12[ 0 ];
/* FALLTHROUGH */
default:
break;
}
/* If the DC is unstable, we don't even need to do the full calculations */
if( DC_resp >= 4096 ) {
invGain_Q30 = 0;
} else {
vst1q_s32( Atmp_QA + 0, vshll_n_s16( vget_low_s16 ( t0_s16x8 ), QA - 12 ) );
vst1q_s32( Atmp_QA + 4, vshll_n_s16( vget_high_s16( t0_s16x8 ), QA - 12 ) );
invGain_Q30 = LPC_inverse_pred_gain_QA_neon( Atmp_QA, order );
}
}
#ifdef OPUS_CHECK_ASM
silk_assert( invGain_Q30_c == invGain_Q30 );
#endif
return invGain_Q30;
}

View file

@ -0,0 +1,100 @@
/***********************************************************************
Copyright (c) 2017 Google Inc.
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.
***********************************************************************/
#ifndef SILK_NSQ_DEL_DEC_ARM_H
#define SILK_NSQ_DEL_DEC_ARM_H
#include "celt/arm/armcpu.h"
#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
void silk_NSQ_del_dec_neon(
const silk_encoder_state *psEncC, silk_nsq_state *NSQ,
SideInfoIndices *psIndices, const opus_int16 x16[], opus_int8 pulses[],
const opus_int16 PredCoef_Q12[2 * MAX_LPC_ORDER],
const opus_int16 LTPCoef_Q14[LTP_ORDER * MAX_NB_SUBFR],
const opus_int16 AR_Q13[MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER],
const opus_int HarmShapeGain_Q14[MAX_NB_SUBFR],
const opus_int Tilt_Q14[MAX_NB_SUBFR],
const opus_int32 LF_shp_Q14[MAX_NB_SUBFR],
const opus_int32 Gains_Q16[MAX_NB_SUBFR],
const opus_int pitchL[MAX_NB_SUBFR], const opus_int Lambda_Q10,
const opus_int LTP_scale_Q14);
#if !defined(OPUS_HAVE_RTCD)
#define OVERRIDE_silk_NSQ_del_dec (1)
#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \
LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \
LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \
LTP_scale_Q14, arch) \
((void)(arch), \
PRESUME_NEON(silk_NSQ_del_dec)( \
psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, \
AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, \
Lambda_Q10, LTP_scale_Q14))
#endif
#endif
#if !defined(OVERRIDE_silk_NSQ_del_dec)
/*Is run-time CPU detection enabled on this platform?*/
#if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \
!defined(OPUS_ARM_PRESUME_NEON_INTR))
extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])(
const silk_encoder_state *psEncC, silk_nsq_state *NSQ,
SideInfoIndices *psIndices, const opus_int16 x16[], opus_int8 pulses[],
const opus_int16 PredCoef_Q12[2 * MAX_LPC_ORDER],
const opus_int16 LTPCoef_Q14[LTP_ORDER * MAX_NB_SUBFR],
const opus_int16 AR_Q13[MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER],
const opus_int HarmShapeGain_Q14[MAX_NB_SUBFR],
const opus_int Tilt_Q14[MAX_NB_SUBFR],
const opus_int32 LF_shp_Q14[MAX_NB_SUBFR],
const opus_int32 Gains_Q16[MAX_NB_SUBFR],
const opus_int pitchL[MAX_NB_SUBFR], const opus_int Lambda_Q10,
const opus_int LTP_scale_Q14);
#define OVERRIDE_silk_NSQ_del_dec (1)
#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \
LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \
LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \
LTP_scale_Q14, arch) \
((*SILK_NSQ_DEL_DEC_IMPL[(arch)&OPUS_ARCHMASK])( \
psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, \
AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, \
Lambda_Q10, LTP_scale_Q14))
#elif defined(OPUS_ARM_PRESUME_NEON_INTR)
#define OVERRIDE_silk_NSQ_del_dec (1)
#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \
LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \
LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \
LTP_scale_Q14, arch) \
((void)(arch), \
silk_NSQ_del_dec_neon(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \
LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \
LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \
LTP_scale_Q14))
#endif
#endif
#endif /* end SILK_NSQ_DEL_DEC_ARM_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,112 @@
/***********************************************************************
Copyright (C) 2014 Vidyo
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 <arm_neon.h>
#include "main.h"
#include "stack_alloc.h"
#include "NSQ.h"
#include "celt/cpu_support.h"
#include "celt/arm/armcpu.h"
opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order)
{
int32x4_t coef0 = vld1q_s32(coef32);
int32x4_t coef1 = vld1q_s32(coef32 + 4);
int32x4_t coef2 = vld1q_s32(coef32 + 8);
int32x4_t coef3 = vld1q_s32(coef32 + 12);
int32x4_t a0 = vld1q_s32(buf32 - 15);
int32x4_t a1 = vld1q_s32(buf32 - 11);
int32x4_t a2 = vld1q_s32(buf32 - 7);
int32x4_t a3 = vld1q_s32(buf32 - 3);
int32x4_t b0 = vqdmulhq_s32(coef0, a0);
int32x4_t b1 = vqdmulhq_s32(coef1, a1);
int32x4_t b2 = vqdmulhq_s32(coef2, a2);
int32x4_t b3 = vqdmulhq_s32(coef3, a3);
int32x4_t c0 = vaddq_s32(b0, b1);
int32x4_t c1 = vaddq_s32(b2, b3);
int32x4_t d = vaddq_s32(c0, c1);
int64x2_t e = vpaddlq_s32(d);
int64x1_t f = vadd_s64(vget_low_s64(e), vget_high_s64(e));
opus_int32 out = vget_lane_s32(vreinterpret_s32_s64(f), 0);
out += silk_RSHIFT( order, 1 );
return out;
}
opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order)
{
opus_int32 out;
if (order == 8)
{
int32x4_t a00 = vdupq_n_s32(data0[0]);
int32x4_t a01 = vld1q_s32(data1); /* data1[0] ... [3] */
int32x4_t a0 = vextq_s32 (a00, a01, 3); /* data0[0] data1[0] ...[2] */
int32x4_t a1 = vld1q_s32(data1 + 3); /* data1[3] ... [6] */
/*TODO: Convert these once in advance instead of once per sample, like
silk_noise_shape_quantizer_short_prediction_neon() does.*/
int16x8_t coef16 = vld1q_s16(coef);
int32x4_t coef0 = vmovl_s16(vget_low_s16(coef16));
int32x4_t coef1 = vmovl_s16(vget_high_s16(coef16));
/*This is not bit-exact with the C version, since we do not drop the
lower 16 bits of each multiply, but wait until the end to truncate
precision. This is an encoder-specific calculation (and unlike
silk_noise_shape_quantizer_short_prediction_neon(), is not meant to
simulate what the decoder will do). We still could use vqdmulhq_s32()
like silk_noise_shape_quantizer_short_prediction_neon() and save
half the multiplies, but the speed difference is not large, since we
then need two extra adds.*/
int64x2_t b0 = vmull_s32(vget_low_s32(a0), vget_low_s32(coef0));
int64x2_t b1 = vmlal_s32(b0, vget_high_s32(a0), vget_high_s32(coef0));
int64x2_t b2 = vmlal_s32(b1, vget_low_s32(a1), vget_low_s32(coef1));
int64x2_t b3 = vmlal_s32(b2, vget_high_s32(a1), vget_high_s32(coef1));
int64x1_t c = vadd_s64(vget_low_s64(b3), vget_high_s64(b3));
int64x1_t cS = vrshr_n_s64(c, 15);
int32x2_t d = vreinterpret_s32_s64(cS);
out = vget_lane_s32(d, 0);
vst1q_s32(data1, a0);
vst1q_s32(data1 + 4, a1);
return out;
}
return silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order);
}

View file

@ -0,0 +1,114 @@
/***********************************************************************
Copyright (C) 2014 Vidyo
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.
***********************************************************************/
#ifndef SILK_NSQ_NEON_H
#define SILK_NSQ_NEON_H
#include "cpu_support.h"
#include "SigProc_FIX.h"
#undef silk_short_prediction_create_arch_coef
/* For vectorized calc, reverse a_Q12 coefs, convert to 32-bit, and shift for vqdmulhq_s32. */
static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon(opus_int32 *out, const opus_int16 *in, opus_int order)
{
out[15] = silk_LSHIFT32(in[0], 15);
out[14] = silk_LSHIFT32(in[1], 15);
out[13] = silk_LSHIFT32(in[2], 15);
out[12] = silk_LSHIFT32(in[3], 15);
out[11] = silk_LSHIFT32(in[4], 15);
out[10] = silk_LSHIFT32(in[5], 15);
out[9] = silk_LSHIFT32(in[6], 15);
out[8] = silk_LSHIFT32(in[7], 15);
out[7] = silk_LSHIFT32(in[8], 15);
out[6] = silk_LSHIFT32(in[9], 15);
if (order == 16)
{
out[5] = silk_LSHIFT32(in[10], 15);
out[4] = silk_LSHIFT32(in[11], 15);
out[3] = silk_LSHIFT32(in[12], 15);
out[2] = silk_LSHIFT32(in[13], 15);
out[1] = silk_LSHIFT32(in[14], 15);
out[0] = silk_LSHIFT32(in[15], 15);
}
else
{
out[5] = 0;
out[4] = 0;
out[3] = 0;
out[2] = 0;
out[1] = 0;
out[0] = 0;
}
}
#if defined(OPUS_ARM_PRESUME_NEON_INTR)
#define silk_short_prediction_create_arch_coef(out, in, order) \
(silk_short_prediction_create_arch_coef_neon(out, in, order))
#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
#define silk_short_prediction_create_arch_coef(out, in, order) \
do { if (arch == OPUS_ARCH_ARM_NEON) { silk_short_prediction_create_arch_coef_neon(out, in, order); } } while (0)
#endif
opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order);
opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order);
#if defined(OPUS_ARM_PRESUME_NEON_INTR)
#undef silk_noise_shape_quantizer_short_prediction
#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \
((void)arch,silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order))
#undef silk_NSQ_noise_shape_feedback_loop
#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_neon(data0, data1, coef, order))
#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
/* silk_noise_shape_quantizer_short_prediction implementations take different parameters based on arch
(coef vs. coefRev) so can't use the usual IMPL table implementation */
#undef silk_noise_shape_quantizer_short_prediction
#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \
(arch == OPUS_ARCH_ARM_NEON ? \
silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order) : \
silk_noise_shape_quantizer_short_prediction_c(in, coef, order))
extern opus_int32
(*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])(
const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef,
opus_int order);
#undef silk_NSQ_noise_shape_feedback_loop
#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) \
(SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[(arch)&OPUS_ARCHMASK](data0, data1, \
coef, order))
#endif
#endif /* SILK_NSQ_NEON_H */

View file

@ -0,0 +1,123 @@
/***********************************************************************
Copyright (C) 2014 Vidyo
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_FIX.h"
#include "NSQ.h"
#include "SigProc_FIX.h"
#if defined(OPUS_HAVE_RTCD)
# if (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \
!defined(OPUS_ARM_PRESUME_NEON_INTR))
void (*const SILK_BIQUAD_ALT_STRIDE2_IMPL[OPUS_ARCHMASK + 1])(
const opus_int16 *in, /* I input signal */
const opus_int32 *B_Q28, /* I MA coefficients [3] */
const opus_int32 *A_Q28, /* I AR coefficients [2] */
opus_int32 *S, /* I/O State vector [4] */
opus_int16 *out, /* O output signal */
const opus_int32 len /* I signal length (must be even) */
) = {
silk_biquad_alt_stride2_c, /* ARMv4 */
silk_biquad_alt_stride2_c, /* EDSP */
silk_biquad_alt_stride2_c, /* Media */
silk_biquad_alt_stride2_neon, /* Neon */
};
opus_int32 (*const SILK_LPC_INVERSE_PRED_GAIN_IMPL[OPUS_ARCHMASK + 1])( /* 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 */
) = {
silk_LPC_inverse_pred_gain_c, /* ARMv4 */
silk_LPC_inverse_pred_gain_c, /* EDSP */
silk_LPC_inverse_pred_gain_c, /* Media */
silk_LPC_inverse_pred_gain_neon, /* Neon */
};
void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])(
const silk_encoder_state *psEncC, /* I Encoder State */
silk_nsq_state *NSQ, /* I/O NSQ state */
SideInfoIndices *psIndices, /* I/O Quantization Indices */
const opus_int16 x16[], /* I Input */
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 */
const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
const opus_int LTP_scale_Q14 /* I LTP state scaling */
) = {
silk_NSQ_del_dec_c, /* ARMv4 */
silk_NSQ_del_dec_c, /* EDSP */
silk_NSQ_del_dec_c, /* Media */
silk_NSQ_del_dec_neon, /* Neon */
};
/*There is no table for silk_noise_shape_quantizer_short_prediction because the
NEON version takes different parameters than the C version.
Instead RTCD is done via if statements at the call sites.
See NSQ_neon.h for details.*/
opus_int32
(*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])(
const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef,
opus_int order) = {
silk_NSQ_noise_shape_feedback_loop_c, /* ARMv4 */
silk_NSQ_noise_shape_feedback_loop_c, /* EDSP */
silk_NSQ_noise_shape_feedback_loop_c, /* Media */
silk_NSQ_noise_shape_feedback_loop_neon, /* NEON */
};
# endif
# if defined(FIXED_POINT) && \
defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)
void (*const SILK_WARPED_AUTOCORRELATION_FIX_IMPL[OPUS_ARCHMASK + 1])(
opus_int32 *corr, /* O Result [order + 1] */
opus_int *scale, /* O Scaling of the correlation vector */
const opus_int16 *input, /* I Input data to correlate */
const opus_int warping_Q16, /* I Warping coefficient */
const opus_int length, /* I Length of input */
const opus_int order /* I Correlation order (even) */
) = {
silk_warped_autocorrelation_FIX_c, /* ARMv4 */
silk_warped_autocorrelation_FIX_c, /* EDSP */
silk_warped_autocorrelation_FIX_c, /* Media */
silk_warped_autocorrelation_FIX_neon, /* Neon */
};
# endif
#endif /* OPUS_HAVE_RTCD */

View file

@ -0,0 +1,68 @@
/***********************************************************************
Copyright (c) 2017 Google Inc.
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.
***********************************************************************/
#ifndef SILK_BIQUAD_ALT_ARM_H
# define SILK_BIQUAD_ALT_ARM_H
# include "celt/arm/armcpu.h"
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
void silk_biquad_alt_stride2_neon(
const opus_int16 *in, /* I input signal */
const opus_int32 *B_Q28, /* I MA coefficients [3] */
const opus_int32 *A_Q28, /* I AR coefficients [2] */
opus_int32 *S, /* I/O State vector [4] */
opus_int16 *out, /* O output signal */
const opus_int32 len /* I signal length (must be even) */
);
# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON)
# define OVERRIDE_silk_biquad_alt_stride2 (1)
# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), PRESUME_NEON(silk_biquad_alt_stride2)(in, B_Q28, A_Q28, S, out, len))
# endif
# endif
# if !defined(OVERRIDE_silk_biquad_alt_stride2)
/*Is run-time CPU detection enabled on this platform?*/
# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
extern void (*const SILK_BIQUAD_ALT_STRIDE2_IMPL[OPUS_ARCHMASK+1])(
const opus_int16 *in, /* I input signal */
const opus_int32 *B_Q28, /* I MA coefficients [3] */
const opus_int32 *A_Q28, /* I AR coefficients [2] */
opus_int32 *S, /* I/O State vector [4] */
opus_int16 *out, /* O output signal */
const opus_int32 len /* I signal length (must be even) */
);
# define OVERRIDE_silk_biquad_alt_stride2 (1)
# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((*SILK_BIQUAD_ALT_STRIDE2_IMPL[(arch)&OPUS_ARCHMASK])(in, B_Q28, A_Q28, S, out, len))
# elif defined(OPUS_ARM_PRESUME_NEON_INTR)
# define OVERRIDE_silk_biquad_alt_stride2 (1)
# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), silk_biquad_alt_stride2_neon(in, B_Q28, A_Q28, S, out, len))
# endif
# endif
#endif /* end SILK_BIQUAD_ALT_ARM_H */

View file

@ -0,0 +1,156 @@
/***********************************************************************
Copyright (c) 2017 Google Inc.
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 <arm_neon.h>
#ifdef OPUS_CHECK_ASM
# include <string.h>
# include "stack_alloc.h"
#endif
#include "SigProc_FIX.h"
static inline void silk_biquad_alt_stride2_kernel( const int32x4_t A_L_s32x4, const int32x4_t A_U_s32x4, const int32x4_t B_Q28_s32x4, const int32x2_t t_s32x2, const int32x4_t in_s32x4, int32x4_t *S_s32x4, int32x2_t *out32_Q14_s32x2 )
{
int32x4_t t_s32x4, out32_Q14_s32x4;
*out32_Q14_s32x2 = vadd_s32( vget_low_s32( *S_s32x4 ), t_s32x2 ); /* silk_SMLAWB( S{0,1}, B_Q28[ 0 ], in{0,1} ) */
*S_s32x4 = vcombine_s32( vget_high_s32( *S_s32x4 ), vdup_n_s32( 0 ) ); /* S{0,1} = S{2,3}; S{2,3} = 0; */
*out32_Q14_s32x2 = vshl_n_s32( *out32_Q14_s32x2, 2 ); /* out32_Q14_{0,1} = silk_LSHIFT( silk_SMLAWB( S{0,1}, B_Q28[ 0 ], in{0,1} ), 2 ); */
out32_Q14_s32x4 = vcombine_s32( *out32_Q14_s32x2, *out32_Q14_s32x2 ); /* out32_Q14_{0,1,0,1} */
t_s32x4 = vqdmulhq_s32( out32_Q14_s32x4, A_L_s32x4 ); /* silk_SMULWB( out32_Q14_{0,1,0,1}, A{0,0,1,1}_L_Q28 ) */
*S_s32x4 = vrsraq_n_s32( *S_s32x4, t_s32x4, 14 ); /* S{0,1} = S{2,3} + silk_RSHIFT_ROUND(); S{2,3} = silk_RSHIFT_ROUND(); */
t_s32x4 = vqdmulhq_s32( out32_Q14_s32x4, A_U_s32x4 ); /* silk_SMULWB( out32_Q14_{0,1,0,1}, A{0,0,1,1}_U_Q28 ) */
*S_s32x4 = vaddq_s32( *S_s32x4, t_s32x4 ); /* S0 = silk_SMLAWB( S{0,1,2,3}, out32_Q14_{0,1,0,1}, A{0,0,1,1}_U_Q28 ); */
t_s32x4 = vqdmulhq_s32( in_s32x4, B_Q28_s32x4 ); /* silk_SMULWB( B_Q28[ {1,1,2,2} ], in{0,1,0,1} ) */
*S_s32x4 = vaddq_s32( *S_s32x4, t_s32x4 ); /* S0 = silk_SMLAWB( S0, B_Q28[ {1,1,2,2} ], in{0,1,0,1} ); */
}
void silk_biquad_alt_stride2_neon(
const opus_int16 *in, /* I input signal */
const opus_int32 *B_Q28, /* I MA coefficients [3] */
const opus_int32 *A_Q28, /* I AR coefficients [2] */
opus_int32 *S, /* I/O State vector [4] */
opus_int16 *out, /* O output signal */
const opus_int32 len /* I signal length (must be even) */
)
{
/* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
opus_int k = 0;
const int32x2_t offset_s32x2 = vdup_n_s32( (1<<14) - 1 );
const int32x4_t offset_s32x4 = vcombine_s32( offset_s32x2, offset_s32x2 );
int16x4_t in_s16x4 = vdup_n_s16( 0 );
int16x4_t out_s16x4;
int32x2_t A_Q28_s32x2, A_L_s32x2, A_U_s32x2, B_Q28_s32x2, t_s32x2;
int32x4_t A_L_s32x4, A_U_s32x4, B_Q28_s32x4, S_s32x4, out32_Q14_s32x4;
int32x2x2_t t0_s32x2x2, t1_s32x2x2, t2_s32x2x2, S_s32x2x2;
#ifdef OPUS_CHECK_ASM
opus_int32 S_c[ 4 ];
VARDECL( opus_int16, out_c );
SAVE_STACK;
ALLOC( out_c, 2 * len, opus_int16 );
silk_memcpy( &S_c, S, sizeof( S_c ) );
silk_biquad_alt_stride2_c( in, B_Q28, A_Q28, S_c, out_c, len );
#endif
/* Negate A_Q28 values and split in two parts */
A_Q28_s32x2 = vld1_s32( A_Q28 );
A_Q28_s32x2 = vneg_s32( A_Q28_s32x2 );
A_L_s32x2 = vshl_n_s32( A_Q28_s32x2, 18 ); /* ( -A_Q28[] & 0x00003FFF ) << 18 */
A_L_s32x2 = vreinterpret_s32_u32( vshr_n_u32( vreinterpret_u32_s32( A_L_s32x2 ), 3 ) ); /* ( -A_Q28[] & 0x00003FFF ) << 15 */
A_U_s32x2 = vshr_n_s32( A_Q28_s32x2, 14 ); /* silk_RSHIFT( -A_Q28[], 14 ) */
A_U_s32x2 = vshl_n_s32( A_U_s32x2, 16 ); /* silk_RSHIFT( -A_Q28[], 14 ) << 16 (Clip two leading bits to conform to C function.) */
A_U_s32x2 = vshr_n_s32( A_U_s32x2, 1 ); /* silk_RSHIFT( -A_Q28[], 14 ) << 15 */
B_Q28_s32x2 = vld1_s32( B_Q28 );
t_s32x2 = vld1_s32( B_Q28 + 1 );
t0_s32x2x2 = vzip_s32( A_L_s32x2, A_L_s32x2 );
t1_s32x2x2 = vzip_s32( A_U_s32x2, A_U_s32x2 );
t2_s32x2x2 = vzip_s32( t_s32x2, t_s32x2 );
A_L_s32x4 = vcombine_s32( t0_s32x2x2.val[ 0 ], t0_s32x2x2.val[ 1 ] ); /* A{0,0,1,1}_L_Q28 */
A_U_s32x4 = vcombine_s32( t1_s32x2x2.val[ 0 ], t1_s32x2x2.val[ 1 ] ); /* A{0,0,1,1}_U_Q28 */
B_Q28_s32x4 = vcombine_s32( t2_s32x2x2.val[ 0 ], t2_s32x2x2.val[ 1 ] ); /* B_Q28[ {1,1,2,2} ] */
S_s32x4 = vld1q_s32( S ); /* S0 = S[ 0 ]; S3 = S[ 3 ]; */
S_s32x2x2 = vtrn_s32( vget_low_s32( S_s32x4 ), vget_high_s32( S_s32x4 ) ); /* S2 = S[ 1 ]; S1 = S[ 2 ]; */
S_s32x4 = vcombine_s32( S_s32x2x2.val[ 0 ], S_s32x2x2.val[ 1 ] );
for( ; k < len - 1; k += 2 ) {
int32x4_t in_s32x4[ 2 ], t_s32x4;
int32x2_t out32_Q14_s32x2[ 2 ];
/* S[ 2 * i + 0 ], S[ 2 * i + 1 ], S[ 2 * i + 2 ], S[ 2 * i + 3 ]: Q12 */
in_s16x4 = vld1_s16( &in[ 2 * k ] ); /* in{0,1,2,3} = in[ 2 * k + {0,1,2,3} ]; */
in_s32x4[ 0 ] = vshll_n_s16( in_s16x4, 15 ); /* in{0,1,2,3} << 15 */
t_s32x4 = vqdmulhq_lane_s32( in_s32x4[ 0 ], B_Q28_s32x2, 0 ); /* silk_SMULWB( B_Q28[ 0 ], in{0,1,2,3} ) */
in_s32x4[ 1 ] = vcombine_s32( vget_high_s32( in_s32x4[ 0 ] ), vget_high_s32( in_s32x4[ 0 ] ) ); /* in{2,3,2,3} << 15 */
in_s32x4[ 0 ] = vcombine_s32( vget_low_s32 ( in_s32x4[ 0 ] ), vget_low_s32 ( in_s32x4[ 0 ] ) ); /* in{0,1,0,1} << 15 */
silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, vget_low_s32 ( t_s32x4 ), in_s32x4[ 0 ], &S_s32x4, &out32_Q14_s32x2[ 0 ] );
silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, vget_high_s32( t_s32x4 ), in_s32x4[ 1 ], &S_s32x4, &out32_Q14_s32x2[ 1 ] );
/* Scale back to Q0 and saturate */
out32_Q14_s32x4 = vcombine_s32( out32_Q14_s32x2[ 0 ], out32_Q14_s32x2[ 1 ] ); /* out32_Q14_{0,1,2,3} */
out32_Q14_s32x4 = vaddq_s32( out32_Q14_s32x4, offset_s32x4 ); /* out32_Q14_{0,1,2,3} + (1<<14) - 1 */
out_s16x4 = vqshrn_n_s32( out32_Q14_s32x4, 14 ); /* (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,2,3} + (1<<14) - 1, 14 ) ) */
vst1_s16( &out[ 2 * k ], out_s16x4 ); /* out[ 2 * k + {0,1,2,3} ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,2,3} + (1<<14) - 1, 14 ) ); */
}
/* Process leftover. */
if( k < len ) {
int32x4_t in_s32x4;
int32x2_t out32_Q14_s32x2;
/* S[ 2 * i + 0 ], S[ 2 * i + 1 ]: Q12 */
in_s16x4 = vld1_lane_s16( &in[ 2 * k + 0 ], in_s16x4, 0 ); /* in{0,1} = in[ 2 * k + {0,1} ]; */
in_s16x4 = vld1_lane_s16( &in[ 2 * k + 1 ], in_s16x4, 1 ); /* in{0,1} = in[ 2 * k + {0,1} ]; */
in_s32x4 = vshll_n_s16( in_s16x4, 15 ); /* in{0,1} << 15 */
t_s32x2 = vqdmulh_lane_s32( vget_low_s32( in_s32x4 ), B_Q28_s32x2, 0 ); /* silk_SMULWB( B_Q28[ 0 ], in{0,1} ) */
in_s32x4 = vcombine_s32( vget_low_s32( in_s32x4 ), vget_low_s32( in_s32x4 ) ); /* in{0,1,0,1} << 15 */
silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, t_s32x2, in_s32x4, &S_s32x4, &out32_Q14_s32x2 );
/* Scale back to Q0 and saturate */
out32_Q14_s32x2 = vadd_s32( out32_Q14_s32x2, offset_s32x2 ); /* out32_Q14_{0,1} + (1<<14) - 1 */
out32_Q14_s32x4 = vcombine_s32( out32_Q14_s32x2, out32_Q14_s32x2 ); /* out32_Q14_{0,1,0,1} + (1<<14) - 1 */
out_s16x4 = vqshrn_n_s32( out32_Q14_s32x4, 14 ); /* (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,0,1} + (1<<14) - 1, 14 ) ) */
vst1_lane_s16( &out[ 2 * k + 0 ], out_s16x4, 0 ); /* out[ 2 * k + 0 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_0 + (1<<14) - 1, 14 ) ); */
vst1_lane_s16( &out[ 2 * k + 1 ], out_s16x4, 1 ); /* out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_1 + (1<<14) - 1, 14 ) ); */
}
vst1q_lane_s32( &S[ 0 ], S_s32x4, 0 ); /* S[ 0 ] = S0; */
vst1q_lane_s32( &S[ 1 ], S_s32x4, 2 ); /* S[ 1 ] = S2; */
vst1q_lane_s32( &S[ 2 ], S_s32x4, 1 ); /* S[ 2 ] = S1; */
vst1q_lane_s32( &S[ 3 ], S_s32x4, 3 ); /* S[ 3 ] = S3; */
#ifdef OPUS_CHECK_ASM
silk_assert( !memcmp( S_c, S, sizeof( S_c ) ) );
silk_assert( !memcmp( out_c, out, 2 * len * sizeof( opus_int16 ) ) );
RESTORE_STACK;
#endif
}

View file

@ -0,0 +1,39 @@
/***********************************************************************
Copyright (C) 2015 Vidyo
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.
***********************************************************************/
#ifndef SILK_MACROS_ARM64_H
#define SILK_MACROS_ARM64_H
#include <arm_neon.h>
#undef silk_ADD_SAT32
#define silk_ADD_SAT32(a, b) (vqadds_s32((a), (b)))
#undef silk_SUB_SAT32
#define silk_SUB_SAT32(a, b) (vqsubs_s32((a), (b)))
#endif /* SILK_MACROS_ARM64_H */

View file

@ -28,6 +28,11 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef SILK_MACROS_ARMv4_H
#define SILK_MACROS_ARMv4_H
/* This macro only avoids the undefined behaviour from a left shift of
a negative value. It should only be used in macros that can't include
SigProc_FIX.h. In other cases, use silk_LSHIFT32(). */
#define SAFE_SHL(a,b) ((opus_int32)((opus_uint32)(a) << (b)))
/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
#undef silk_SMULWB
static OPUS_INLINE opus_int32 silk_SMULWB_armv4(opus_int32 a, opus_int16 b)
@ -38,7 +43,7 @@ static OPUS_INLINE opus_int32 silk_SMULWB_armv4(opus_int32 a, opus_int16 b)
"#silk_SMULWB\n\t"
"smull %0, %1, %2, %3\n\t"
: "=&r"(rd_lo), "=&r"(rd_hi)
: "%r"(a), "r"(b<<16)
: "%r"(a), "r"(SAFE_SHL(b,16))
);
return rd_hi;
}
@ -80,7 +85,7 @@ static OPUS_INLINE opus_int32 silk_SMULWW_armv4(opus_int32 a, opus_int32 b)
: "=&r"(rd_lo), "=&r"(rd_hi)
: "%r"(a), "r"(b)
);
return (rd_hi<<16)+(rd_lo>>16);
return SAFE_SHL(rd_hi,16)+(rd_lo>>16);
}
#define silk_SMULWW(a, b) (silk_SMULWW_armv4(a, b))
@ -96,8 +101,10 @@ static OPUS_INLINE opus_int32 silk_SMLAWW_armv4(opus_int32 a, opus_int32 b,
: "=&r"(rd_lo), "=&r"(rd_hi)
: "%r"(b), "r"(c)
);
return a+(rd_hi<<16)+(rd_lo>>16);
return a+SAFE_SHL(rd_hi,16)+(rd_lo>>16);
}
#define silk_SMLAWW(a, b, c) (silk_SMLAWW_armv4(a, b, c))
#undef SAFE_SHL
#endif /* SILK_MACROS_ARMv4_H */

View file

@ -29,6 +29,11 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef SILK_MACROS_ARMv5E_H
#define SILK_MACROS_ARMv5E_H
/* This macro only avoids the undefined behaviour from a left shift of
a negative value. It should only be used in macros that can't include
SigProc_FIX.h. In other cases, use silk_LSHIFT32(). */
#define SAFE_SHL(a,b) ((opus_int32)((opus_uint32)(a) << (b)))
/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
#undef silk_SMULWB
static OPUS_INLINE opus_int32 silk_SMULWB_armv5e(opus_int32 a, opus_int16 b)
@ -190,7 +195,7 @@ static OPUS_INLINE opus_int32 silk_CLZ16_armv5(opus_int16 in16)
"#silk_CLZ16\n\t"
"clz %0, %1;\n"
: "=r"(res)
: "r"(in16<<16|0x8000)
: "r"(SAFE_SHL(in16,16)|0x8000)
);
return res;
}
@ -210,4 +215,6 @@ static OPUS_INLINE opus_int32 silk_CLZ32_armv5(opus_int32 in32)
}
#define silk_CLZ32(in32) (silk_CLZ32_armv5(in32))
#undef SAFE_SHL
#endif /* SILK_MACROS_ARMv5E_H */

View file

@ -0,0 +1,121 @@
/***********************************************************************
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.
***********************************************************************/
/* *
* silk_biquad_alt.c *
* *
* Second order ARMA filter *
* Can handle slowly varying filter coefficients *
* */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "SigProc_FIX.h"
/* Second order ARMA filter, alternative implementation */
void silk_biquad_alt_stride1(
const opus_int16 *in, /* I input signal */
const opus_int32 *B_Q28, /* I MA coefficients [3] */
const opus_int32 *A_Q28, /* I AR coefficients [2] */
opus_int32 *S, /* I/O State vector [2] */
opus_int16 *out, /* O output signal */
const opus_int32 len /* I signal length (must be even) */
)
{
/* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
opus_int k;
opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
/* Negate A_Q28 values and split in two parts */
A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */
A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */
A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */
A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */
for( k = 0; k < len; k++ ) {
/* S[ 0 ], S[ 1 ]: Q12 */
inval = in[ k ];
out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 );
S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 );
S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 );
S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval);
S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 );
S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 );
S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval );
/* Scale back to Q0 and saturate */
out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) );
}
}
void silk_biquad_alt_stride2_c(
const opus_int16 *in, /* I input signal */
const opus_int32 *B_Q28, /* I MA coefficients [3] */
const opus_int32 *A_Q28, /* I AR coefficients [2] */
opus_int32 *S, /* I/O State vector [4] */
opus_int16 *out, /* O output signal */
const opus_int32 len /* I signal length (must be even) */
)
{
/* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
opus_int k;
opus_int32 A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14[ 2 ];
/* Negate A_Q28 values and split in two parts */
A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */
A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */
A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */
A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */
for( k = 0; k < len; k++ ) {
/* S[ 0 ], S[ 1 ], S[ 2 ], S[ 3 ]: Q12 */
out32_Q14[ 0 ] = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], in[ 2 * k + 0 ] ), 2 );
out32_Q14[ 1 ] = silk_LSHIFT( silk_SMLAWB( S[ 2 ], B_Q28[ 0 ], in[ 2 * k + 1 ] ), 2 );
S[ 0 ] = S[ 1 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A0_L_Q28 ), 14 );
S[ 2 ] = S[ 3 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A0_L_Q28 ), 14 );
S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14[ 0 ], A0_U_Q28 );
S[ 2 ] = silk_SMLAWB( S[ 2 ], out32_Q14[ 1 ], A0_U_Q28 );
S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], in[ 2 * k + 0 ] );
S[ 2 ] = silk_SMLAWB( S[ 2 ], B_Q28[ 1 ], in[ 2 * k + 1 ] );
S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A1_L_Q28 ), 14 );
S[ 3 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A1_L_Q28 ), 14 );
S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14[ 0 ], A1_U_Q28 );
S[ 3 ] = silk_SMLAWB( S[ 3 ], out32_Q14[ 1 ], A1_U_Q28 );
S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], in[ 2 * k + 0 ] );
S[ 3 ] = silk_SMLAWB( S[ 3 ], B_Q28[ 2 ], in[ 2 * k + 1 ] );
/* Scale back to Q0 and saturate */
out[ 2 * k + 0 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 0 ] + (1<<14) - 1, 14 ) );
out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 1 ] + (1<<14) - 1, 14 ) );
}
}

View file

@ -45,7 +45,7 @@ void silk_bwexpander(
/* Bias in silk_SMULWB can lead to unstable filters */
for( i = 0; i < d - 1; i++ ) {
ar[ i ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ] ), 16 );
chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 );
chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 );
}
ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 );
}

View file

@ -0,0 +1,106 @@
/***********************************************************************
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 "control.h"
#include "errors.h"
/* Check encoder control struct */
opus_int check_control_input(
silk_EncControlStruct *encControl /* I Control structure */
)
{
celt_assert( encControl != NULL );
if( ( ( encControl->API_sampleRate != 8000 ) &&
( encControl->API_sampleRate != 12000 ) &&
( encControl->API_sampleRate != 16000 ) &&
( encControl->API_sampleRate != 24000 ) &&
( encControl->API_sampleRate != 32000 ) &&
( encControl->API_sampleRate != 44100 ) &&
( encControl->API_sampleRate != 48000 ) ) ||
( ( encControl->desiredInternalSampleRate != 8000 ) &&
( encControl->desiredInternalSampleRate != 12000 ) &&
( encControl->desiredInternalSampleRate != 16000 ) ) ||
( ( encControl->maxInternalSampleRate != 8000 ) &&
( encControl->maxInternalSampleRate != 12000 ) &&
( encControl->maxInternalSampleRate != 16000 ) ) ||
( ( encControl->minInternalSampleRate != 8000 ) &&
( encControl->minInternalSampleRate != 12000 ) &&
( encControl->minInternalSampleRate != 16000 ) ) ||
( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) ||
( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) ||
( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) {
celt_assert( 0 );
return SILK_ENC_FS_NOT_SUPPORTED;
}
if( encControl->payloadSize_ms != 10 &&
encControl->payloadSize_ms != 20 &&
encControl->payloadSize_ms != 40 &&
encControl->payloadSize_ms != 60 ) {
celt_assert( 0 );
return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
}
if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) {
celt_assert( 0 );
return SILK_ENC_INVALID_LOSS_RATE;
}
if( encControl->useDTX < 0 || encControl->useDTX > 1 ) {
celt_assert( 0 );
return SILK_ENC_INVALID_DTX_SETTING;
}
if( encControl->useCBR < 0 || encControl->useCBR > 1 ) {
celt_assert( 0 );
return SILK_ENC_INVALID_CBR_SETTING;
}
if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) {
celt_assert( 0 );
return SILK_ENC_INVALID_INBAND_FEC_SETTING;
}
if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) {
celt_assert( 0 );
return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
}
if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) {
celt_assert( 0 );
return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
}
if( encControl->nChannelsInternal > encControl->nChannelsAPI ) {
celt_assert( 0 );
return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
}
if( encControl->complexity < 0 || encControl->complexity > 10 ) {
celt_assert( 0 );
return SILK_ENC_INVALID_COMPLEXITY_SETTING;
}
return SILK_NO_ERROR;
}

View file

@ -37,7 +37,6 @@ POSSIBILITY OF SUCH DAMAGE.
#define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 )
#define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 )
#if 0
/* Encodes signs of excitation */
void silk_encode_signs(
ec_enc *psRangeEnc, /* I/O Compressor data structure */
@ -71,7 +70,6 @@ void silk_encode_signs(
q_ptr += SHELL_CODEC_FRAME_LENGTH;
}
}
#endif
/* Decodes signs of excitation */
void silk_decode_signs(

View file

@ -77,6 +77,9 @@ typedef struct {
/* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */
opus_int useInBandFEC;
/* I: Flag to actually code in-band Forward Error Correction (FEC) in the current packet; 0/1 */
opus_int LBRR_coded;
/* I: Flag to enable discontinuous transmission (DTX); 0/1 */
opus_int useDTX;
@ -110,6 +113,11 @@ typedef struct {
/* O: Tells the Opus encoder we're ready to switch */
opus_int switchReady;
/* O: SILK Signal type */
opus_int signalType;
/* O: SILK offset (dithering) */
opus_int offset;
} silk_EncControlStruct;
/**************************************************************************/

View file

@ -0,0 +1,113 @@
/***********************************************************************
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"
/* These tables hold SNR values divided by 21 (so they fit in 8 bits)
for different target bitrates spaced at 400 bps interval. The first
10 values are omitted (0-4 kb/s) because they're all zeros.
These tables were obtained by running different SNRs through the
encoder and measuring the active bitrate. */
static const unsigned char silk_TargetRate_NB_21[117 - 10] = {
0, 15, 39, 52, 61, 68,
74, 79, 84, 88, 92, 95, 99,102,105,108,111,114,117,119,122,124,
126,129,131,133,135,137,139,142,143,145,147,149,151,153,155,157,
158,160,162,163,165,167,168,170,171,173,174,176,177,179,180,182,
183,185,186,187,189,190,192,193,194,196,197,199,200,201,203,204,
205,207,208,209,211,212,213,215,216,217,219,220,221,223,224,225,
227,228,230,231,232,234,235,236,238,239,241,242,243,245,246,248,
249,250,252,253,255
};
static const unsigned char silk_TargetRate_MB_21[165 - 10] = {
0, 0, 28, 43, 52, 59,
65, 70, 74, 78, 81, 85, 87, 90, 93, 95, 98,100,102,105,107,109,
111,113,115,116,118,120,122,123,125,127,128,130,131,133,134,136,
137,138,140,141,143,144,145,147,148,149,151,152,153,154,156,157,
158,159,160,162,163,164,165,166,167,168,169,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,188,189,190,
191,192,193,194,195,196,197,198,199,200,201,202,203,203,204,205,
206,207,208,209,210,211,212,213,214,214,215,216,217,218,219,220,
221,222,223,224,224,225,226,227,228,229,230,231,232,233,234,235,
236,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,
251,252,253,254,255
};
static const unsigned char silk_TargetRate_WB_21[201 - 10] = {
0, 0, 0, 8, 29, 41,
49, 56, 62, 66, 70, 74, 77, 80, 83, 86, 88, 91, 93, 95, 97, 99,
101,103,105,107,108,110,112,113,115,116,118,119,121,122,123,125,
126,127,129,130,131,132,134,135,136,137,138,140,141,142,143,144,
145,146,147,148,149,150,151,152,153,154,156,157,158,159,159,160,
161,162,163,164,165,166,167,168,169,170,171,171,172,173,174,175,
176,177,177,178,179,180,181,181,182,183,184,185,185,186,187,188,
189,189,190,191,192,192,193,194,195,195,196,197,198,198,199,200,
200,201,202,203,203,204,205,206,206,207,208,209,209,210,211,211,
212,213,214,214,215,216,216,217,218,219,219,220,221,221,222,223,
224,224,225,226,226,227,228,229,229,230,231,232,232,233,234,234,
235,236,237,237,238,239,240,240,241,242,243,243,244,245,246,246,
247,248,249,249,250,251,252,253,255
};
/* Control SNR of redidual quantizer */
opus_int silk_control_SNR(
silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
opus_int32 TargetRate_bps /* I Target max bitrate (bps) */
)
{
int id;
int bound;
const unsigned char *snr_table;
psEncC->TargetRate_bps = TargetRate_bps;
if( psEncC->nb_subfr == 2 ) {
TargetRate_bps -= 2000 + psEncC->fs_kHz/16;
}
if( psEncC->fs_kHz == 8 ) {
bound = sizeof(silk_TargetRate_NB_21);
snr_table = silk_TargetRate_NB_21;
} else if( psEncC->fs_kHz == 12 ) {
bound = sizeof(silk_TargetRate_MB_21);
snr_table = silk_TargetRate_MB_21;
} else {
bound = sizeof(silk_TargetRate_WB_21);
snr_table = silk_TargetRate_WB_21;
}
id = (TargetRate_bps+200)/400;
id = silk_min(id - 10, bound-1);
if( id <= 0 ) {
psEncC->SNR_dB_Q7 = 0;
} else {
psEncC->SNR_dB_Q7 = snr_table[id]*21;
}
return SILK_NO_ERROR;
}

View file

@ -0,0 +1,132 @@
/***********************************************************************
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"
/* Control internal sampling rate */
opus_int silk_control_audio_bandwidth(
silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
silk_EncControlStruct *encControl /* I Control structure */
)
{
opus_int fs_kHz;
opus_int orig_kHz;
opus_int32 fs_Hz;
orig_kHz = psEncC->fs_kHz;
/* Handle a bandwidth-switching reset where we need to be aware what the last sampling rate was. */
if( orig_kHz == 0 ) {
orig_kHz = psEncC->sLP.saved_fs_kHz;
}
fs_kHz = orig_kHz;
fs_Hz = silk_SMULBB( fs_kHz, 1000 );
if( fs_Hz == 0 ) {
/* Encoder has just been initialized */
fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz );
fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
} else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) {
/* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */
fs_Hz = psEncC->API_fs_Hz;
fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz );
fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz );
fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
} else {
/* State machine for the internal sampling rate switching */
if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) {
/* Stop transition phase */
psEncC->sLP.mode = 0;
}
if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) {
/* Check if we should switch down */
if( silk_SMULBB( orig_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz )
{
/* Switch down */
if( psEncC->sLP.mode == 0 ) {
/* New transition */
psEncC->sLP.transition_frame_no = TRANSITION_FRAMES;
/* Reset transition filter state */
silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
}
if( encControl->opusCanSwitch ) {
/* Stop transition phase */
psEncC->sLP.mode = 0;
/* Switch to a lower sample frequency */
fs_kHz = orig_kHz == 16 ? 12 : 8;
} else {
if( psEncC->sLP.transition_frame_no <= 0 ) {
encControl->switchReady = 1;
/* Make room for redundancy */
encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
} else {
/* Direction: down (at double speed) */
psEncC->sLP.mode = -2;
}
}
}
else
/* Check if we should switch up */
if( silk_SMULBB( orig_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz )
{
/* Switch up */
if( encControl->opusCanSwitch ) {
/* Switch to a higher sample frequency */
fs_kHz = orig_kHz == 8 ? 12 : 16;
/* New transition */
psEncC->sLP.transition_frame_no = 0;
/* Reset transition filter state */
silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
/* Direction: up */
psEncC->sLP.mode = 1;
} else {
if( psEncC->sLP.mode == 0 ) {
encControl->switchReady = 1;
/* Make room for redundancy */
encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
} else {
/* Direction: up */
psEncC->sLP.mode = 1;
}
}
} else {
if (psEncC->sLP.mode<0)
psEncC->sLP.mode = 1;
}
}
}
return fs_kHz;
}

View file

@ -0,0 +1,423 @@
/***********************************************************************
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
#ifdef FIXED_POINT
#include "main_FIX.h"
#define silk_encoder_state_Fxx silk_encoder_state_FIX
#else
#include "main_FLP.h"
#define silk_encoder_state_Fxx silk_encoder_state_FLP
#endif
#include "stack_alloc.h"
#include "tuning_parameters.h"
#include "pitch_est_defines.h"
static opus_int silk_setup_resamplers(
silk_encoder_state_Fxx *psEnc, /* I/O */
opus_int fs_kHz /* I */
);
static opus_int silk_setup_fs(
silk_encoder_state_Fxx *psEnc, /* I/O */
opus_int fs_kHz, /* I */
opus_int PacketSize_ms /* I */
);
static opus_int silk_setup_complexity(
silk_encoder_state *psEncC, /* I/O */
opus_int Complexity /* I */
);
static OPUS_INLINE opus_int silk_setup_LBRR(
silk_encoder_state *psEncC, /* I/O */
const silk_EncControlStruct *encControl /* I */
);
/* Control encoder */
opus_int silk_control_encoder(
silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
silk_EncControlStruct *encControl, /* I Control structure */
const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
const opus_int channelNb, /* I Channel number */
const opus_int force_fs_kHz
)
{
opus_int fs_kHz, ret = 0;
psEnc->sCmn.useDTX = encControl->useDTX;
psEnc->sCmn.useCBR = encControl->useCBR;
psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate;
psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate;
psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate;
psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate;
psEnc->sCmn.useInBandFEC = encControl->useInBandFEC;
psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI;
psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal;
psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch;
psEnc->sCmn.channelNb = channelNb;
if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) {
if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) {
/* Change in API sampling rate in the middle of encoding a packet */
ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz );
}
return ret;
}
/* Beyond this point we know that there are no previously coded frames in the payload buffer */
/********************************************/
/* Determine internal sampling rate */
/********************************************/
fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl );
if( force_fs_kHz ) {
fs_kHz = force_fs_kHz;
}
/********************************************/
/* Prepare resampler and buffered data */
/********************************************/
ret += silk_setup_resamplers( psEnc, fs_kHz );
/********************************************/
/* Set internal sampling frequency */
/********************************************/
ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms );
/********************************************/
/* Set encoding complexity */
/********************************************/
ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity );
/********************************************/
/* Set packet loss rate measured by farend */
/********************************************/
psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage;
/********************************************/
/* Set LBRR usage */
/********************************************/
ret += silk_setup_LBRR( &psEnc->sCmn, encControl );
psEnc->sCmn.controlled_since_last_payload = 1;
return ret;
}
static opus_int silk_setup_resamplers(
silk_encoder_state_Fxx *psEnc, /* I/O */
opus_int fs_kHz /* I */
)
{
opus_int ret = SILK_NO_ERROR;
SAVE_STACK;
if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz )
{
if( psEnc->sCmn.fs_kHz == 0 ) {
/* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 );
} else {
VARDECL( opus_int16, x_buf_API_fs_Hz );
VARDECL( silk_resampler_state_struct, temp_resampler_state );
#ifdef FIXED_POINT
opus_int16 *x_bufFIX = psEnc->x_buf;
#else
VARDECL( opus_int16, x_bufFIX );
opus_int32 new_buf_samples;
#endif
opus_int32 api_buf_samples;
opus_int32 old_buf_samples;
opus_int32 buf_length_ms;
buf_length_ms = silk_LSHIFT( psEnc->sCmn.nb_subfr * 5, 1 ) + LA_SHAPE_MS;
old_buf_samples = buf_length_ms * psEnc->sCmn.fs_kHz;
#ifndef FIXED_POINT
new_buf_samples = buf_length_ms * fs_kHz;
ALLOC( x_bufFIX, silk_max( old_buf_samples, new_buf_samples ),
opus_int16 );
silk_float2short_array( x_bufFIX, psEnc->x_buf, old_buf_samples );
#endif
/* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */
ALLOC( temp_resampler_state, 1, silk_resampler_state_struct );
ret += silk_resampler_init( temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 );
/* Calculate number of samples to temporarily upsample */
api_buf_samples = buf_length_ms * silk_DIV32_16( psEnc->sCmn.API_fs_Hz, 1000 );
/* Temporary resampling of x_buf data to API_fs_Hz */
ALLOC( x_buf_API_fs_Hz, api_buf_samples, opus_int16 );
ret += silk_resampler( temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, old_buf_samples );
/* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 );
/* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */
ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, api_buf_samples );
#ifndef FIXED_POINT
silk_short2float_array( psEnc->x_buf, x_bufFIX, new_buf_samples);
#endif
}
}
psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz;
RESTORE_STACK;
return ret;
}
static opus_int silk_setup_fs(
silk_encoder_state_Fxx *psEnc, /* I/O */
opus_int fs_kHz, /* I */
opus_int PacketSize_ms /* I */
)
{
opus_int ret = SILK_NO_ERROR;
/* Set packet size */
if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) {
if( ( PacketSize_ms != 10 ) &&
( PacketSize_ms != 20 ) &&
( PacketSize_ms != 40 ) &&
( PacketSize_ms != 60 ) ) {
ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
}
if( PacketSize_ms <= 10 ) {
psEnc->sCmn.nFramesPerPacket = 1;
psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1;
psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz );
psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
if( psEnc->sCmn.fs_kHz == 8 ) {
psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
} else {
psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
}
} else {
psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS );
psEnc->sCmn.nb_subfr = MAX_NB_SUBFR;
psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz );
psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
if( psEnc->sCmn.fs_kHz == 8 ) {
psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
} else {
psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
}
}
psEnc->sCmn.PacketSize_ms = PacketSize_ms;
psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */
}
/* Set internal sampling frequency */
celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
celt_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 );
if( psEnc->sCmn.fs_kHz != fs_kHz ) {
/* reset part of the state */
silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) );
silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) );
silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) );
psEnc->sCmn.inputBufIx = 0;
psEnc->sCmn.nFramesEncoded = 0;
psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */
/* Initialize non-zero parameters */
psEnc->sCmn.prevLag = 100;
psEnc->sCmn.first_frame_after_reset = 1;
psEnc->sShape.LastGainIndex = 10;
psEnc->sCmn.sNSQ.lagPrev = 100;
psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536;
psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY;
psEnc->sCmn.fs_kHz = fs_kHz;
if( psEnc->sCmn.fs_kHz == 8 ) {
if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
} else {
psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
}
} else {
if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
} else {
psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
}
}
if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) {
psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER;
psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB;
} else {
psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER;
psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB;
}
psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz;
psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr );
psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz );
psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz );
psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz );
if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
} else {
psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
}
if( psEnc->sCmn.fs_kHz == 16 ) {
psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF;
} else if( psEnc->sCmn.fs_kHz == 12 ) {
psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF;
} else {
psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF;
}
}
/* Check that settings are valid */
celt_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length );
return ret;
}
static opus_int silk_setup_complexity(
silk_encoder_state *psEncC, /* I/O */
opus_int Complexity /* I */
)
{
opus_int ret = 0;
/* Set encoding complexity */
celt_assert( Complexity >= 0 && Complexity <= 10 );
if( Complexity < 1 ) {
psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX;
psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 );
psEncC->pitchEstimationLPCOrder = 6;
psEncC->shapingLPCOrder = 12;
psEncC->la_shape = 3 * psEncC->fs_kHz;
psEncC->nStatesDelayedDecision = 1;
psEncC->useInterpolatedNLSFs = 0;
psEncC->NLSF_MSVQ_Survivors = 2;
psEncC->warping_Q16 = 0;
} else if( Complexity < 2 ) {
psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 );
psEncC->pitchEstimationLPCOrder = 8;
psEncC->shapingLPCOrder = 14;
psEncC->la_shape = 5 * psEncC->fs_kHz;
psEncC->nStatesDelayedDecision = 1;
psEncC->useInterpolatedNLSFs = 0;
psEncC->NLSF_MSVQ_Survivors = 3;
psEncC->warping_Q16 = 0;
} else if( Complexity < 3 ) {
psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX;
psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 );
psEncC->pitchEstimationLPCOrder = 6;
psEncC->shapingLPCOrder = 12;
psEncC->la_shape = 3 * psEncC->fs_kHz;
psEncC->nStatesDelayedDecision = 2;
psEncC->useInterpolatedNLSFs = 0;
psEncC->NLSF_MSVQ_Survivors = 2;
psEncC->warping_Q16 = 0;
} else if( Complexity < 4 ) {
psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 );
psEncC->pitchEstimationLPCOrder = 8;
psEncC->shapingLPCOrder = 14;
psEncC->la_shape = 5 * psEncC->fs_kHz;
psEncC->nStatesDelayedDecision = 2;
psEncC->useInterpolatedNLSFs = 0;
psEncC->NLSF_MSVQ_Survivors = 4;
psEncC->warping_Q16 = 0;
} else if( Complexity < 6 ) {
psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 );
psEncC->pitchEstimationLPCOrder = 10;
psEncC->shapingLPCOrder = 16;
psEncC->la_shape = 5 * psEncC->fs_kHz;
psEncC->nStatesDelayedDecision = 2;
psEncC->useInterpolatedNLSFs = 1;
psEncC->NLSF_MSVQ_Survivors = 6;
psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
} else if( Complexity < 8 ) {
psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 );
psEncC->pitchEstimationLPCOrder = 12;
psEncC->shapingLPCOrder = 20;
psEncC->la_shape = 5 * psEncC->fs_kHz;
psEncC->nStatesDelayedDecision = 3;
psEncC->useInterpolatedNLSFs = 1;
psEncC->NLSF_MSVQ_Survivors = 8;
psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
} else {
psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX;
psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 16 );
psEncC->pitchEstimationLPCOrder = 16;
psEncC->shapingLPCOrder = 24;
psEncC->la_shape = 5 * psEncC->fs_kHz;
psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES;
psEncC->useInterpolatedNLSFs = 1;
psEncC->NLSF_MSVQ_Survivors = 16;
psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
}
/* Do not allow higher pitch estimation LPC order than predict LPC order */
psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder );
psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape;
psEncC->Complexity = Complexity;
celt_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER );
celt_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER );
celt_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES );
celt_assert( psEncC->warping_Q16 <= 32767 );
celt_assert( psEncC->la_shape <= LA_SHAPE_MAX );
celt_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX );
return ret;
}
static OPUS_INLINE opus_int silk_setup_LBRR(
silk_encoder_state *psEncC, /* I/O */
const silk_EncControlStruct *encControl /* I */
)
{
opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR;
LBRR_in_previous_packet = psEncC->LBRR_enabled;
psEncC->LBRR_enabled = encControl->LBRR_coded;
if( psEncC->LBRR_enabled ) {
/* Set gain increase for coding LBRR excitation */
if( LBRR_in_previous_packet == 0 ) {
/* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */
psEncC->LBRR_GainIncreases = 7;
} else {
psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 );
}
}
return ret;
}

View file

@ -0,0 +1,170 @@
/***********************************************************************
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 "debug.h"
#include "SigProc_FIX.h"
#if SILK_TIC_TOC
#ifdef _WIN32
#if (defined(_WIN32) || defined(_WINCE))
#include <windows.h> /* timer */
#else /* Linux or Mac*/
#include <sys/time.h>
#endif
unsigned long silk_GetHighResolutionTime(void) /* O time in usec*/
{
/* Returns a time counter in microsec */
/* the resolution is platform dependent */
/* but is typically 1.62 us resolution */
LARGE_INTEGER lpPerformanceCount;
LARGE_INTEGER lpFrequency;
QueryPerformanceCounter(&lpPerformanceCount);
QueryPerformanceFrequency(&lpFrequency);
return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart);
}
#else /* Linux or Mac*/
unsigned long GetHighResolutionTime(void) /* O time in usec*/
{
struct timeval tv;
gettimeofday(&tv, 0);
return((tv.tv_sec*1000000)+(tv.tv_usec));
}
#endif
int silk_Timer_nTimers = 0;
int silk_Timer_depth_ctr = 0;
char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN];
#ifdef WIN32
LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX];
#else
unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX];
#endif
unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX];
opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX];
opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX];
opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX];
opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX];
#ifdef WIN32
void silk_TimerSave(char *file_name)
{
if( silk_Timer_nTimers > 0 )
{
int k;
FILE *fp;
LARGE_INTEGER lpFrequency;
LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2;
int del = 0x7FFFFFFF;
double avg, sum_avg;
/* estimate overhead of calling performance counters */
for( k = 0; k < 1000; k++ ) {
QueryPerformanceCounter(&lpPerformanceCount1);
QueryPerformanceCounter(&lpPerformanceCount2);
lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart;
if( (int)lpPerformanceCount2.LowPart < del )
del = lpPerformanceCount2.LowPart;
}
QueryPerformanceFrequency(&lpFrequency);
/* print results to file */
sum_avg = 0.0f;
for( k = 0; k < silk_Timer_nTimers; k++ ) {
if (silk_Timer_depth[k] == 0) {
sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k];
}
}
fp = fopen(file_name, "w");
fprintf(fp, " min avg %% max count\n");
for( k = 0; k < silk_Timer_nTimers; k++ ) {
if (silk_Timer_depth[k] == 0) {
fprintf(fp, "%-28s", silk_Timer_tags[k]);
} else if (silk_Timer_depth[k] == 1) {
fprintf(fp, " %-27s", silk_Timer_tags[k]);
} else if (silk_Timer_depth[k] == 2) {
fprintf(fp, " %-26s", silk_Timer_tags[k]);
} else if (silk_Timer_depth[k] == 3) {
fprintf(fp, " %-25s", silk_Timer_tags[k]);
} else {
fprintf(fp, " %-24s", silk_Timer_tags[k]);
}
avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart;
fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart);
fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]);
fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart);
fprintf(fp, "%10d\n", silk_Timer_cnt[k]);
}
fprintf(fp, " microseconds\n");
fclose(fp);
}
}
#else
void silk_TimerSave(char *file_name)
{
if( silk_Timer_nTimers > 0 )
{
int k;
FILE *fp;
/* print results to file */
fp = fopen(file_name, "w");
fprintf(fp, " min avg max count\n");
for( k = 0; k < silk_Timer_nTimers; k++ )
{
if (silk_Timer_depth[k] == 0) {
fprintf(fp, "%-28s", silk_Timer_tags[k]);
} else if (silk_Timer_depth[k] == 1) {
fprintf(fp, " %-27s", silk_Timer_tags[k]);
} else if (silk_Timer_depth[k] == 2) {
fprintf(fp, " %-26s", silk_Timer_tags[k]);
} else if (silk_Timer_depth[k] == 3) {
fprintf(fp, " %-25s", silk_Timer_tags[k]);
} else {
fprintf(fp, " %-24s", silk_Timer_tags[k]);
}
fprintf(fp, "%d ", silk_Timer_min[k]);
fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]);
fprintf(fp, "%d ", silk_Timer_max[k]);
fprintf(fp, "%10d\n", silk_Timer_cnt[k]);
}
fprintf(fp, " microseconds\n");
fclose(fp);
}
}
#endif
#endif /* SILK_TIC_TOC */
#if SILK_DEBUG
FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ];
int silk_debug_store_count = 0;
#endif /* SILK_DEBUG */

View file

@ -0,0 +1,266 @@
/***********************************************************************
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.
***********************************************************************/
#ifndef SILK_DEBUG_H
#define SILK_DEBUG_H
#include "typedef.h"
#include <stdio.h> /* file writing */
#include <string.h> /* strcpy, strcmp */
#ifdef __cplusplus
extern "C"
{
#endif
unsigned long GetHighResolutionTime(void); /* O time in usec*/
/* Set to 1 to enable DEBUG_STORE_DATA() macros for dumping
* intermediate signals from the codec.
*/
#define SILK_DEBUG 0
/* Flag for using timers */
#define SILK_TIC_TOC 0
#if SILK_TIC_TOC
#if (defined(_WIN32) || defined(_WINCE))
#include <windows.h> /* timer */
#else /* Linux or Mac*/
#include <sys/time.h>
#endif
/*********************************/
/* timer functions for profiling */
/*********************************/
/* example: */
/* */
/* TIC(LPC) */
/* do_LPC(in_vec, order, acoef); // do LPC analysis */
/* TOC(LPC) */
/* */
/* and call the following just before exiting (from main) */
/* */
/* silk_TimerSave("silk_TimingData.txt"); */
/* */
/* results are now in silk_TimingData.txt */
void silk_TimerSave(char *file_name);
/* max number of timers (in different locations) */
#define silk_NUM_TIMERS_MAX 50
/* max length of name tags in TIC(..), TOC(..) */
#define silk_NUM_TIMERS_MAX_TAG_LEN 30
extern int silk_Timer_nTimers;
extern int silk_Timer_depth_ctr;
extern char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN];
#ifdef _WIN32
extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX];
#else
extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX];
#endif
extern unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX];
extern opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX];
extern opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX];
extern opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX];
extern opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX];
/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */
#ifdef _WIN32
#define TIC(TAG_NAME) { \
static int init = 0; \
static int ID = -1; \
if( init == 0 ) \
{ \
int k; \
init = 1; \
for( k = 0; k < silk_Timer_nTimers; k++ ) { \
if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
ID = k; \
break; \
} \
} \
if (ID == -1) { \
ID = silk_Timer_nTimers; \
silk_Timer_nTimers++; \
silk_Timer_depth[ID] = silk_Timer_depth_ctr; \
strcpy(silk_Timer_tags[ID], #TAG_NAME); \
silk_Timer_cnt[ID] = 0; \
silk_Timer_sum[ID] = 0; \
silk_Timer_min[ID] = 0xFFFFFFFF; \
silk_Timer_max[ID] = 0; \
} \
} \
silk_Timer_depth_ctr++; \
QueryPerformanceCounter(&silk_Timer_start[ID]); \
}
#else
#define TIC(TAG_NAME) { \
static int init = 0; \
static int ID = -1; \
if( init == 0 ) \
{ \
int k; \
init = 1; \
for( k = 0; k < silk_Timer_nTimers; k++ ) { \
if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
ID = k; \
break; \
} \
} \
if (ID == -1) { \
ID = silk_Timer_nTimers; \
silk_Timer_nTimers++; \
silk_Timer_depth[ID] = silk_Timer_depth_ctr; \
strcpy(silk_Timer_tags[ID], #TAG_NAME); \
silk_Timer_cnt[ID] = 0; \
silk_Timer_sum[ID] = 0; \
silk_Timer_min[ID] = 0xFFFFFFFF; \
silk_Timer_max[ID] = 0; \
} \
} \
silk_Timer_depth_ctr++; \
silk_Timer_start[ID] = GetHighResolutionTime(); \
}
#endif
#ifdef _WIN32
#define TOC(TAG_NAME) { \
LARGE_INTEGER lpPerformanceCount; \
static int init = 0; \
static int ID = 0; \
if( init == 0 ) \
{ \
int k; \
init = 1; \
for( k = 0; k < silk_Timer_nTimers; k++ ) { \
if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
ID = k; \
break; \
} \
} \
} \
QueryPerformanceCounter(&lpPerformanceCount); \
lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart; \
if((lpPerformanceCount.QuadPart < 100000000) && \
(lpPerformanceCount.QuadPart >= 0)) { \
silk_Timer_cnt[ID]++; \
silk_Timer_sum[ID] += lpPerformanceCount.QuadPart; \
if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] ) \
silk_Timer_max[ID] = lpPerformanceCount.QuadPart; \
if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] ) \
silk_Timer_min[ID] = lpPerformanceCount.QuadPart; \
} \
silk_Timer_depth_ctr--; \
}
#else
#define TOC(TAG_NAME) { \
unsigned long endTime; \
static int init = 0; \
static int ID = 0; \
if( init == 0 ) \
{ \
int k; \
init = 1; \
for( k = 0; k < silk_Timer_nTimers; k++ ) { \
if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
ID = k; \
break; \
} \
} \
} \
endTime = GetHighResolutionTime(); \
endTime -= silk_Timer_start[ID]; \
if((endTime < 100000000) && \
(endTime >= 0)) { \
silk_Timer_cnt[ID]++; \
silk_Timer_sum[ID] += endTime; \
if( endTime > silk_Timer_max[ID] ) \
silk_Timer_max[ID] = endTime; \
if( endTime < silk_Timer_min[ID] ) \
silk_Timer_min[ID] = endTime; \
} \
silk_Timer_depth_ctr--; \
}
#endif
#else /* SILK_TIC_TOC */
/* define macros as empty strings */
#define TIC(TAG_NAME)
#define TOC(TAG_NAME)
#define silk_TimerSave(FILE_NAME)
#endif /* SILK_TIC_TOC */
#if SILK_DEBUG
/************************************/
/* write data to file for debugging */
/************************************/
/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */
#define silk_NUM_STORES_MAX 100
extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ];
extern int silk_debug_store_count;
/* Faster way of storing the data */
#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) { \
static opus_int init = 0, cnt = 0; \
static FILE **fp; \
if (init == 0) { \
init = 1; \
cnt = silk_debug_store_count++; \
silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb"); \
} \
fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]); \
}
/* Call this at the end of main() */
#define SILK_DEBUG_STORE_CLOSE_FILES { \
opus_int i; \
for( i = 0; i < silk_debug_store_count; i++ ) { \
fclose( silk_debug_store_fp[ i ] ); \
} \
}
#else /* SILK_DEBUG */
/* define macros as empty strings */
#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES)
#define SILK_DEBUG_STORE_CLOSE_FILES
#endif /* SILK_DEBUG */
#ifdef __cplusplus
}
#endif
#endif /* SILK_DEBUG_H */

View file

@ -85,7 +85,8 @@ opus_int silk_Decode( /* O Returns error co
opus_int newPacketFlag, /* I Indicates first decoder call for this packet */
ec_dec *psRangeDec, /* I/O Compressor data structure */
opus_int16 *samplesOut, /* O Decoded output speech vector */
opus_int32 *nSamplesOut /* O Number of samples decoded */
opus_int32 *nSamplesOut, /* O Number of samples decoded */
int arch /* I Run-time architecture */
)
{
opus_int i, n, decode_only_middle = 0, ret = SILK_NO_ERROR;
@ -103,7 +104,7 @@ opus_int silk_Decode( /* O Returns error co
int delay_stack_alloc;
SAVE_STACK;
silk_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 );
celt_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 );
/**********************************/
/* Test if first frame in payload */
@ -142,13 +143,13 @@ opus_int silk_Decode( /* O Returns error co
channel_state[ n ].nFramesPerPacket = 3;
channel_state[ n ].nb_subfr = 4;
} else {
silk_assert( 0 );
celt_assert( 0 );
RESTORE_STACK;
return SILK_DEC_INVALID_FRAME_SIZE;
}
fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1;
if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) {
silk_assert( 0 );
celt_assert( 0 );
RESTORE_STACK;
return SILK_DEC_INVALID_SAMPLING_FREQUENCY;
}
@ -296,7 +297,7 @@ opus_int silk_Decode( /* O Returns error co
} else {
condCoding = CODE_CONDITIONALLY;
}
ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding);
ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding, arch);
} else {
silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) );
}

View file

@ -39,7 +39,8 @@ void silk_decode_core(
silk_decoder_state *psDec, /* I/O Decoder state */
silk_decoder_control *psDecCtrl, /* I Decoder control */
opus_int16 xq[], /* O Decoded speech */
const opus_int16 pulses[ MAX_FRAME_LENGTH ] /* I Pulse signal */
const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */
int arch /* I Run-time architecture */
)
{
opus_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType;
@ -140,14 +141,14 @@ void silk_decode_core(
if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) {
/* Rewhiten with new A coefs */
start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
silk_assert( start_idx > 0 );
celt_assert( start_idx > 0 );
if( k == 2 ) {
silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) );
}
silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ],
A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order );
A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order, arch );
/* After rewhitening the LTP state is unscaled */
if( k == 0 ) {
@ -195,7 +196,7 @@ void silk_decode_core(
for( i = 0; i < psDec->subfr_length; i++ ) {
/* Short-term prediction */
silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] );
@ -218,14 +219,12 @@ void silk_decode_core(
}
/* Add prediction to LPC excitation */
sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( pres_Q14[ i ], LPC_pred_Q10, 4 );
sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( pres_Q14[ i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) );
/* Scale with gain */
pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) );
}
/* DEBUG_STORE_DATA( dec.pcm, pxq, psDec->subfr_length * sizeof( opus_int16 ) ) */
/* Update LPC filter state */
silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
pexc_Q14 += psDec->subfr_length;

View file

@ -42,7 +42,8 @@ opus_int silk_decode_frame(
opus_int16 pOut[], /* O Pointer to output speech frame */
opus_int32 *pN, /* O Pointer to size of output frame */
opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
opus_int condCoding /* I The type of conditional coding to use */
opus_int condCoding, /* I The type of conditional coding to use */
int arch /* I Run-time architecture */
)
{
VARDECL( silk_decoder_control, psDecCtrl );
@ -54,7 +55,7 @@ opus_int silk_decode_frame(
psDecCtrl->LTP_scale_Q14 = 0;
/* Safety checks */
silk_assert( L > 0 && L <= MAX_FRAME_LENGTH );
celt_assert( L > 0 && L <= MAX_FRAME_LENGTH );
if( lostFlag == FLAG_DECODE_NORMAL ||
( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) )
@ -81,28 +82,29 @@ opus_int silk_decode_frame(
/********************************************************/
/* Run inverse NSQ */
/********************************************************/
silk_decode_core( psDec, psDecCtrl, pOut, pulses );
silk_decode_core( psDec, psDecCtrl, pOut, pulses, arch );
/********************************************************/
/* Update PLC state */
/********************************************************/
silk_PLC( psDec, psDecCtrl, pOut, 0 );
silk_PLC( psDec, psDecCtrl, pOut, 0, arch );
psDec->lossCnt = 0;
psDec->prevSignalType = psDec->indices.signalType;
silk_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 );
celt_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 );
/* A frame has been decoded without errors */
psDec->first_frame_after_reset = 0;
} else {
/* Handle packet loss by extrapolation */
silk_PLC( psDec, psDecCtrl, pOut, 1 );
psDec->indices.signalType = psDec->prevSignalType;
silk_PLC( psDec, psDecCtrl, pOut, 1, arch );
}
/*************************/
/* Update output buffer. */
/*************************/
silk_assert( psDec->ltp_mem_length >= psDec->frame_length );
celt_assert( psDec->ltp_mem_length >= psDec->frame_length );
mv_len = psDec->ltp_mem_length - psDec->frame_length;
silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) );
silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) );

View file

@ -79,7 +79,7 @@ void silk_decode_indices(
/**********************/
psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 );
silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] );
silk_assert( psDec->psNLSF_CB->order == psDec->LPC_order );
celt_assert( psDec->psNLSF_CB->order == psDec->LPC_order );
for( i = 0; i < psDec->psNLSF_CB->order; i++ ) {
Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
if( Ix == 0 ) {

View file

@ -52,7 +52,7 @@ void silk_decode_parameters(
silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB );
/* Convert NLSF parameters to AR prediction filter coefficients */
silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order );
silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order, psDec->arch );
/* If just reset, e.g., because internal Fs changed, do not allow interpolation */
/* improves the case of packet loss in the first frame after a switch */
@ -69,7 +69,7 @@ void silk_decode_parameters(
}
/* Convert NLSF parameters to AR prediction filter coefficients */
silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order );
silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order, psDec->arch );
} else {
/* Copy LPC coefficients for first half from second half */
silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );

View file

@ -51,7 +51,7 @@ void silk_decode_pitch(
Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
cbk_size = PE_NB_CBKS_STAGE2_EXT;
} else {
silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
cbk_size = PE_NB_CBKS_STAGE2_10MS;
}
@ -60,7 +60,7 @@ void silk_decode_pitch(
Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
cbk_size = PE_NB_CBKS_STAGE3_MAX;
} else {
silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
cbk_size = PE_NB_CBKS_STAGE3_10MS;
}

View file

@ -56,7 +56,7 @@ void silk_decode_pulses(
silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH );
iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH );
if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) {
silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
iter++;
}
@ -69,9 +69,9 @@ void silk_decode_pulses(
sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 );
/* LSB indication */
while( sum_pulses[ i ] == MAX_PULSES + 1 ) {
while( sum_pulses[ i ] == SILK_MAX_PULSES + 1 ) {
nLshifts[ i ]++;
/* When we've already got 10 LSBs, we shift the table to not allow (MAX_PULSES + 1) */
/* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */
sum_pulses[ i ] = ec_dec_icdf( psRangeDec,
silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 );
}

View file

@ -40,8 +40,8 @@ opus_int silk_decoder_set_fs(
{
opus_int frame_length, ret = 0;
silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
silk_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 );
celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
celt_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 );
/* New (sub)frame length */
psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz );
@ -86,7 +86,7 @@ opus_int silk_decoder_set_fs(
psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF;
} else {
/* unsupported sampling rate */
silk_assert( 0 );
celt_assert( 0 );
}
psDec->first_frame_after_reset = 1;
psDec->lagPrev = 100;
@ -101,7 +101,7 @@ opus_int silk_decoder_set_fs(
}
/* Check that settings are valid */
silk_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH );
celt_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH );
return ret;
}

View file

@ -46,7 +46,6 @@ extern "C"
/* Limits on bitrate */
#define MIN_TARGET_RATE_BPS 5000
#define MAX_TARGET_RATE_BPS 80000
#define TARGET_RATE_TAB_SZ 8
/* LBRR thresholds */
#define LBRR_NB_MIN_RATE_BPS 12000
@ -56,6 +55,12 @@ extern "C"
/* DTX settings */
#define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */
#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */
#define DTX_ACTIVITY_THRESHOLD 0.1f
/* VAD decision */
#define VAD_NO_DECISION -1
#define VAD_NO_ACTIVITY 0
#define VAD_ACTIVITY 1
/* Maximum sampling frequency */
#define MAX_FS_KHZ 16
@ -147,7 +152,7 @@ extern "C"
#define USE_HARM_SHAPING 1
/* Max LPC order of noise shaping filters */
#define MAX_SHAPE_LPC_ORDER 16
#define MAX_SHAPE_LPC_ORDER 24
#define HARM_SHAPE_FIR_TAPS 3
@ -157,8 +162,7 @@ extern "C"
#define LTP_BUF_LENGTH 512
#define LTP_MASK ( LTP_BUF_LENGTH - 1 )
#define DECISION_DELAY 32
#define DECISION_DELAY_MASK ( DECISION_DELAY - 1 )
#define DECISION_DELAY 40
/* Number of subframes for excitation entropy coding */
#define SHELL_CODEC_FRAME_LENGTH 16
@ -169,15 +173,11 @@ extern "C"
#define N_RATE_LEVELS 10
/* Maximum sum of pulses per shell coding frame */
#define MAX_PULSES 16
#define SILK_MAX_PULSES 16
#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */
#if( MAX_LPC_ORDER > DECISION_DELAY )
# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER
#else
# define NSQ_LPC_BUF_LENGTH DECISION_DELAY
#endif
/***************************/
/* Voice activity detector */
@ -205,7 +205,6 @@ extern "C"
/******************/
#define NLSF_W_Q 2
#define NLSF_VQ_MAX_VECTORS 32
#define NLSF_VQ_MAX_SURVIVORS 32
#define NLSF_QUANT_MAX_AMPLITUDE 4
#define NLSF_QUANT_MAX_AMPLITUDE_EXT 10
#define NLSF_QUANT_LEVEL_ADJ 0.1

View file

@ -0,0 +1,576 @@
/***********************************************************************
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 "define.h"
#include "API.h"
#include "control.h"
#include "typedef.h"
#include "stack_alloc.h"
#include "structs.h"
#include "tuning_parameters.h"
#ifdef FIXED_POINT
#include "main_FIX.h"
#else
#include "main_FLP.h"
#endif
/***************************************/
/* Read control structure from encoder */
/***************************************/
static opus_int silk_QueryEncoder( /* O Returns error code */
const void *encState, /* I State */
silk_EncControlStruct *encStatus /* O Encoder Status */
);
/****************************************/
/* Encoder functions */
/****************************************/
opus_int silk_Get_Encoder_Size( /* O Returns error code */
opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */
)
{
opus_int ret = SILK_NO_ERROR;
*encSizeBytes = sizeof( silk_encoder );
return ret;
}
/*************************/
/* Init or Reset encoder */
/*************************/
opus_int silk_InitEncoder( /* O Returns error code */
void *encState, /* I/O State */
int arch, /* I Run-time architecture */
silk_EncControlStruct *encStatus /* O Encoder Status */
)
{
silk_encoder *psEnc;
opus_int n, ret = SILK_NO_ERROR;
psEnc = (silk_encoder *)encState;
/* Reset encoder */
silk_memset( psEnc, 0, sizeof( silk_encoder ) );
for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) {
if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ], arch ) ) {
celt_assert( 0 );
}
}
psEnc->nChannelsAPI = 1;
psEnc->nChannelsInternal = 1;
/* Read control structure */
if( ret += silk_QueryEncoder( encState, encStatus ) ) {
celt_assert( 0 );
}
return ret;
}
/***************************************/
/* Read control structure from encoder */
/***************************************/
static opus_int silk_QueryEncoder( /* O Returns error code */
const void *encState, /* I State */
silk_EncControlStruct *encStatus /* O Encoder Status */
)
{
opus_int ret = SILK_NO_ERROR;
silk_encoder_state_Fxx *state_Fxx;
silk_encoder *psEnc = (silk_encoder *)encState;
state_Fxx = psEnc->state_Fxx;
encStatus->nChannelsAPI = psEnc->nChannelsAPI;
encStatus->nChannelsInternal = psEnc->nChannelsInternal;
encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz;
encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz;
encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz;
encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz;
encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms;
encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps;
encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc;
encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity;
encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC;
encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX;
encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR;
encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch;
encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0;
return ret;
}
/**************************/
/* Encode frame with Silk */
/**************************/
/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */
/* encControl->payloadSize_ms is set to */
opus_int silk_Encode( /* O Returns error code */
void *encState, /* I/O State */
silk_EncControlStruct *encControl, /* I Control status */
const opus_int16 *samplesIn, /* I Speech sample input vector */
opus_int nSamplesIn, /* I Number of samples in input vector */
ec_enc *psRangeEnc, /* I/O Compressor data structure */
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */
opus_int activity /* I Decision of Opus voice activity detector */
)
{
opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0;
opus_int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms;
opus_int nSamplesFromInput = 0, nSamplesFromInputMax;
opus_int speech_act_thr_for_switch_Q8;
opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum;
silk_encoder *psEnc = ( silk_encoder * )encState;
VARDECL( opus_int16, buf );
opus_int transition, curr_block, tot_blocks;
SAVE_STACK;
if (encControl->reducedDependency)
{
psEnc->state_Fxx[0].sCmn.first_frame_after_reset = 1;
psEnc->state_Fxx[1].sCmn.first_frame_after_reset = 1;
}
psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0;
/* Check values in encoder control structure */
if( ( ret = check_control_input( encControl ) ) != 0 ) {
celt_assert( 0 );
RESTORE_STACK;
return ret;
}
encControl->switchReady = 0;
if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) {
/* Mono -> Stereo transition: init state of second channel and stereo state */
ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ], psEnc->state_Fxx[ 0 ].sCmn.arch );
silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) );
silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) );
psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0;
psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1;
psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0;
psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1;
psEnc->sStereo.width_prev_Q14 = 0;
psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 );
if( psEnc->nChannelsAPI == 2 ) {
silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) );
silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) );
}
}
transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal);
psEnc->nChannelsAPI = encControl->nChannelsAPI;
psEnc->nChannelsInternal = encControl->nChannelsInternal;
nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate );
tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1;
curr_block = 0;
if( prefillFlag ) {
silk_LP_state save_LP;
/* Only accept input length of 10 ms */
if( nBlocksOf10ms != 1 ) {
celt_assert( 0 );
RESTORE_STACK;
return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
}
if ( prefillFlag == 2 ) {
save_LP = psEnc->state_Fxx[ 0 ].sCmn.sLP;
/* Save the sampling rate so the bandwidth switching code can keep handling transitions. */
save_LP.saved_fs_kHz = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz;
}
/* Reset Encoder */
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
ret = silk_init_encoder( &psEnc->state_Fxx[ n ], psEnc->state_Fxx[ n ].sCmn.arch );
/* Restore the variable LP state. */
if ( prefillFlag == 2 ) {
psEnc->state_Fxx[ n ].sCmn.sLP = save_LP;
}
celt_assert( !ret );
}
tmp_payloadSize_ms = encControl->payloadSize_ms;
encControl->payloadSize_ms = 10;
tmp_complexity = encControl->complexity;
encControl->complexity = 0;
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1;
}
} else {
/* Only accept input lengths that are a multiple of 10 ms */
if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) {
celt_assert( 0 );
RESTORE_STACK;
return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
}
/* Make sure no more than one packet can be produced */
if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) {
celt_assert( 0 );
RESTORE_STACK;
return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
}
}
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
/* Force the side channel to the same rate as the mid */
opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0;
if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) {
silk_assert( 0 );
RESTORE_STACK;
return ret;
}
if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) {
for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0;
}
}
psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX;
}
celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
/* Input buffering/resampling and encoding */
nSamplesToBufferMax =
10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz;
nSamplesFromInputMax =
silk_DIV32_16( nSamplesToBufferMax *
psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz,
psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
ALLOC( buf, nSamplesFromInputMax, opus_int16 );
while( 1 ) {
nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx;
nSamplesToBuffer = silk_min( nSamplesToBuffer, nSamplesToBufferMax );
nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
/* Resample and write to buffer */
if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) {
opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
for( n = 0; n < nSamplesFromInput; n++ ) {
buf[ n ] = samplesIn[ 2 * n ];
}
/* Making sure to start both resamplers from the same state when switching from mono to stereo */
if( psEnc->nPrevChannelsInternal == 1 && id==0 ) {
silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state));
}
ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
&psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx;
nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
for( n = 0; n < nSamplesFromInput; n++ ) {
buf[ n ] = samplesIn[ 2 * n + 1 ];
}
ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
&psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer;
} else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) {
/* Combine left and right channels before resampling */
for( n = 0; n < nSamplesFromInput; n++ ) {
sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ];
buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
}
ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
&psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
/* On the first mono frame, average the results for the two resampler states */
if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) {
ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
&psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) {
psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] =
silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ]
+ psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1);
}
}
psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
} else {
celt_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 );
silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16));
ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
&psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
}
samplesIn += nSamplesFromInput * encControl->nChannelsAPI;
nSamplesIn -= nSamplesFromInput;
/* Default */
psEnc->allowBandwidthSwitch = 0;
/* Silk encoder */
if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) {
/* Enough data in input buffer, so encode */
celt_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length );
celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length );
/* Deal with LBRR data */
if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) {
/* Create space at start of payload for VAD and FEC flags */
opus_uint8 iCDF[ 2 ] = { 0, 0 };
iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
ec_enc_icdf( psRangeEnc, 0, iCDF, 8 );
/* Encode any LBRR data from previous packet */
/* Encode LBRR flags */
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
LBRR_symbol = 0;
for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i );
}
psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0;
if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) {
ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 );
}
}
/* Code LBRR indices and excitation signals */
for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) {
opus_int condCoding;
if( encControl->nChannelsInternal == 2 && n == 0 ) {
silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] );
/* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */
if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) {
silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] );
}
}
/* Use conditional coding if previous frame available */
if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) {
condCoding = CODE_CONDITIONALLY;
} else {
condCoding = CODE_INDEPENDENTLY;
}
silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding );
silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType,
psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length );
}
}
}
/* Reset LBRR flags */
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) );
}
psEnc->nBitsUsedLBRR = ec_tell( psRangeEnc );
}
silk_HP_variable_cutoff( psEnc->state_Fxx );
/* Total target bits for packet */
nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
/* Subtract bits used for LBRR */
if( !prefillFlag ) {
nBits -= psEnc->nBitsUsedLBRR;
}
/* Divide by number of uncoded frames left in packet */
nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket );
/* Convert to bits/second */
if( encControl->payloadSize_ms == 10 ) {
TargetRate_bps = silk_SMULBB( nBits, 100 );
} else {
TargetRate_bps = silk_SMULBB( nBits, 50 );
}
/* Subtract fraction of bits in excess of target in previous frames and packets */
TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS );
if( !prefillFlag && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded > 0 ) {
/* Compare actual vs target bits so far in this packet */
opus_int32 bitsBalance = ec_tell( psRangeEnc ) - psEnc->nBitsUsedLBRR - nBits * psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
TargetRate_bps -= silk_DIV32_16( silk_MUL( bitsBalance, 1000 ), BITRESERVOIR_DECAY_TIME_MS );
}
/* Never exceed input bitrate */
TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 );
/* Convert Left/Right to Mid/Side */
if( encControl->nChannelsInternal == 2 ) {
silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ],
psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ],
MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono,
psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length );
if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
/* Reset side channel encoder memory for first frame with side coding */
if( psEnc->prev_decode_only_middle == 1 ) {
silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) );
silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) );
silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) );
silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) );
psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100;
psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100;
psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10;
psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY;
psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536;
psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1;
}
silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ], activity );
} else {
psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0;
}
if( !prefillFlag ) {
silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
}
}
} else {
/* Buffering */
silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) );
silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) );
}
silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ], activity );
/* Encode */
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
opus_int maxBits, useCBR;
/* Handling rate constraints */
maxBits = encControl->maxBits;
if( tot_blocks == 2 && curr_block == 0 ) {
maxBits = maxBits * 3 / 5;
} else if( tot_blocks == 3 ) {
if( curr_block == 0 ) {
maxBits = maxBits * 2 / 5;
} else if( curr_block == 1 ) {
maxBits = maxBits * 3 / 4;
}
}
useCBR = encControl->useCBR && curr_block == tot_blocks - 1;
if( encControl->nChannelsInternal == 1 ) {
channelRate_bps = TargetRate_bps;
} else {
channelRate_bps = MStargetRates_bps[ n ];
if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) {
useCBR = 0;
/* Give mid up to 1/2 of the max bits for that frame */
maxBits -= encControl->maxBits / ( tot_blocks * 2 );
}
}
if( channelRate_bps > 0 ) {
opus_int condCoding;
silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps );
/* Use independent coding if no previous frame available */
if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) {
condCoding = CODE_INDEPENDENTLY;
} else if( n > 0 && psEnc->prev_decode_only_middle ) {
/* If we skipped a side frame in this packet, we don't
need LTP scaling; the LTP state is well-defined. */
condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING;
} else {
condCoding = CODE_CONDITIONALLY;
}
if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) {
silk_assert( 0 );
}
}
psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0;
psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++;
}
psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ];
/* Insert VAD and FEC flags at beginning of bitstream */
if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) {
flags = 0;
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
flags = silk_LSHIFT( flags, 1 );
flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ];
}
flags = silk_LSHIFT( flags, 1 );
flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag;
}
if( !prefillFlag ) {
ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
}
/* Return zero bytes if all channels DTXed */
if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) {
*nBytesOut = 0;
}
psEnc->nBitsExceeded += *nBytesOut * 8;
psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 );
/* Update flag indicating if bandwidth switching is allowed */
speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ),
SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms );
if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) {
psEnc->allowBandwidthSwitch = 1;
psEnc->timeSinceSwitchAllowed_ms = 0;
} else {
psEnc->allowBandwidthSwitch = 0;
psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms;
}
}
if( nSamplesIn == 0 ) {
break;
}
} else {
break;
}
curr_block++;
}
psEnc->nPrevChannelsInternal = encControl->nChannelsInternal;
encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch;
encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0;
encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14;
if( prefillFlag ) {
encControl->payloadSize_ms = tmp_payloadSize_ms;
encControl->complexity = tmp_complexity;
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0;
}
}
encControl->signalType = psEnc->state_Fxx[0].sCmn.indices.signalType;
encControl->offset = silk_Quantization_Offsets_Q10
[ psEnc->state_Fxx[0].sCmn.indices.signalType >> 1 ]
[ psEnc->state_Fxx[0].sCmn.indices.quantOffsetType ];
RESTORE_STACK;
return ret;
}

View file

@ -0,0 +1,181 @@
/***********************************************************************
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"
/* Encode side-information parameters to payload */
void silk_encode_indices(
silk_encoder_state *psEncC, /* I/O Encoder state */
ec_enc *psRangeEnc, /* I/O Compressor data structure */
opus_int FrameIndex, /* I Frame number */
opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */
opus_int condCoding /* I The type of conditional coding to use */
)
{
opus_int i, k, typeOffset;
opus_int encode_absolute_lagIndex, delta_lagIndex;
opus_int16 ec_ix[ MAX_LPC_ORDER ];
opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
const SideInfoIndices *psIndices;
if( encode_LBRR ) {
psIndices = &psEncC->indices_LBRR[ FrameIndex ];
} else {
psIndices = &psEncC->indices;
}
/*******************************************/
/* Encode signal type and quantizer offset */
/*******************************************/
typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType;
celt_assert( typeOffset >= 0 && typeOffset < 6 );
celt_assert( encode_LBRR == 0 || typeOffset >= 2 );
if( encode_LBRR || typeOffset >= 2 ) {
ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 );
} else {
ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 );
}
/****************/
/* Encode gains */
/****************/
/* first subframe */
if( condCoding == CODE_CONDITIONALLY ) {
/* conditional coding */
silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 );
} else {
/* independent coding, in two stages: MSB bits followed by 3 LSBs */
silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN );
ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 );
ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 );
}
/* remaining subframes */
for( i = 1; i < psEncC->nb_subfr; i++ ) {
silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 );
}
/****************/
/* Encode NLSFs */
/****************/
ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 );
silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] );
celt_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder );
for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) {
if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) {
ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
} else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) {
ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
} else {
ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
}
}
/* Encode NLSF interpolation factor */
if( psEncC->nb_subfr == MAX_NB_SUBFR ) {
silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 );
ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 );
}
if( psIndices->signalType == TYPE_VOICED )
{
/*********************/
/* Encode pitch lags */
/*********************/
/* lag index */
encode_absolute_lagIndex = 1;
if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) {
/* Delta Encoding */
delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex;
if( delta_lagIndex < -8 || delta_lagIndex > 11 ) {
delta_lagIndex = 0;
} else {
delta_lagIndex = delta_lagIndex + 9;
encode_absolute_lagIndex = 0; /* Only use delta */
}
silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 );
ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 );
}
if( encode_absolute_lagIndex ) {
/* Absolute encoding */
opus_int32 pitch_high_bits, pitch_low_bits;
pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 );
silk_assert( pitch_high_bits < 32 );
ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 );
ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 );
}
psEncC->ec_prevLagIndex = psIndices->lagIndex;
/* Countour index */
silk_assert( psIndices->contourIndex >= 0 );
silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 4 ) ||
( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) ||
( psIndices->contourIndex < 12 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 2 ) ||
( psIndices->contourIndex < 3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) );
ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 );
/********************/
/* Encode LTP gains */
/********************/
/* PERIndex value */
silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 );
ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 );
/* Codebook Indices */
for( k = 0; k < psEncC->nb_subfr; k++ ) {
silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) );
ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 );
}
/**********************/
/* Encode LTP scaling */
/**********************/
if( condCoding == CODE_INDEPENDENTLY ) {
silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 );
ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 );
}
silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 );
}
psEncC->ec_prevSignalType = psIndices->signalType;
/***************/
/* Encode seed */
/***************/
silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 );
ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 );
}

View file

@ -0,0 +1,206 @@
/***********************************************************************
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"
/*********************************************/
/* Encode quantization indices of excitation */
/*********************************************/
static OPUS_INLINE opus_int combine_and_check( /* return ok */
opus_int *pulses_comb, /* O */
const opus_int *pulses_in, /* I */
opus_int max_pulses, /* I max value for sum of pulses */
opus_int len /* I number of output values */
)
{
opus_int k, sum;
for( k = 0; k < len; k++ ) {
sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ];
if( sum > max_pulses ) {
return 1;
}
pulses_comb[ k ] = sum;
}
return 0;
}
/* Encode quantization indices of excitation */
void silk_encode_pulses(
ec_enc *psRangeEnc, /* I/O compressor data structure */
const opus_int signalType, /* I Signal type */
const opus_int quantOffsetType, /* I quantOffsetType */
opus_int8 pulses[], /* I quantization indices */
const opus_int frame_length /* I Frame length */
)
{
opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0;
opus_int32 abs_q, minSumBits_Q5, sumBits_Q5;
VARDECL( opus_int, abs_pulses );
VARDECL( opus_int, sum_pulses );
VARDECL( opus_int, nRshifts );
opus_int pulses_comb[ 8 ];
opus_int *abs_pulses_ptr;
const opus_int8 *pulses_ptr;
const opus_uint8 *cdf_ptr;
const opus_uint8 *nBits_ptr;
SAVE_STACK;
silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/
/****************************/
/* Prepare for shell coding */
/****************************/
/* Calculate number of shell blocks */
silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH );
iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH );
if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) {
celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
iter++;
silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8));
}
/* Take the absolute value of the pulses */
ALLOC( abs_pulses, iter * SHELL_CODEC_FRAME_LENGTH, opus_int );
silk_assert( !( SHELL_CODEC_FRAME_LENGTH & 3 ) );
for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) {
abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] );
abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] );
abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] );
abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] );
}
/* Calc sum pulses per shell code frame */
ALLOC( sum_pulses, iter, opus_int );
ALLOC( nRshifts, iter, opus_int );
abs_pulses_ptr = abs_pulses;
for( i = 0; i < iter; i++ ) {
nRshifts[ i ] = 0;
while( 1 ) {
/* 1+1 -> 2 */
scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 );
/* 2+2 -> 4 */
scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 );
/* 4+4 -> 8 */
scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 );
/* 8+8 -> 16 */
scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 );
if( scale_down ) {
/* We need to downscale the quantization signal */
nRshifts[ i ]++;
for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 );
}
} else {
/* Jump out of while(1) loop and go to next shell coding frame */
break;
}
}
abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH;
}
/**************/
/* Rate level */
/**************/
/* find rate level that leads to fewest bits for coding of pulses per block info */
minSumBits_Q5 = silk_int32_MAX;
for( k = 0; k < N_RATE_LEVELS - 1; k++ ) {
nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ];
sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ];
for( i = 0; i < iter; i++ ) {
if( nRshifts[ i ] > 0 ) {
sumBits_Q5 += nBits_ptr[ SILK_MAX_PULSES + 1 ];
} else {
sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ];
}
}
if( sumBits_Q5 < minSumBits_Q5 ) {
minSumBits_Q5 = sumBits_Q5;
RateLevelIndex = k;
}
}
ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 );
/***************************************************/
/* Sum-Weighted-Pulses Encoding */
/***************************************************/
cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ];
for( i = 0; i < iter; i++ ) {
if( nRshifts[ i ] == 0 ) {
ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 );
} else {
ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, cdf_ptr, 8 );
for( k = 0; k < nRshifts[ i ] - 1; k++ ) {
ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
}
ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
}
}
/******************/
/* Shell Encoding */
/******************/
for( i = 0; i < iter; i++ ) {
if( sum_pulses[ i ] > 0 ) {
silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] );
}
}
/****************/
/* LSB Encoding */
/****************/
for( i = 0; i < iter; i++ ) {
if( nRshifts[ i ] > 0 ) {
pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ];
nLS = nRshifts[ i ] - 1;
for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] );
for( j = nLS; j > 0; j-- ) {
bit = silk_RSHIFT( abs_q, j ) & 1;
ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
}
bit = abs_q & 1;
ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
}
}
}
/****************/
/* Encode signs */
/****************/
silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses );
RESTORE_STACK;
}

View file

@ -0,0 +1,90 @@
/***********************************************************************
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_FIX.h"
void silk_LTP_analysis_filter_FIX(
opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */
const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */
const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */
const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */
const opus_int subfr_length, /* I Length of each subframe */
const opus_int nb_subfr, /* I Number of subframes */
const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */
)
{
const opus_int16 *x_ptr, *x_lag_ptr;
opus_int16 Btmp_Q14[ LTP_ORDER ];
opus_int16 *LTP_res_ptr;
opus_int k, i;
opus_int32 LTP_est;
x_ptr = x;
LTP_res_ptr = LTP_res;
for( k = 0; k < nb_subfr; k++ ) {
x_lag_ptr = x_ptr - pitchL[ k ];
Btmp_Q14[ 0 ] = LTPCoef_Q14[ k * LTP_ORDER ];
Btmp_Q14[ 1 ] = LTPCoef_Q14[ k * LTP_ORDER + 1 ];
Btmp_Q14[ 2 ] = LTPCoef_Q14[ k * LTP_ORDER + 2 ];
Btmp_Q14[ 3 ] = LTPCoef_Q14[ k * LTP_ORDER + 3 ];
Btmp_Q14[ 4 ] = LTPCoef_Q14[ k * LTP_ORDER + 4 ];
/* LTP analysis FIR filter */
for( i = 0; i < subfr_length + pre_length; i++ ) {
LTP_res_ptr[ i ] = x_ptr[ i ];
/* Long-term prediction */
LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] );
LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 1 ], Btmp_Q14[ 1 ] );
LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 0 ], Btmp_Q14[ 2 ] );
LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -1 ], Btmp_Q14[ 3 ] );
LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -2 ], Btmp_Q14[ 4 ] );
LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/
/* Subtract long-term prediction */
LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est );
/* Scale residual */
LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] );
x_lag_ptr++;
}
/* Update pointers */
LTP_res_ptr += subfr_length + pre_length;
x_ptr += subfr_length;
}
}

View file

@ -0,0 +1,53 @@
/***********************************************************************
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_FIX.h"
/* Calculation of LTP state scaling */
void silk_LTP_scale_ctrl_FIX(
silk_encoder_state_FIX *psEnc, /* I/O encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
opus_int condCoding /* I The type of conditional coding to use */
)
{
opus_int round_loss;
if( condCoding == CODE_INDEPENDENTLY ) {
/* Only scale if first frame in packet */
round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket;
psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT(
silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 );
} else {
/* Default is minimum scaling */
psEnc->sCmn.indices.LTP_scaleIndex = 0;
}
psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ];
}

View file

@ -0,0 +1,101 @@
/***********************************************************************
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 "SigProc_FIX.h"
/* Apply sine window to signal vector. */
/* Window types: */
/* 1 -> sine window from 0 to pi/2 */
/* 2 -> sine window from pi/2 to pi */
/* Every other sample is linearly interpolated, for speed. */
/* Window length must be between 16 and 120 (incl) and a multiple of 4. */
/* Matlab code for table:
for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end
*/
static const opus_int16 freq_table_Q16[ 27 ] = {
12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202,
3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422,
2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702,
};
void silk_apply_sine_window(
opus_int16 px_win[], /* O Pointer to windowed signal */
const opus_int16 px[], /* I Pointer to input signal */
const opus_int win_type, /* I Selects a window type */
const opus_int length /* I Window length, multiple of 4 */
)
{
opus_int k, f_Q16, c_Q16;
opus_int32 S0_Q16, S1_Q16;
celt_assert( win_type == 1 || win_type == 2 );
/* Length must be in a range from 16 to 120 and a multiple of 4 */
celt_assert( length >= 16 && length <= 120 );
celt_assert( ( length & 3 ) == 0 );
/* Frequency */
k = ( length >> 2 ) - 4;
celt_assert( k >= 0 && k <= 26 );
f_Q16 = (opus_int)freq_table_Q16[ k ];
/* Factor used for cosine approximation */
c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 );
silk_assert( c_Q16 >= -32768 );
/* initialize state */
if( win_type == 1 ) {
/* start from 0 */
S0_Q16 = 0;
/* approximation of sin(f) */
S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 );
} else {
/* start from 1 */
S0_Q16 = ( (opus_int32)1 << 16 );
/* approximation of cos(f) */
S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 );
}
/* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */
/* 4 samples at a time */
for( k = 0; k < length; k += 4 ) {
px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] );
px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] );
S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1;
S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) );
px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] );
px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] );
S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16;
S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) );
}
}

View file

@ -0,0 +1,68 @@
/***********************************************************************
Copyright (c) 2017 Google Inc.
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.
***********************************************************************/
#ifndef SILK_WARPED_AUTOCORRELATION_FIX_ARM_H
# define SILK_WARPED_AUTOCORRELATION_FIX_ARM_H
# include "celt/arm/armcpu.h"
# if defined(FIXED_POINT)
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
void silk_warped_autocorrelation_FIX_neon(
opus_int32 *corr, /* O Result [order + 1] */
opus_int *scale, /* O Scaling of the correlation vector */
const opus_int16 *input, /* I Input data to correlate */
const opus_int warping_Q16, /* I Warping coefficient */
const opus_int length, /* I Length of input */
const opus_int order /* I Correlation order (even) */
);
# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON)
# define OVERRIDE_silk_warped_autocorrelation_FIX (1)
# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \
((void)(arch), PRESUME_NEON(silk_warped_autocorrelation_FIX)(corr, scale, input, warping_Q16, length, order))
# endif
# endif
# if !defined(OVERRIDE_silk_warped_autocorrelation_FIX)
/*Is run-time CPU detection enabled on this platform?*/
# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
extern void (*const SILK_WARPED_AUTOCORRELATION_FIX_IMPL[OPUS_ARCHMASK+1])(opus_int32*, opus_int*, const opus_int16*, const opus_int, const opus_int, const opus_int);
# define OVERRIDE_silk_warped_autocorrelation_FIX (1)
# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \
((*SILK_WARPED_AUTOCORRELATION_FIX_IMPL[(arch)&OPUS_ARCHMASK])(corr, scale, input, warping_Q16, length, order))
# elif defined(OPUS_ARM_PRESUME_NEON_INTR)
# define OVERRIDE_silk_warped_autocorrelation_FIX (1)
# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \
((void)(arch), silk_warped_autocorrelation_FIX_neon(corr, scale, input, warping_Q16, length, order))
# endif
# endif
# endif /* end FIXED_POINT */
#endif /* end SILK_WARPED_AUTOCORRELATION_FIX_ARM_H */

View file

@ -0,0 +1,260 @@
/***********************************************************************
Copyright (c) 2017 Google Inc., Jean-Marc Valin
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 <arm_neon.h>
#ifdef OPUS_CHECK_ASM
# include <string.h>
#endif
#include "stack_alloc.h"
#include "main_FIX.h"
static OPUS_INLINE void calc_corr( const opus_int32 *const input_QS, opus_int64 *const corr_QC, const opus_int offset, const int32x4_t state_QS_s32x4 )
{
int64x2_t corr_QC_s64x2[ 2 ], t_s64x2[ 2 ];
const int32x4_t input_QS_s32x4 = vld1q_s32( input_QS + offset );
corr_QC_s64x2[ 0 ] = vld1q_s64( corr_QC + offset + 0 );
corr_QC_s64x2[ 1 ] = vld1q_s64( corr_QC + offset + 2 );
t_s64x2[ 0 ] = vmull_s32( vget_low_s32( state_QS_s32x4 ), vget_low_s32( input_QS_s32x4 ) );
t_s64x2[ 1 ] = vmull_s32( vget_high_s32( state_QS_s32x4 ), vget_high_s32( input_QS_s32x4 ) );
corr_QC_s64x2[ 0 ] = vsraq_n_s64( corr_QC_s64x2[ 0 ], t_s64x2[ 0 ], 2 * QS - QC );
corr_QC_s64x2[ 1 ] = vsraq_n_s64( corr_QC_s64x2[ 1 ], t_s64x2[ 1 ], 2 * QS - QC );
vst1q_s64( corr_QC + offset + 0, corr_QC_s64x2[ 0 ] );
vst1q_s64( corr_QC + offset + 2, corr_QC_s64x2[ 1 ] );
}
static OPUS_INLINE int32x4_t calc_state( const int32x4_t state_QS0_s32x4, const int32x4_t state_QS0_1_s32x4, const int32x4_t state_QS1_1_s32x4, const int32x4_t warping_Q16_s32x4 )
{
int32x4_t t_s32x4 = vsubq_s32( state_QS0_s32x4, state_QS0_1_s32x4 );
t_s32x4 = vqdmulhq_s32( t_s32x4, warping_Q16_s32x4 );
return vaddq_s32( state_QS1_1_s32x4, t_s32x4 );
}
void silk_warped_autocorrelation_FIX_neon(
opus_int32 *corr, /* O Result [order + 1] */
opus_int *scale, /* O Scaling of the correlation vector */
const opus_int16 *input, /* I Input data to correlate */
const opus_int warping_Q16, /* I Warping coefficient */
const opus_int length, /* I Length of input */
const opus_int order /* I Correlation order (even) */
)
{
if( ( MAX_SHAPE_LPC_ORDER > 24 ) || ( order < 6 ) ) {
silk_warped_autocorrelation_FIX_c( corr, scale, input, warping_Q16, length, order );
} else {
opus_int n, i, lsh;
opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; /* In reverse order */
opus_int64 corr_QC_orderT;
int64x2_t lsh_s64x2;
const opus_int orderT = ( order + 3 ) & ~3;
opus_int64 *corr_QCT;
opus_int32 *input_QS;
VARDECL( opus_int32, input_QST );
VARDECL( opus_int32, state );
SAVE_STACK;
/* Order must be even */
silk_assert( ( order & 1 ) == 0 );
silk_assert( 2 * QS - QC >= 0 );
ALLOC( input_QST, length + 2 * MAX_SHAPE_LPC_ORDER, opus_int32 );
input_QS = input_QST;
/* input_QS has zero paddings in the beginning and end. */
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
/* Loop over samples */
for( n = 0; n < length - 7; n += 8, input_QS += 8 ) {
const int16x8_t t0_s16x4 = vld1q_s16( input + n );
vst1q_s32( input_QS + 0, vshll_n_s16( vget_low_s16( t0_s16x4 ), QS ) );
vst1q_s32( input_QS + 4, vshll_n_s16( vget_high_s16( t0_s16x4 ), QS ) );
}
for( ; n < length; n++, input_QS++ ) {
input_QS[ 0 ] = silk_LSHIFT32( (opus_int32)input[ n ], QS );
}
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS += 4;
vst1q_s32( input_QS, vdupq_n_s32( 0 ) );
input_QS = input_QST + MAX_SHAPE_LPC_ORDER - orderT;
/* The following loop runs ( length + order ) times, with ( order ) extra epilogues. */
/* The zero paddings in input_QS guarantee corr_QC's correctness even with the extra epilogues. */
/* The values of state_QS will be polluted by the extra epilogues, however they are temporary values. */
/* Keep the C code here to help understand the intrinsics optimization. */
/*
{
opus_int32 state_QS[ 2 ][ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
opus_int32 *state_QST[ 3 ];
state_QST[ 0 ] = state_QS[ 0 ];
state_QST[ 1 ] = state_QS[ 1 ];
for( n = 0; n < length + order; n++, input_QS++ ) {
state_QST[ 0 ][ orderT ] = input_QS[ orderT ];
for( i = 0; i < orderT; i++ ) {
corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( state_QST[ 0 ][ i ], input_QS[ i ] ), 2 * QS - QC );
state_QST[ 1 ][ i ] = silk_SMLAWB( state_QST[ 1 ][ i + 1 ], state_QST[ 0 ][ i ] - state_QST[ 0 ][ i + 1 ], warping_Q16 );
}
state_QST[ 2 ] = state_QST[ 0 ];
state_QST[ 0 ] = state_QST[ 1 ];
state_QST[ 1 ] = state_QST[ 2 ];
}
}
*/
{
const int32x4_t warping_Q16_s32x4 = vdupq_n_s32( warping_Q16 << 15 );
const opus_int32 *in = input_QS + orderT;
opus_int o = orderT;
int32x4_t state_QS_s32x4[ 3 ][ 2 ];
ALLOC( state, length + orderT, opus_int32 );
state_QS_s32x4[ 2 ][ 1 ] = vdupq_n_s32( 0 );
/* Calculate 8 taps of all inputs in each loop. */
do {
state_QS_s32x4[ 0 ][ 0 ] = state_QS_s32x4[ 0 ][ 1 ] =
state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 1 ][ 1 ] = vdupq_n_s32( 0 );
n = 0;
do {
calc_corr( input_QS + n, corr_QC, o - 8, state_QS_s32x4[ 0 ][ 0 ] );
calc_corr( input_QS + n, corr_QC, o - 4, state_QS_s32x4[ 0 ][ 1 ] );
state_QS_s32x4[ 2 ][ 1 ] = vld1q_s32( in + n );
vst1q_lane_s32( state + n, state_QS_s32x4[ 0 ][ 0 ], 0 );
state_QS_s32x4[ 2 ][ 0 ] = vextq_s32( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 0 ][ 1 ], 1 );
state_QS_s32x4[ 2 ][ 1 ] = vextq_s32( state_QS_s32x4[ 0 ][ 1 ], state_QS_s32x4[ 2 ][ 1 ], 1 );
state_QS_s32x4[ 0 ][ 0 ] = calc_state( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], state_QS_s32x4[ 1 ][ 0 ], warping_Q16_s32x4 );
state_QS_s32x4[ 0 ][ 1 ] = calc_state( state_QS_s32x4[ 0 ][ 1 ], state_QS_s32x4[ 2 ][ 1 ], state_QS_s32x4[ 1 ][ 1 ], warping_Q16_s32x4 );
state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 2 ][ 0 ];
state_QS_s32x4[ 1 ][ 1 ] = state_QS_s32x4[ 2 ][ 1 ];
} while( ++n < ( length + order ) );
in = state;
o -= 8;
} while( o > 4 );
if( o ) {
/* Calculate the last 4 taps of all inputs. */
opus_int32 *stateT = state;
silk_assert( o == 4 );
state_QS_s32x4[ 0 ][ 0 ] = state_QS_s32x4[ 1 ][ 0 ] = vdupq_n_s32( 0 );
n = length + order;
do {
calc_corr( input_QS, corr_QC, 0, state_QS_s32x4[ 0 ][ 0 ] );
state_QS_s32x4[ 2 ][ 0 ] = vld1q_s32( stateT );
vst1q_lane_s32( stateT, state_QS_s32x4[ 0 ][ 0 ], 0 );
state_QS_s32x4[ 2 ][ 0 ] = vextq_s32( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], 1 );
state_QS_s32x4[ 0 ][ 0 ] = calc_state( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], state_QS_s32x4[ 1 ][ 0 ], warping_Q16_s32x4 );
state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 2 ][ 0 ];
input_QS++;
stateT++;
} while( --n );
}
}
{
const opus_int16 *inputT = input;
int32x4_t t_s32x4;
int64x1_t t_s64x1;
int64x2_t t_s64x2 = vdupq_n_s64( 0 );
for( n = 0; n <= length - 8; n += 8 ) {
int16x8_t input_s16x8 = vld1q_s16( inputT );
t_s32x4 = vmull_s16( vget_low_s16( input_s16x8 ), vget_low_s16( input_s16x8 ) );
t_s32x4 = vmlal_s16( t_s32x4, vget_high_s16( input_s16x8 ), vget_high_s16( input_s16x8 ) );
t_s64x2 = vaddw_s32( t_s64x2, vget_low_s32( t_s32x4 ) );
t_s64x2 = vaddw_s32( t_s64x2, vget_high_s32( t_s32x4 ) );
inputT += 8;
}
t_s64x1 = vadd_s64( vget_low_s64( t_s64x2 ), vget_high_s64( t_s64x2 ) );
corr_QC_orderT = vget_lane_s64( t_s64x1, 0 );
for( ; n < length; n++ ) {
corr_QC_orderT += silk_SMULL( input[ n ], input[ n ] );
}
corr_QC_orderT = silk_LSHIFT64( corr_QC_orderT, QC );
corr_QC[ orderT ] = corr_QC_orderT;
}
corr_QCT = corr_QC + orderT - order;
lsh = silk_CLZ64( corr_QC_orderT ) - 35;
lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC );
*scale = -( QC + lsh );
silk_assert( *scale >= -30 && *scale <= 12 );
lsh_s64x2 = vdupq_n_s64( lsh );
for( i = 0; i <= order - 3; i += 4 ) {
int32x4_t corr_s32x4;
int64x2_t corr_QC0_s64x2, corr_QC1_s64x2;
corr_QC0_s64x2 = vld1q_s64( corr_QCT + i );
corr_QC1_s64x2 = vld1q_s64( corr_QCT + i + 2 );
corr_QC0_s64x2 = vshlq_s64( corr_QC0_s64x2, lsh_s64x2 );
corr_QC1_s64x2 = vshlq_s64( corr_QC1_s64x2, lsh_s64x2 );
corr_s32x4 = vcombine_s32( vmovn_s64( corr_QC1_s64x2 ), vmovn_s64( corr_QC0_s64x2 ) );
corr_s32x4 = vrev64q_s32( corr_s32x4 );
vst1q_s32( corr + order - i - 3, corr_s32x4 );
}
if( lsh >= 0 ) {
for( ; i < order + 1; i++ ) {
corr[ order - i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QCT[ i ], lsh ) );
}
} else {
for( ; i < order + 1; i++ ) {
corr[ order - i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QCT[ i ], -lsh ) );
}
}
silk_assert( corr_QCT[ order ] >= 0 ); /* If breaking, decrease QC*/
RESTORE_STACK;
}
#ifdef OPUS_CHECK_ASM
{
opus_int32 corr_c[ MAX_SHAPE_LPC_ORDER + 1 ];
opus_int scale_c;
silk_warped_autocorrelation_FIX_c( corr_c, &scale_c, input, warping_Q16, length, order );
silk_assert( !memcmp( corr_c, corr, sizeof( corr_c[ 0 ] ) * ( order + 1 ) ) );
silk_assert( scale_c == *scale );
}
#endif
}

View file

@ -0,0 +1,48 @@
/***********************************************************************
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 "SigProc_FIX.h"
#include "celt_lpc.h"
/* Compute autocorrelation */
void silk_autocorr(
opus_int32 *results, /* O Result (length correlationCount) */
opus_int *scale, /* O Scaling of the correlation vector */
const opus_int16 *inputData, /* I Input data to correlate */
const opus_int inputDataSize, /* I Length of input */
const opus_int correlationCount, /* I Number of correlation taps to compute */
int arch /* I Run-time architecture */
)
{
opus_int corrCount;
corrCount = silk_min_int( inputDataSize, correlationCount );
*scale = _celt_autocorr(inputData, results, NULL, 0, corrCount-1, inputDataSize, arch);
}

View file

@ -0,0 +1,280 @@
/***********************************************************************
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 "SigProc_FIX.h"
#include "define.h"
#include "tuning_parameters.h"
#include "pitch.h"
#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
#define QA 25
#define N_BITS_HEAD_ROOM 3
#define MIN_RSHIFTS -16
#define MAX_RSHIFTS (32 - QA)
/* Compute reflection coefficients from input signal */
void silk_burg_modified_c(
opus_int32 *res_nrg, /* O Residual energy */
opus_int *res_nrg_Q, /* O Residual energy Q value */
opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
const opus_int nb_subfr, /* I Number of subframes stacked in x */
const opus_int D, /* I Order */
int arch /* I Run-time architecture */
)
{
opus_int k, n, s, lz, rshifts, reached_max_gain;
opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
const opus_int16 *x_ptr;
opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ];
opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ];
opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ];
opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ];
opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ];
opus_int32 xcorr[ SILK_MAX_ORDER_LPC ];
opus_int64 C0_64;
celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
/* Compute autocorrelations, added over subframes */
C0_64 = silk_inner_prod16_aligned_64( x, x, subfr_length*nb_subfr, arch );
lz = silk_CLZ64(C0_64);
rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz;
if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS;
if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS;
if (rshifts > 0) {
C0 = (opus_int32)silk_RSHIFT64(C0_64, rshifts );
} else {
C0 = silk_LSHIFT32((opus_int32)C0_64, -rshifts );
}
CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
if( rshifts > 0 ) {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
for( n = 1; n < D + 1; n++ ) {
C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64(
silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts );
}
}
} else {
for( s = 0; s < nb_subfr; s++ ) {
int i;
opus_int32 d;
x_ptr = x + s * subfr_length;
celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch );
for( n = 1; n < D + 1; n++ ) {
for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ )
d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] );
xcorr[ n - 1 ] += d;
}
for( n = 1; n < D + 1; n++ ) {
C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts );
}
}
}
silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
/* Initialize */
CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
invGain_Q30 = (opus_int32)1 << 30;
reached_max_gain = 0;
for( n = 0; n < D; n++ ) {
/* Update first row of correlation matrix (without first element) */
/* Update last row of correlation matrix (without last element, stored in reversed order) */
/* Update C * Af */
/* Update C * flipud(Af) (stored in reversed order) */
if( rshifts > -2 ) {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */
x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */
tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */
tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */
for( k = 0; k < n; k++ ) {
C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
Atmp_QA = Af_QA[ k ];
tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */
tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */
}
tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */
tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */
for( k = 0; k <= n; k++ ) {
CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */
CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */
}
}
} else {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */
x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */
tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */
tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */
for( k = 0; k < n; k++ ) {
C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */
/* We sometimes have get overflows in the multiplications (even beyond +/- 2^32),
but they cancel each other and the real result seems to always fit in a 32-bit
signed integer. This was determined experimentally, not theoretically (unfortunately). */
tmp1 = silk_MLA_ovflw( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */
tmp2 = silk_MLA_ovflw( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */
}
tmp1 = -tmp1; /* Q17 */
tmp2 = -tmp2; /* Q17 */
for( k = 0; k <= n; k++ ) {
CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1,
silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */
CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2,
silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */
}
}
}
/* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */
tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */
num = 0; /* Q( -rshifts ) */
nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */
for( k = 0; k < n; k++ ) {
Atmp_QA = Af_QA[ k ];
lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1;
lz = silk_min( 32 - QA, lz );
Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */
tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ),
Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */
}
CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */
CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */
num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */
num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */
/* Calculate the next order reflection (parcor) coefficient */
if( silk_abs( num ) < nrg ) {
rc_Q31 = silk_DIV32_varQ( num, nrg, 31 );
} else {
rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN;
}
/* Update inverse prediction gain */
tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 );
if( tmp1 <= minInvGain_Q30 ) {
/* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */
rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */
if( rc_Q31 > 0 ) {
/* Newton-Raphson iteration */
rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */
rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */
if( num < 0 ) {
/* Ensure adjusted reflection coefficients has the original sign */
rc_Q31 = -rc_Q31;
}
}
invGain_Q30 = minInvGain_Q30;
reached_max_gain = 1;
} else {
invGain_Q30 = tmp1;
}
/* Update the AR coefficients */
for( k = 0; k < (n + 1) >> 1; k++ ) {
tmp1 = Af_QA[ k ]; /* QA */
tmp2 = Af_QA[ n - k - 1 ]; /* QA */
Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */
Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */
}
Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */
if( reached_max_gain ) {
/* Reached max prediction gain; set remaining coefficients to zero and exit loop */
for( k = n + 1; k < D; k++ ) {
Af_QA[ k ] = 0;
}
break;
}
/* Update C * Af and C * Ab */
for( k = 0; k <= n + 1; k++ ) {
tmp1 = CAf[ k ]; /* Q( -rshifts ) */
tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */
CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */
CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */
}
}
if( reached_max_gain ) {
for( k = 0; k < D; k++ ) {
/* Scale coefficients */
A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );
}
/* Subtract energy of preceding samples from C0 */
if( rshifts > 0 ) {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts );
}
} else {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch), -rshifts);
}
}
/* Approximate residual energy */
*res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 );
*res_nrg_Q = -rshifts;
} else {
/* Return residual energy */
nrg = CAf[ 0 ]; /* Q( -rshifts ) */
tmp1 = (opus_int32)1 << 16; /* Q16 */
for( k = 0; k < D; k++ ) {
Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */
nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */
tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */
A_Q16[ k ] = -Atmp1;
}
*res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
*res_nrg_Q = -rshifts;
}
}

View file

@ -0,0 +1,150 @@
/***********************************************************************
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
/**********************************************************************
* Correlation Matrix Computations for LS estimate.
**********************************************************************/
#include "main_FIX.h"
/* Calculates correlation vector X'*t */
void silk_corrVector_FIX(
const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
const opus_int16 *t, /* I Target vector [L] */
const opus_int L, /* I Length of vectors */
const opus_int order, /* I Max lag for correlation */
opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */
const opus_int rshifts, /* I Right shifts of correlations */
int arch /* I Run-time architecture */
)
{
opus_int lag, i;
const opus_int16 *ptr1, *ptr2;
opus_int32 inner_prod;
ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */
ptr2 = t;
/* Calculate X'*t */
if( rshifts > 0 ) {
/* Right shifting used */
for( lag = 0; lag < order; lag++ ) {
inner_prod = 0;
for( i = 0; i < L; i++ ) {
inner_prod = silk_ADD_RSHIFT32( inner_prod, silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts );
}
Xt[ lag ] = inner_prod; /* X[:,lag]'*t */
ptr1--; /* Go to next column of X */
}
} else {
silk_assert( rshifts == 0 );
for( lag = 0; lag < order; lag++ ) {
Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); /* X[:,lag]'*t */
ptr1--; /* Go to next column of X */
}
}
}
/* Calculates correlation matrix X'*X */
void silk_corrMatrix_FIX(
const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
const opus_int L, /* I Length of vectors */
const opus_int order, /* I Max lag for correlation */
opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
opus_int32 *nrg, /* O Energy of x vector */
opus_int *rshifts, /* O Right shifts of correlations and energy */
int arch /* I Run-time architecture */
)
{
opus_int i, j, lag;
opus_int32 energy;
const opus_int16 *ptr1, *ptr2;
/* Calculate energy to find shift used to fit in 32 bits */
silk_sum_sqr_shift( nrg, rshifts, x, L + order - 1 );
energy = *nrg;
/* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */
/* Remove contribution of first order - 1 samples */
for( i = 0; i < order - 1; i++ ) {
energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), *rshifts );
}
/* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */
/* Fill out the diagonal of the correlation matrix */
matrix_ptr( XX, 0, 0, order ) = energy;
silk_assert( energy >= 0 );
ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */
for( j = 1; j < order; j++ ) {
energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), *rshifts ) );
energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), *rshifts ) );
matrix_ptr( XX, j, j, order ) = energy;
silk_assert( energy >= 0 );
}
ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */
/* Calculate the remaining elements of the correlation matrix */
if( *rshifts > 0 ) {
/* Right shifting used */
for( lag = 1; lag < order; lag++ ) {
/* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
energy = 0;
for( i = 0; i < L; i++ ) {
energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), *rshifts );
}
/* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
matrix_ptr( XX, lag, 0, order ) = energy;
matrix_ptr( XX, 0, lag, order ) = energy;
for( j = 1; j < ( order - lag ); j++ ) {
energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), *rshifts ) );
energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), *rshifts ) );
matrix_ptr( XX, lag + j, j, order ) = energy;
matrix_ptr( XX, j, lag + j, order ) = energy;
}
ptr2--; /* Update pointer to first sample of next column (lag) in X */
}
} else {
for( lag = 1; lag < order; lag++ ) {
/* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
energy = silk_inner_prod_aligned( ptr1, ptr2, L, arch );
matrix_ptr( XX, lag, 0, order ) = energy;
matrix_ptr( XX, 0, lag, order ) = energy;
/* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
for( j = 1; j < ( order - lag ); j++ ) {
energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) );
energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] );
matrix_ptr( XX, lag + j, j, order ) = energy;
matrix_ptr( XX, j, lag + j, order ) = energy;
}
ptr2--;/* Update pointer to first sample of next column (lag) in X */
}
}
}

View file

@ -0,0 +1,448 @@
/***********************************************************************
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 <stdlib.h>
#include "main_FIX.h"
#include "stack_alloc.h"
#include "tuning_parameters.h"
/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */
static OPUS_INLINE void silk_LBRR_encode_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */
const opus_int16 x16[], /* I Input signal */
opus_int condCoding /* I The type of conditional coding used so far for this frame */
);
void silk_encode_do_VAD_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
opus_int activity /* I Decision of Opus voice activity detector */
)
{
const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 );
/****************************/
/* Voice Activity Detection */
/****************************/
silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch );
/* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */
if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) {
psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1;
}
/**************************************************/
/* Convert speech activity into VAD and DTX flags */
/**************************************************/
if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) {
psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
psEnc->sCmn.noSpeechCounter++;
if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) {
psEnc->sCmn.inDTX = 0;
} else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) {
psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX;
psEnc->sCmn.inDTX = 0;
}
psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0;
} else {
psEnc->sCmn.noSpeechCounter = 0;
psEnc->sCmn.inDTX = 0;
psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
}
}
/****************/
/* Encode frame */
/****************/
opus_int silk_encode_frame_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */
ec_enc *psRangeEnc, /* I/O compressor data structure */
opus_int condCoding, /* I The type of conditional coding to use */
opus_int maxBits, /* I If > 0: maximum number of output bits */
opus_int useCBR /* I Flag to force constant-bitrate operation */
)
{
silk_encoder_control_FIX sEncCtrl;
opus_int i, iter, maxIter, found_upper, found_lower, ret = 0;
opus_int16 *x_frame;
ec_enc sRangeEnc_copy, sRangeEnc_copy2;
silk_nsq_state sNSQ_copy, sNSQ_copy2;
opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
opus_int32 gainsID, gainsID_lower, gainsID_upper;
opus_int16 gainMult_Q8;
opus_int16 ec_prevLagIndex_copy;
opus_int ec_prevSignalType_copy;
opus_int8 LastGainIndex_copy2;
opus_int gain_lock[ MAX_NB_SUBFR ] = {0};
opus_int16 best_gain_mult[ MAX_NB_SUBFR ];
opus_int best_sum[ MAX_NB_SUBFR ];
SAVE_STACK;
/* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
/**************************************************************/
/* Set up Input Pointers, and insert frame in input buffer */
/*************************************************************/
/* start of frame to encode */
x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length;
/***************************************/
/* Ensure smooth bandwidth transitions */
/***************************************/
silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
/*******************************************/
/* Copy new frame to front of input buffer */
/*******************************************/
silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) );
if( !psEnc->sCmn.prefillFlag ) {
VARDECL( opus_int16, res_pitch );
VARDECL( opus_uint8, ec_buf_copy );
opus_int16 *res_pitch_frame;
ALLOC( res_pitch,
psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length
+ psEnc->sCmn.ltp_mem_length, opus_int16 );
/* start of pitch LPC residual frame */
res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length;
/*****************************************/
/* Find pitch lags, initial LPC analysis */
/*****************************************/
silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame - psEnc->sCmn.ltp_mem_length, psEnc->sCmn.arch );
/************************/
/* Noise shape analysis */
/************************/
silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch );
/***************************************************/
/* Find linear prediction coefficients (LPC + LTP) */
/***************************************************/
silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding );
/****************************************/
/* Process gains */
/****************************************/
silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding );
/****************************************/
/* Low Bitrate Redundant Encoding */
/****************************************/
silk_LBRR_encode_FIX( psEnc, &sEncCtrl, x_frame, condCoding );
/* Loop over quantizer and entropy coding to control bitrate */
maxIter = 6;
gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
found_lower = 0;
found_upper = 0;
gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
gainsID_lower = -1;
gainsID_upper = -1;
/* Copy part of the input state */
silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
seed_copy = psEnc->sCmn.indices.Seed;
ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
ALLOC( ec_buf_copy, 1275, opus_uint8 );
for( iter = 0; ; iter++ ) {
if( gainsID == gainsID_lower ) {
nBits = nBits_lower;
} else if( gainsID == gainsID_upper ) {
nBits = nBits_upper;
} else {
/* Restore part of the input state */
if( iter > 0 ) {
silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
psEnc->sCmn.indices.Seed = seed_copy;
psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
}
/*****************************************/
/* Noise shaping quantization */
/*****************************************/
if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses,
sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14,
sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14,
psEnc->sCmn.arch );
} else {
silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses,
sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14,
sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14,
psEnc->sCmn.arch);
}
if ( iter == maxIter && !found_lower ) {
silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
}
/****************************************/
/* Encode Parameters */
/****************************************/
silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
/****************************************/
/* Encode Excitation Signal */
/****************************************/
silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
nBits = ec_tell( psRangeEnc );
/* If we still bust after the last iteration, do some damage control. */
if ( iter == maxIter && !found_lower && nBits > maxBits ) {
silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
/* Keep gains the same as the last frame. */
psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
psEnc->sCmn.indices.GainsIndices[ i ] = 4;
}
if (condCoding != CODE_CONDITIONALLY) {
psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev;
}
psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
/* Clear all pulses. */
for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) {
psEnc->sCmn.pulses[ i ] = 0;
}
silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
nBits = ec_tell( psRangeEnc );
}
if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
break;
}
}
if( iter == maxIter ) {
if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
/* Restore output state from earlier iteration that did meet the bitrate budget */
silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
celt_assert( sRangeEnc_copy2.offs <= 1275 );
silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
}
break;
}
if( nBits > maxBits ) {
if( found_lower == 0 && iter >= 2 ) {
/* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 );
found_upper = 0;
gainsID_upper = -1;
} else {
found_upper = 1;
nBits_upper = nBits;
gainMult_upper = gainMult_Q8;
gainsID_upper = gainsID;
}
} else if( nBits < maxBits - 5 ) {
found_lower = 1;
nBits_lower = nBits;
gainMult_lower = gainMult_Q8;
if( gainsID != gainsID_lower ) {
gainsID_lower = gainsID;
/* Copy part of the output state */
silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
celt_assert( psRangeEnc->offs <= 1275 );
silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
}
} else {
/* Within 5 bits of budget: close enough */
break;
}
if ( !found_lower && nBits > maxBits ) {
int j;
for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
int sum=0;
for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) {
sum += abs( psEnc->sCmn.pulses[j] );
}
if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) {
best_sum[i] = sum;
best_gain_mult[i] = gainMult_Q8;
} else {
gain_lock[i] = 1;
}
}
}
if( ( found_lower & found_upper ) == 0 ) {
/* Adjust gain according to high-rate rate/distortion curve */
if( nBits > maxBits ) {
if (gainMult_Q8 < 16384) {
gainMult_Q8 *= 2;
} else {
gainMult_Q8 = 32767;
}
} else {
opus_int32 gain_factor_Q16;
gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 );
}
} else {
/* Adjust gain by interpolating */
gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower );
/* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
} else
if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
}
}
for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
opus_int16 tmp;
if ( gain_lock[i] ) {
tmp = best_gain_mult[i];
} else {
tmp = gainMult_Q8;
}
sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 );
}
/* Quantize gains */
psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16,
&psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
/* Unique identifier of gains vector */
gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
}
}
/* Update input buffer */
silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) );
/* Exit without entropy coding */
if( psEnc->sCmn.prefillFlag ) {
/* No payload */
*pnBytesOut = 0;
RESTORE_STACK;
return ret;
}
/* Parameters needed for next frame */
psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ];
psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType;
/****************************************/
/* Finalize payload */
/****************************************/
psEnc->sCmn.first_frame_after_reset = 0;
/* Payload size */
*pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
RESTORE_STACK;
return ret;
}
/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */
static OPUS_INLINE void silk_LBRR_encode_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */
const opus_int16 x16[], /* I Input signal */
opus_int condCoding /* I The type of conditional coding used so far for this frame */
)
{
opus_int32 TempGains_Q16[ MAX_NB_SUBFR ];
SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ];
silk_nsq_state sNSQ_LBRR;
/*******************************************/
/* Control use of inband LBRR */
/*******************************************/
if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) {
psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
/* Copy noise shaping quantizer state and quantization indices from regular encoding */
silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) );
/* Save original gains */
silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) {
/* First frame in packet or previous frame not LBRR coded */
psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
/* Increase Gains to get target LBRR rate */
psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases;
psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 );
}
/* Decode to get gains in sync with decoder */
/* Overwrite unquantized gains with quantized gains */
silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices,
&psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
/*****************************************/
/* Noise shaping quantization */
/*****************************************/
if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16,
psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch );
} else {
silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16,
psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch );
}
/* Restore original gains */
silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
}
}

View file

@ -0,0 +1,151 @@
/***********************************************************************
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_FIX.h"
#include "stack_alloc.h"
#include "tuning_parameters.h"
/* Finds LPC vector from correlations, and converts to NLSF */
void silk_find_LPC_FIX(
silk_encoder_state *psEncC, /* I/O Encoder state */
opus_int16 NLSF_Q15[], /* O NLSFs */
const opus_int16 x[], /* I Input signal */
const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */
)
{
opus_int k, subfr_length;
opus_int32 a_Q16[ MAX_LPC_ORDER ];
opus_int isInterpLower, shift;
opus_int32 res_nrg0, res_nrg1;
opus_int rshift0, rshift1;
/* Used only for LSF interpolation */
opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg;
opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q;
opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ];
opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ];
SAVE_STACK;
subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder;
/* Default: no interpolation */
psEncC->indices.NLSFInterpCoef_Q2 = 4;
/* Burg AR analysis for the full frame */
silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch );
if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) {
VARDECL( opus_int16, LPC_res );
/* Optimal solution for last 10 ms */
silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch );
/* subtract residual energy here, as that's easier than adding it to the */
/* residual energy of the first 10 ms in each iteration of the search below */
shift = res_tmp_nrg_Q - res_nrg_Q;
if( shift >= 0 ) {
if( shift < 32 ) {
res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift );
}
} else {
silk_assert( shift > -32 );
res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg;
res_nrg_Q = res_tmp_nrg_Q;
}
/* Convert to NLSFs */
silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder );
ALLOC( LPC_res, 2 * subfr_length, opus_int16 );
/* Search over interpolation indices to find the one with lowest residual energy */
for( k = 3; k >= 0; k-- ) {
/* Interpolate NLSFs for first half */
silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder );
/* Convert to LPC for residual energy evaluation */
silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder, psEncC->arch );
/* Calculate residual energy with NLSF interpolation */
silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder, psEncC->arch );
silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder );
silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder );
/* Add subframe energies from first half frame */
shift = rshift0 - rshift1;
if( shift >= 0 ) {
res_nrg1 = silk_RSHIFT( res_nrg1, shift );
res_nrg_interp_Q = -rshift0;
} else {
res_nrg0 = silk_RSHIFT( res_nrg0, -shift );
res_nrg_interp_Q = -rshift1;
}
res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 );
/* Compare with first half energy without NLSF interpolation, or best interpolated value so far */
shift = res_nrg_interp_Q - res_nrg_Q;
if( shift >= 0 ) {
if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) {
isInterpLower = silk_TRUE;
} else {
isInterpLower = silk_FALSE;
}
} else {
if( -shift < 32 ) {
if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) {
isInterpLower = silk_TRUE;
} else {
isInterpLower = silk_FALSE;
}
} else {
isInterpLower = silk_FALSE;
}
}
/* Determine whether current interpolated NLSFs are best so far */
if( isInterpLower == silk_TRUE ) {
/* Interpolation has lower residual energy */
res_nrg = res_nrg_interp;
res_nrg_Q = res_nrg_interp_Q;
psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k;
}
}
}
if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) {
/* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder );
}
celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) );
RESTORE_STACK;
}

View file

@ -0,0 +1,99 @@
/***********************************************************************
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_FIX.h"
#include "tuning_parameters.h"
void silk_find_LTP_FIX(
opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */
opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */
const opus_int16 r_ptr[], /* I Residual signal after LPC */
const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
const opus_int subfr_length, /* I Subframe length */
const opus_int nb_subfr, /* I Number of subframes */
int arch /* I Run-time architecture */
)
{
opus_int i, k, extra_shifts;
opus_int xx_shifts, xX_shifts, XX_shifts;
const opus_int16 *lag_ptr;
opus_int32 *XXLTP_Q17_ptr, *xXLTP_Q17_ptr;
opus_int32 xx, nrg, temp;
xXLTP_Q17_ptr = xXLTP_Q17;
XXLTP_Q17_ptr = XXLTP_Q17;
for( k = 0; k < nb_subfr; k++ ) {
lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 );
silk_sum_sqr_shift( &xx, &xx_shifts, r_ptr, subfr_length + LTP_ORDER ); /* xx in Q( -xx_shifts ) */
silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, XXLTP_Q17_ptr, &nrg, &XX_shifts, arch ); /* XXLTP_Q17_ptr and nrg in Q( -XX_shifts ) */
extra_shifts = xx_shifts - XX_shifts;
if( extra_shifts > 0 ) {
/* Shift XX */
xX_shifts = xx_shifts;
for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) {
XXLTP_Q17_ptr[ i ] = silk_RSHIFT32( XXLTP_Q17_ptr[ i ], extra_shifts ); /* Q( -xX_shifts ) */
}
nrg = silk_RSHIFT32( nrg, extra_shifts ); /* Q( -xX_shifts ) */
} else if( extra_shifts < 0 ) {
/* Shift xx */
xX_shifts = XX_shifts;
xx = silk_RSHIFT32( xx, -extra_shifts ); /* Q( -xX_shifts ) */
} else {
xX_shifts = xx_shifts;
}
silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xXLTP_Q17_ptr, xX_shifts, arch ); /* xXLTP_Q17_ptr in Q( -xX_shifts ) */
/* At this point all correlations are in Q(-xX_shifts) */
temp = silk_SMLAWB( 1, nrg, SILK_FIX_CONST( LTP_CORR_INV_MAX, 16 ) );
temp = silk_max( temp, xx );
TIC(div)
#if 0
for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) {
XXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( XXLTP_Q17_ptr[ i ], temp, 17 );
}
for( i = 0; i < LTP_ORDER; i++ ) {
xXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( xXLTP_Q17_ptr[ i ], temp, 17 );
}
#else
for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) {
XXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)XXLTP_Q17_ptr[ i ], 17 ) / temp );
}
for( i = 0; i < LTP_ORDER; i++ ) {
xXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)xXLTP_Q17_ptr[ i ], 17 ) / temp );
}
#endif
TOC(div)
r_ptr += subfr_length;
XXLTP_Q17_ptr += LTP_ORDER * LTP_ORDER;
xXLTP_Q17_ptr += LTP_ORDER;
}
}

View file

@ -0,0 +1,143 @@
/***********************************************************************
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_FIX.h"
#include "stack_alloc.h"
#include "tuning_parameters.h"
/* Find pitch lags */
void silk_find_pitch_lags_FIX(
silk_encoder_state_FIX *psEnc, /* I/O encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
opus_int16 res[], /* O residual */
const opus_int16 x[], /* I Speech signal */
int arch /* I Run-time architecture */
)
{
opus_int buf_len, i, scale;
opus_int32 thrhld_Q13, res_nrg;
const opus_int16 *x_ptr;
VARDECL( opus_int16, Wsig );
opus_int16 *Wsig_ptr;
opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ];
opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ];
opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ];
opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ];
SAVE_STACK;
/******************************************/
/* Set up buffer lengths etc based on Fs */
/******************************************/
buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length;
/* Safety check */
celt_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length );
/*************************************/
/* Estimate LPC AR coefficients */
/*************************************/
/* Calculate windowed signal */
ALLOC( Wsig, psEnc->sCmn.pitch_LPC_win_length, opus_int16 );
/* First LA_LTP samples */
x_ptr = x + buf_len - psEnc->sCmn.pitch_LPC_win_length;
Wsig_ptr = Wsig;
silk_apply_sine_window( Wsig_ptr, x_ptr, 1, psEnc->sCmn.la_pitch );
/* Middle un - windowed samples */
Wsig_ptr += psEnc->sCmn.la_pitch;
x_ptr += psEnc->sCmn.la_pitch;
silk_memcpy( Wsig_ptr, x_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) );
/* Last LA_LTP samples */
Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
x_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
silk_apply_sine_window( Wsig_ptr, x_ptr, 2, psEnc->sCmn.la_pitch );
/* Calculate autocorrelation sequence */
silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1, arch );
/* Add white noise, as fraction of energy */
auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1;
/* Calculate the reflection coefficients using schur */
res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder );
/* Prediction gain */
psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 );
/* Convert reflection coefficients to prediction coefficients */
silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder );
/* Convert From 32 bit Q24 to 16 bit Q12 coefs */
for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) {
A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) );
}
/* Do BWE */
silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) );
/*****************************************/
/* LPC analysis filtering */
/*****************************************/
silk_LPC_analysis_filter( res, x, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder, psEnc->sCmn.arch );
if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) {
/* Threshold for pitch estimator */
thrhld_Q13 = SILK_FIX_CONST( 0.6, 13 );
thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.004, 13 ), psEnc->sCmn.pitchEstimationLPCOrder );
thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 21 ), psEnc->sCmn.speech_activity_Q8 );
thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.15, 13 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) );
thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 14 ), psEnc->sCmn.input_tilt_Q15 );
thrhld_Q13 = silk_SAT16( thrhld_Q13 );
/*****************************************/
/* Call pitch estimator */
/*****************************************/
if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex,
&psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16,
(opus_int)thrhld_Q13, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr,
psEnc->sCmn.arch) == 0 )
{
psEnc->sCmn.indices.signalType = TYPE_VOICED;
} else {
psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
}
} else {
silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) );
psEnc->sCmn.indices.lagIndex = 0;
psEnc->sCmn.indices.contourIndex = 0;
psEnc->LTPCorr_Q15 = 0;
}
RESTORE_STACK;
}

View file

@ -0,0 +1,145 @@
/***********************************************************************
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_FIX.h"
#include "stack_alloc.h"
void silk_find_pred_coefs_FIX(
silk_encoder_state_FIX *psEnc, /* I/O encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
const opus_int16 res_pitch[], /* I Residual from pitch analysis */
const opus_int16 x[], /* I Speech signal */
opus_int condCoding /* I The type of conditional coding to use */
)
{
opus_int i;
opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ];
opus_int16 NLSF_Q15[ MAX_LPC_ORDER ];
const opus_int16 *x_ptr;
opus_int16 *x_pre_ptr;
VARDECL( opus_int16, LPC_in_pre );
opus_int32 min_gain_Q16, minInvGain_Q30;
SAVE_STACK;
/* weighting for weighted least squares */
min_gain_Q16 = silk_int32_MAX >> 6;
for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] );
}
for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
/* Divide to Q16 */
silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 );
/* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */
invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 );
/* Limit inverse */
invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 100 );
/* Square the inverted gains */
silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) );
/* Invert the inverted and normalized gains */
local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] );
}
ALLOC( LPC_in_pre,
psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder
+ psEnc->sCmn.frame_length, opus_int16 );
if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
VARDECL( opus_int32, xXLTP_Q17 );
VARDECL( opus_int32, XXLTP_Q17 );
/**********/
/* VOICED */
/**********/
celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 );
ALLOC( xXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER, opus_int32 );
ALLOC( XXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 );
/* LTP analysis */
silk_find_LTP_FIX( XXLTP_Q17, xXLTP_Q17, res_pitch,
psEncCtrl->pitchL, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch );
/* Quantize LTP gain parameters */
silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex,
&psEnc->sCmn.sum_log_gain_Q7, &psEncCtrl->LTPredCodGain_Q7, XXLTP_Q17, xXLTP_Q17, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch );
/* Control LTP scaling */
silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding );
/* Create LTP residual */
silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14,
psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
} else {
/************/
/* UNVOICED */
/************/
/* Create signal with prepended subframes, scaled by inverse gains */
x_ptr = x - psEnc->sCmn.predictLPCOrder;
x_pre_ptr = LPC_in_pre;
for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ],
psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder );
x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder;
x_ptr += psEnc->sCmn.subfr_length;
}
silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) );
psEncCtrl->LTPredCodGain_Q7 = 0;
psEnc->sCmn.sum_log_gain_Q7 = 0;
}
/* Limit on total predictive coding gain */
if( psEnc->sCmn.first_frame_after_reset ) {
minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 );
} else {
minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */
minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30,
silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ),
silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 );
}
/* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 );
/* Quantize LSFs */
silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 );
/* Calculate residual energy using quantized LPC coefficients */
silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains,
psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.arch );
/* Copy to prediction struct for use in next frame for interpolation */
silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
RESTORE_STACK;
}

View file

@ -0,0 +1,54 @@
/***********************************************************************
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 "SigProc_FIX.h"
/* Step up function, converts reflection coefficients to prediction coefficients */
void silk_k2a(
opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */
const opus_int32 order /* I Prediction order */
)
{
opus_int k, n;
opus_int32 rc, tmp1, tmp2;
for( k = 0; k < order; k++ ) {
rc = rc_Q15[ k ];
for( n = 0; n < (k + 1) >> 1; n++ ) {
tmp1 = A_Q24[ n ];
tmp2 = A_Q24[ k - n - 1 ];
A_Q24[ n ] = silk_SMLAWB( tmp1, silk_LSHIFT( tmp2, 1 ), rc );
A_Q24[ k - n - 1 ] = silk_SMLAWB( tmp2, silk_LSHIFT( tmp1, 1 ), rc );
}
A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 );
}
}

View file

@ -0,0 +1,54 @@
/***********************************************************************
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 "SigProc_FIX.h"
/* Step up function, converts reflection coefficients to prediction coefficients */
void silk_k2a_Q16(
opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */
const opus_int32 order /* I Prediction order */
)
{
opus_int k, n;
opus_int32 rc, tmp1, tmp2;
for( k = 0; k < order; k++ ) {
rc = rc_Q16[ k ];
for( n = 0; n < (k + 1) >> 1; n++ ) {
tmp1 = A_Q24[ n ];
tmp2 = A_Q24[ k - n - 1 ];
A_Q24[ n ] = silk_SMLAWW( tmp1, tmp2, rc );
A_Q24[ k - n - 1 ] = silk_SMLAWW( tmp2, tmp1, rc );
}
A_Q24[ k ] = -silk_LSHIFT( rc, 8 );
}
}

View file

@ -0,0 +1,244 @@
/***********************************************************************
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.
***********************************************************************/
#ifndef SILK_MAIN_FIX_H
#define SILK_MAIN_FIX_H
#include "SigProc_FIX.h"
#include "structs_FIX.h"
#include "control.h"
#include "main.h"
#include "PLC.h"
#include "debug.h"
#include "entenc.h"
#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \
|| defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
#include "fixed/arm/warped_autocorrelation_FIX_arm.h"
#endif
#ifndef FORCE_CPP_BUILD
#ifdef __cplusplus
extern "C"
{
#endif
#endif
#define silk_encoder_state_Fxx silk_encoder_state_FIX
#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX
#define silk_encode_frame_Fxx silk_encode_frame_FIX
#define QC 10
#define QS 13
/*********************/
/* Encoder Functions */
/*********************/
/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
void silk_HP_variable_cutoff(
silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
);
/* Encoder main function */
void silk_encode_do_VAD_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
opus_int activity /* I Decision of Opus voice activity detector */
);
/* Encoder main function */
opus_int silk_encode_frame_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */
ec_enc *psRangeEnc, /* I/O compressor data structure */
opus_int condCoding, /* I The type of conditional coding to use */
opus_int maxBits, /* I If > 0: maximum number of output bits */
opus_int useCBR /* I Flag to force constant-bitrate operation */
);
/* Initializes the Silk encoder state */
opus_int silk_init_encoder(
silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */
int arch /* I Run-time architecture */
);
/* Control the Silk encoder */
opus_int silk_control_encoder(
silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
silk_EncControlStruct *encControl, /* I Control structure */
const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
const opus_int channelNb, /* I Channel number */
const opus_int force_fs_kHz
);
/**************************/
/* Noise shaping analysis */
/**************************/
/* Compute noise shaping coefficients and initial gain values */
void silk_noise_shape_analysis_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */
silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */
const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */
const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */
int arch /* I Run-time architecture */
);
/* Autocorrelations for a warped frequency axis */
void silk_warped_autocorrelation_FIX_c(
opus_int32 *corr, /* O Result [order + 1] */
opus_int *scale, /* O Scaling of the correlation vector */
const opus_int16 *input, /* I Input data to correlate */
const opus_int warping_Q16, /* I Warping coefficient */
const opus_int length, /* I Length of input */
const opus_int order /* I Correlation order (even) */
);
#if !defined(OVERRIDE_silk_warped_autocorrelation_FIX)
#define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \
((void)(arch), silk_warped_autocorrelation_FIX_c(corr, scale, input, warping_Q16, length, order))
#endif
/* Calculation of LTP state scaling */
void silk_LTP_scale_ctrl_FIX(
silk_encoder_state_FIX *psEnc, /* I/O encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
opus_int condCoding /* I The type of conditional coding to use */
);
/**********************************************/
/* Prediction Analysis */
/**********************************************/
/* Find pitch lags */
void silk_find_pitch_lags_FIX(
silk_encoder_state_FIX *psEnc, /* I/O encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
opus_int16 res[], /* O residual */
const opus_int16 x[], /* I Speech signal */
int arch /* I Run-time architecture */
);
/* Find LPC and LTP coefficients */
void silk_find_pred_coefs_FIX(
silk_encoder_state_FIX *psEnc, /* I/O encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
const opus_int16 res_pitch[], /* I Residual from pitch analysis */
const opus_int16 x[], /* I Speech signal */
opus_int condCoding /* I The type of conditional coding to use */
);
/* LPC analysis */
void silk_find_LPC_FIX(
silk_encoder_state *psEncC, /* I/O Encoder state */
opus_int16 NLSF_Q15[], /* O NLSFs */
const opus_int16 x[], /* I Input signal */
const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */
);
/* LTP analysis */
void silk_find_LTP_FIX(
opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */
opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */
const opus_int16 r_lpc[], /* I Residual signal after LPC */
const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
const opus_int subfr_length, /* I Subframe length */
const opus_int nb_subfr, /* I Number of subframes */
int arch /* I Run-time architecture */
);
void silk_LTP_analysis_filter_FIX(
opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */
const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */
const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */
const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */
const opus_int subfr_length, /* I Length of each subframe */
const opus_int nb_subfr, /* I Number of subframes */
const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */
);
/* Calculates residual energies of input subframes where all subframes have LPC_order */
/* of preceding samples */
void silk_residual_energy_FIX(
opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */
const opus_int16 x[], /* I Input signal */
opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */
const opus_int subfr_length, /* I Subframe length */
const opus_int nb_subfr, /* I Number of subframes */
const opus_int LPC_order, /* I LPC order */
int arch /* I Run-time architecture */
);
/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
opus_int32 silk_residual_energy16_covar_FIX(
const opus_int16 *c, /* I Prediction vector */
const opus_int32 *wXX, /* I Correlation matrix */
const opus_int32 *wXx, /* I Correlation vector */
opus_int32 wxx, /* I Signal energy */
opus_int D, /* I Dimension */
opus_int cQ /* I Q value for c vector 0 - 15 */
);
/* Processing of gains */
void silk_process_gains_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */
opus_int condCoding /* I The type of conditional coding to use */
);
/******************/
/* Linear Algebra */
/******************/
/* Calculates correlation matrix X'*X */
void silk_corrMatrix_FIX(
const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
const opus_int L, /* I Length of vectors */
const opus_int order, /* I Max lag for correlation */
opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
opus_int32 *nrg, /* O Energy of x vector */
opus_int *rshifts, /* O Right shifts of correlations */
int arch /* I Run-time architecture */
);
/* Calculates correlation vector X'*t */
void silk_corrVector_FIX(
const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
const opus_int16 *t, /* I Target vector [L] */
const opus_int L, /* I Length of vectors */
const opus_int order, /* I Max lag for correlation */
opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */
const opus_int rshifts, /* I Right shifts of correlations */
int arch /* I Run-time architecture */
);
#ifndef FORCE_CPP_BUILD
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* FORCE_CPP_BUILD */
#endif /* SILK_MAIN_FIX_H */

View file

@ -0,0 +1,336 @@
/***********************************************************************
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.
***********************************************************************/
/**************************************************************/
/* Compute noise shaping coefficients and initial gain values */
/**************************************************************/
#define OVERRIDE_silk_noise_shape_analysis_FIX
void silk_noise_shape_analysis_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */
silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */
const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */
const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */
int arch /* I Run-time architecture */
)
{
silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
opus_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0;
opus_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32;
opus_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
opus_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;
opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ];
opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ];
opus_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ];
opus_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ];
VARDECL( opus_int16, x_windowed );
const opus_int16 *x_ptr, *pitch_res_ptr;
SAVE_STACK;
/* Point to start of first LPC analysis block */
x_ptr = x - psEnc->sCmn.la_shape;
/****************/
/* GAIN CONTROL */
/****************/
SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7;
/* Input quality is the average of the quality in the lowest two VAD bands */
psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ]
+ psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 );
/* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 -
SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 );
/* Reduce coding SNR during low speech activity */
if( psEnc->sCmn.useCBR == 0 ) {
b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8;
b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 );
SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/
silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/
}
if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
/* Reduce gains for periodic signals */
SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 );
} else {
/* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ),
SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 );
}
/*************************/
/* SPARSENESS PROCESSING */
/*************************/
/* Set quantizer offset */
if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
/* Initially set to 0; may be overruled in process_gains(..) */
psEnc->sCmn.indices.quantOffsetType = 0;
psEncCtrl->sparseness_Q8 = 0;
} else {
/* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 );
energy_variation_Q7 = 0;
log_energy_prev_Q7 = 0;
pitch_res_ptr = pitch_res;
for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) {
silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples );
nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/
log_energy_Q7 = silk_lin2log( nrg );
if( k > 0 ) {
energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 );
}
log_energy_prev_Q7 = log_energy_Q7;
pitch_res_ptr += nSamples;
}
psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 -
SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 );
/* Set quantization offset depending on sparseness measure */
if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) {
psEnc->sCmn.indices.quantOffsetType = 0;
} else {
psEnc->sCmn.indices.quantOffsetType = 1;
}
/* Increase coding SNR for sparse signals */
SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) );
}
/*******************************/
/* Control bandwidth expansion */
/*******************************/
/* More BWE for signals with high prediction gain */
strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) );
BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ),
silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 );
delta_Q16 = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ),
SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) );
BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 );
BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 );
/* BWExp1 will be applied after BWExp2, so make it relative */
BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_RSHIFT( BWExp2_Q16, 2 ) );
if( psEnc->sCmn.warping_Q16 > 0 ) {
/* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) );
} else {
warping_Q16 = 0;
}
/********************************************/
/* Compute noise shaping AR coefs and gains */
/********************************************/
ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 );
for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
/* Apply window: sine slope followed by flat part followed by cosine slope */
opus_int shift, slope_part, flat_part;
flat_part = psEnc->sCmn.fs_kHz * 3;
slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 );
silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part );
shift = slope_part;
silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) );
shift += flat_part;
silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part );
/* Update pointer: next LPC analysis block */
x_ptr += psEnc->sCmn.subfr_length;
if( psEnc->sCmn.warping_Q16 > 0 ) {
/* Calculate warped auto correlation */
silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch );
} else {
/* Calculate regular auto correlation */
silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch );
}
/* Add white noise, as a fraction of energy */
auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ),
SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) );
/* Calculate the reflection coefficients using schur */
nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder );
silk_assert( nrg >= 0 );
/* Convert reflection coefficients to prediction coefficients */
silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder );
Qnrg = -scale; /* range: -12...30*/
silk_assert( Qnrg >= -12 );
silk_assert( Qnrg <= 30 );
/* Make sure that Qnrg is an even number */
if( Qnrg & 1 ) {
Qnrg -= 1;
nrg >>= 1;
}
tmp32 = silk_SQRT_APPROX( nrg );
Qnrg >>= 1; /* range: -6...15*/
psEncCtrl->Gains_Q16[ k ] = (silk_LSHIFT32( silk_LIMIT( (tmp32), silk_RSHIFT32( silk_int32_MIN, (16 - Qnrg) ), \
silk_RSHIFT32( silk_int32_MAX, (16 - Qnrg) ) ), (16 - Qnrg) ));
if( psEnc->sCmn.warping_Q16 > 0 ) {
/* Adjust gain for warping */
gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder );
silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
if ( silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ) >= ( silk_int32_MAX >> 1 ) ) {
psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX;
} else {
psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
}
}
/* Bandwidth expansion for synthesis filter shaping */
silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 );
/* Compute noise shaping filter coefficients */
silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) );
/* Bandwidth expansion for analysis filter shaping */
silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) );
silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 );
/* Ratio of prediction gains, in energy domain */
pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder, arch );
nrg = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder, arch );
/*psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/
pre_nrg_Q30 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 );
psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_DIV32_varQ( pre_nrg_Q30, nrg, 14 );
/* Convert to monic warped prediction coefficients and limit absolute values */
limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder );
/* Convert from Q24 to Q13 and store in int16 */
for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) {
psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) );
psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) );
}
}
/*****************/
/* Gain tweaking */
/*****************/
/* Increase gains during low speech activity and put lower limit on gains */
gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) );
gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) );
silk_assert( gain_mult_Q16 > 0 );
for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 );
}
gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ),
psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 );
for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] );
}
/************************************************/
/* Control low-frequency shaping and noise tilt */
/************************************************/
/* Less low frequency shaping for noisy inputs */
strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ),
SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) );
strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 );
if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
/* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
/*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz );
for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] );
/* Pack two coefficients in one int32 */
psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 );
psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
}
silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/
Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) -
silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ),
silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) );
} else {
b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/
/* Pack two coefficients in one int32 */
psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 -
silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 );
psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ];
}
Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 );
}
/****************************/
/* HARMONIC SHAPING CONTROL */
/****************************/
/* Control boosting of harmonic frequencies */
HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ),
psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) );
/* More harmonic boost for noisy input signals */
HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16,
SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) );
if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
/* More harmonic noise shaping for high bitrates or noisy input */
HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ),
SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ),
psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) );
/* Less harmonic noise shaping for less periodic signals */
HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ),
silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) );
} else {
HarmShapeGain_Q16 = 0;
}
/*************************/
/* Smooth over subframes */
/*************************/
for( k = 0; k < MAX_NB_SUBFR; k++ ) {
psShapeSt->HarmBoost_smth_Q16 =
silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
psShapeSt->HarmShapeGain_smth_Q16 =
silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
psShapeSt->Tilt_smth_Q16 =
silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
psEncCtrl->HarmBoost_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 );
psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 );
psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 );
}
RESTORE_STACK;
}

View file

@ -0,0 +1,184 @@
/***********************************************************************
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.
***********************************************************************/
#ifndef __PREFILTER_FIX_MIPSR1_H__
#define __PREFILTER_FIX_MIPSR1_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "main_FIX.h"
#include "stack_alloc.h"
#include "tuning_parameters.h"
#define OVERRIDE_silk_warped_LPC_analysis_filter_FIX
void silk_warped_LPC_analysis_filter_FIX(
opus_int32 state[], /* I/O State [order + 1] */
opus_int32 res_Q2[], /* O Residual signal [length] */
const opus_int16 coef_Q13[], /* I Coefficients [order] */
const opus_int16 input[], /* I Input signal [length] */
const opus_int16 lambda_Q16, /* I Warping factor */
const opus_int length, /* I Length of input signal */
const opus_int order, /* I Filter order (even) */
int arch
)
{
opus_int n, i;
opus_int32 acc_Q11, acc_Q22, tmp1, tmp2, tmp3, tmp4;
opus_int32 state_cur, state_next;
(void)arch;
/* Order must be even */
/* Length must be even */
silk_assert( ( order & 1 ) == 0 );
silk_assert( ( length & 1 ) == 0 );
for( n = 0; n < length; n+=2 ) {
/* Output of lowpass section */
tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 );
state_cur = silk_LSHIFT( input[ n ], 14 );
/* Output of allpass section */
tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 );
state_next = tmp2;
acc_Q11 = silk_RSHIFT( order, 1 );
acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] );
/* Output of lowpass section */
tmp4 = silk_SMLAWB( state_cur, state_next, lambda_Q16 );
state[ 0 ] = silk_LSHIFT( input[ n+1 ], 14 );
/* Output of allpass section */
tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 );
state[ 1 ] = tmp4;
acc_Q22 = silk_RSHIFT( order, 1 );
acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ 0 ] );
/* Loop over allpass sections */
for( i = 2; i < order; i += 2 ) {
/* Output of allpass section */
tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 );
state_cur = tmp1;
acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] );
/* Output of allpass section */
tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 );
state_next = tmp2;
acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] );
/* Output of allpass section */
tmp4 = silk_SMLAWB( state_cur, state_next - tmp3, lambda_Q16 );
state[ i ] = tmp3;
acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ i - 1 ] );
/* Output of allpass section */
tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 );
state[ i + 1 ] = tmp4;
acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ i ] );
}
acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] );
res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 );
state[ order ] = tmp3;
acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ order - 1 ] );
res_Q2[ n+1 ] = silk_LSHIFT( (opus_int32)input[ n+1 ], 2 ) - silk_RSHIFT_ROUND( acc_Q22, 9 );
}
}
/* Prefilter for finding Quantizer input signal */
#define OVERRIDE_silk_prefilt_FIX
static inline void silk_prefilt_FIX(
silk_prefilter_state_FIX *P, /* I/O state */
opus_int32 st_res_Q12[], /* I short term residual signal */
opus_int32 xw_Q3[], /* O prefiltered signal */
opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */
opus_int Tilt_Q14, /* I Tilt shaping coeficient */
opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */
opus_int lag, /* I Lag for harmonic shaping */
opus_int length /* I Length of signals */
)
{
opus_int i, idx, LTP_shp_buf_idx;
opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10;
opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12;
opus_int16 *LTP_shp_buf;
/* To speed up use temp variables instead of using the struct */
LTP_shp_buf = P->sLTP_shp;
LTP_shp_buf_idx = P->sLTP_shp_buf_idx;
sLF_AR_shp_Q12 = P->sLF_AR_shp_Q12;
sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12;
if( lag > 0 ) {
for( i = 0; i < length; i++ ) {
/* unrolled loop */
silk_assert( HARM_SHAPE_FIR_TAPS == 3 );
idx = lag + LTP_shp_buf_idx;
n_LTP_Q12 = silk_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
n_LTP_Q12 = silk_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 );
n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 );
sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) );
sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) );
LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) );
xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 );
}
}
else
{
for( i = 0; i < length; i++ ) {
n_LTP_Q12 = 0;
n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 );
n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 );
sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) );
sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) );
LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) );
xw_Q3[i] = silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 9 );
}
}
/* Copy temp variable back to state */
P->sLF_AR_shp_Q12 = sLF_AR_shp_Q12;
P->sLF_MA_shp_Q12 = sLF_MA_shp_Q12;
P->sLTP_shp_buf_idx = LTP_shp_buf_idx;
}
#endif /* __PREFILTER_FIX_MIPSR1_H__ */

View file

@ -0,0 +1,166 @@
/***********************************************************************
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.
***********************************************************************/
#ifndef __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__
#define __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "main_FIX.h"
#undef QC
#define QC 10
#undef QS
#define QS 14
/* Autocorrelations for a warped frequency axis */
#define OVERRIDE_silk_warped_autocorrelation_FIX
void silk_warped_autocorrelation_FIX(
opus_int32 *corr, /* O Result [order + 1] */
opus_int *scale, /* O Scaling of the correlation vector */
const opus_int16 *input, /* I Input data to correlate */
const opus_int warping_Q16, /* I Warping coefficient */
const opus_int length, /* I Length of input */
const opus_int order, /* I Correlation order (even) */
int arch /* I Run-time architecture */
)
{
opus_int n, i, lsh;
opus_int32 tmp1_QS=0, tmp2_QS=0, tmp3_QS=0, tmp4_QS=0, tmp5_QS=0, tmp6_QS=0, tmp7_QS=0, tmp8_QS=0, start_1=0, start_2=0, start_3=0;
opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
opus_int64 temp64;
opus_int32 val;
val = 2 * QS - QC;
/* Order must be even */
silk_assert( ( order & 1 ) == 0 );
silk_assert( 2 * QS - QC >= 0 );
/* Loop over samples */
for( n = 0; n < length; n=n+4 ) {
tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
start_1 = tmp1_QS;
tmp3_QS = silk_LSHIFT32( (opus_int32)input[ n+1], QS );
start_2 = tmp3_QS;
tmp5_QS = silk_LSHIFT32( (opus_int32)input[ n+2], QS );
start_3 = tmp5_QS;
tmp7_QS = silk_LSHIFT32( (opus_int32)input[ n+3], QS );
/* Loop over allpass sections */
for( i = 0; i < order; i += 2 ) {
/* Output of allpass section */
tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp1_QS, start_1);
tmp4_QS = silk_SMLAWB( tmp1_QS, tmp2_QS - tmp3_QS, warping_Q16 );
corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp3_QS, start_2);
tmp6_QS = silk_SMLAWB( tmp3_QS, tmp4_QS - tmp5_QS, warping_Q16 );
corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp5_QS, start_3);
tmp8_QS = silk_SMLAWB( tmp5_QS, tmp6_QS - tmp7_QS, warping_Q16 );
state_QS[ i ] = tmp7_QS;
corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp7_QS, state_QS[0]);
/* Output of allpass section */
tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp2_QS, start_1);
tmp3_QS = silk_SMLAWB( tmp2_QS, tmp1_QS - tmp4_QS, warping_Q16 );
corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp4_QS, start_2);
tmp5_QS = silk_SMLAWB( tmp4_QS, tmp3_QS - tmp6_QS, warping_Q16 );
corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp6_QS, start_3);
tmp7_QS = silk_SMLAWB( tmp6_QS, tmp5_QS - tmp8_QS, warping_Q16 );
state_QS[ i + 1 ] = tmp8_QS;
corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp8_QS, state_QS[ 0 ]);
}
state_QS[ order ] = tmp7_QS;
corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp1_QS, start_1);
corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp3_QS, start_2);
corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp5_QS, start_3);
corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp7_QS, state_QS[ 0 ]);
}
for(;n< length; n++ ) {
tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
/* Loop over allpass sections */
for( i = 0; i < order; i += 2 ) {
/* Output of allpass section */
tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
state_QS[ i ] = tmp1_QS;
corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp1_QS, state_QS[ 0 ]);
/* Output of allpass section */
tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
state_QS[ i + 1 ] = tmp2_QS;
corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp2_QS, state_QS[ 0 ]);
}
state_QS[ order ] = tmp1_QS;
corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp1_QS, state_QS[ 0 ]);
}
temp64 = corr_QC[ 0 ];
temp64 = __builtin_mips_shilo(temp64, val);
lsh = silk_CLZ64( temp64 ) - 35;
lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC );
*scale = -( QC + lsh );
silk_assert( *scale >= -30 && *scale <= 12 );
if( lsh >= 0 ) {
for( i = 0; i < order + 1; i++ ) {
temp64 = corr_QC[ i ];
//temp64 = __builtin_mips_shilo(temp64, val);
temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val);
corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) );
}
} else {
for( i = 0; i < order + 1; i++ ) {
temp64 = corr_QC[ i ];
//temp64 = __builtin_mips_shilo(temp64, val);
temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val);
corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) );
}
}
corr_QC[ 0 ] = __builtin_mips_shilo(corr_QC[ 0 ], val);
silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
}
#endif /* __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ */

View file

@ -0,0 +1,407 @@
/***********************************************************************
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_FIX.h"
#include "stack_alloc.h"
#include "tuning_parameters.h"
/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */
/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
/* coefficient in an array of coefficients, for monic filters. */
static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/
const opus_int32 *coefs_Q24,
opus_int lambda_Q16,
opus_int order
) {
opus_int i;
opus_int32 gain_Q24;
lambda_Q16 = -lambda_Q16;
gain_Q24 = coefs_Q24[ order - 1 ];
for( i = order - 2; i >= 0; i-- ) {
gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 );
}
gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 );
return silk_INVERSE32_varQ( gain_Q24, 40 );
}
/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */
/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
static OPUS_INLINE void limit_warped_coefs(
opus_int32 *coefs_Q24,
opus_int lambda_Q16,
opus_int32 limit_Q24,
opus_int order
) {
opus_int i, iter, ind = 0;
opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_Q16;
opus_int32 nom_Q16, den_Q24;
opus_int32 limit_Q20, maxabs_Q20;
/* Convert to monic coefficients */
lambda_Q16 = -lambda_Q16;
for( i = order - 1; i > 0; i-- ) {
coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 );
}
lambda_Q16 = -lambda_Q16;
nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 );
den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 );
gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
for( i = 0; i < order; i++ ) {
coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] );
}
limit_Q20 = silk_RSHIFT(limit_Q24, 4);
for( iter = 0; iter < 10; iter++ ) {
/* Find maximum absolute value */
maxabs_Q24 = -1;
for( i = 0; i < order; i++ ) {
tmp = silk_abs_int32( coefs_Q24[ i ] );
if( tmp > maxabs_Q24 ) {
maxabs_Q24 = tmp;
ind = i;
}
}
/* Use Q20 to avoid any overflow when multiplying by (ind + 1) later. */
maxabs_Q20 = silk_RSHIFT(maxabs_Q24, 4);
if( maxabs_Q20 <= limit_Q20 ) {
/* Coefficients are within range - done */
return;
}
/* Convert back to true warped coefficients */
for( i = 1; i < order; i++ ) {
coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 );
}
gain_Q16 = silk_INVERSE32_varQ( gain_Q16, 32 );
for( i = 0; i < order; i++ ) {
coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] );
}
/* Apply bandwidth expansion */
chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ(
silk_SMULWB( maxabs_Q20 - limit_Q20, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ),
silk_MUL( maxabs_Q20, ind + 1 ), 22 );
silk_bwexpander_32( coefs_Q24, order, chirp_Q16 );
/* Convert to monic warped coefficients */
lambda_Q16 = -lambda_Q16;
for( i = order - 1; i > 0; i-- ) {
coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 );
}
lambda_Q16 = -lambda_Q16;
nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 );
den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 );
gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
for( i = 0; i < order; i++ ) {
coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] );
}
}
silk_assert( 0 );
}
/* Disable MIPS version until it's updated. */
#if 0 && defined(MIPSr1_ASM)
#include "mips/noise_shape_analysis_FIX_mipsr1.h"
#endif
/**************************************************************/
/* Compute noise shaping coefficients and initial gain values */
/**************************************************************/
#ifndef OVERRIDE_silk_noise_shape_analysis_FIX
void silk_noise_shape_analysis_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */
silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */
const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */
const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */
int arch /* I Run-time architecture */
)
{
silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
opus_int k, i, nSamples, nSegs, Qnrg, b_Q14, warping_Q16, scale = 0;
opus_int32 SNR_adj_dB_Q7, HarmShapeGain_Q16, Tilt_Q16, tmp32;
opus_int32 nrg, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
opus_int32 BWExp_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;
opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ];
opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ];
opus_int32 AR_Q24[ MAX_SHAPE_LPC_ORDER ];
VARDECL( opus_int16, x_windowed );
const opus_int16 *x_ptr, *pitch_res_ptr;
SAVE_STACK;
/* Point to start of first LPC analysis block */
x_ptr = x - psEnc->sCmn.la_shape;
/****************/
/* GAIN CONTROL */
/****************/
SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7;
/* Input quality is the average of the quality in the lowest two VAD bands */
psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ]
+ psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 );
/* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 -
SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 );
/* Reduce coding SNR during low speech activity */
if( psEnc->sCmn.useCBR == 0 ) {
b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8;
b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 );
SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/
silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/
}
if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
/* Reduce gains for periodic signals */
SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 );
} else {
/* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ),
SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 );
}
/*************************/
/* SPARSENESS PROCESSING */
/*************************/
/* Set quantizer offset */
if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
/* Initially set to 0; may be overruled in process_gains(..) */
psEnc->sCmn.indices.quantOffsetType = 0;
} else {
/* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 );
energy_variation_Q7 = 0;
log_energy_prev_Q7 = 0;
pitch_res_ptr = pitch_res;
nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2;
for( k = 0; k < nSegs; k++ ) {
silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples );
nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/
log_energy_Q7 = silk_lin2log( nrg );
if( k > 0 ) {
energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 );
}
log_energy_prev_Q7 = log_energy_Q7;
pitch_res_ptr += nSamples;
}
/* Set quantization offset depending on sparseness measure */
if( energy_variation_Q7 > SILK_FIX_CONST( ENERGY_VARIATION_THRESHOLD_QNT_OFFSET, 7 ) * (nSegs-1) ) {
psEnc->sCmn.indices.quantOffsetType = 0;
} else {
psEnc->sCmn.indices.quantOffsetType = 1;
}
}
/*******************************/
/* Control bandwidth expansion */
/*******************************/
/* More BWE for signals with high prediction gain */
strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) );
BWExp_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ),
silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 );
if( psEnc->sCmn.warping_Q16 > 0 ) {
/* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) );
} else {
warping_Q16 = 0;
}
/********************************************/
/* Compute noise shaping AR coefs and gains */
/********************************************/
ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 );
for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
/* Apply window: sine slope followed by flat part followed by cosine slope */
opus_int shift, slope_part, flat_part;
flat_part = psEnc->sCmn.fs_kHz * 3;
slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 );
silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part );
shift = slope_part;
silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) );
shift += flat_part;
silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part );
/* Update pointer: next LPC analysis block */
x_ptr += psEnc->sCmn.subfr_length;
if( psEnc->sCmn.warping_Q16 > 0 ) {
/* Calculate warped auto correlation */
silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch );
} else {
/* Calculate regular auto correlation */
silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch );
}
/* Add white noise, as a fraction of energy */
auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ),
SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) );
/* Calculate the reflection coefficients using schur */
nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder );
silk_assert( nrg >= 0 );
/* Convert reflection coefficients to prediction coefficients */
silk_k2a_Q16( AR_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder );
Qnrg = -scale; /* range: -12...30*/
silk_assert( Qnrg >= -12 );
silk_assert( Qnrg <= 30 );
/* Make sure that Qnrg is an even number */
if( Qnrg & 1 ) {
Qnrg -= 1;
nrg >>= 1;
}
tmp32 = silk_SQRT_APPROX( nrg );
Qnrg >>= 1; /* range: -6...15*/
psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg );
if( psEnc->sCmn.warping_Q16 > 0 ) {
/* Adjust gain for warping */
gain_mult_Q16 = warped_gain( AR_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder );
silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 );
if( psEncCtrl->Gains_Q16[ k ] < SILK_FIX_CONST( 0.25, 16 ) ) {
psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
} else {
psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 );
if ( psEncCtrl->Gains_Q16[ k ] >= ( silk_int32_MAX >> 1 ) ) {
psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX;
} else {
psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT32( psEncCtrl->Gains_Q16[ k ], 1 );
}
}
silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 );
}
/* Bandwidth expansion */
silk_bwexpander_32( AR_Q24, psEnc->sCmn.shapingLPCOrder, BWExp_Q16 );
if( psEnc->sCmn.warping_Q16 > 0 ) {
/* Convert to monic warped prediction coefficients and limit absolute values */
limit_warped_coefs( AR_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder );
/* Convert from Q24 to Q13 and store in int16 */
for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) {
psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR_Q24[ i ], 11 ) );
}
} else {
silk_LPC_fit( &psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER ], AR_Q24, 13, 24, psEnc->sCmn.shapingLPCOrder );
}
}
/*****************/
/* Gain tweaking */
/*****************/
/* Increase gains during low speech activity and put lower limit on gains */
gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) );
gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) );
silk_assert( gain_mult_Q16 > 0 );
for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 );
}
/************************************************/
/* Control low-frequency shaping and noise tilt */
/************************************************/
/* Less low frequency shaping for noisy inputs */
strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ),
SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) );
strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 );
if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
/* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
/*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz );
for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] );
/* Pack two coefficients in one int32 */
psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 );
psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
}
silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/
Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) -
silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ),
silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) );
} else {
b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/
/* Pack two coefficients in one int32 */
psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 -
silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 );
psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ];
}
Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 );
}
/****************************/
/* HARMONIC SHAPING CONTROL */
/****************************/
if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
/* More harmonic noise shaping for high bitrates or noisy input */
HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ),
SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ),
psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) );
/* Less harmonic noise shaping for less periodic signals */
HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ),
silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) );
} else {
HarmShapeGain_Q16 = 0;
}
/*************************/
/* Smooth over subframes */
/*************************/
for( k = 0; k < MAX_NB_SUBFR; k++ ) {
psShapeSt->HarmShapeGain_smth_Q16 =
silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
psShapeSt->Tilt_smth_Q16 =
silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 );
psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 );
}
RESTORE_STACK;
}
#endif /* OVERRIDE_silk_noise_shape_analysis_FIX */

View file

@ -0,0 +1,721 @@
/***********************************************************************
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
/***********************************************************
* Pitch analyser function
********************************************************** */
#include "SigProc_FIX.h"
#include "pitch_est_defines.h"
#include "stack_alloc.h"
#include "debug.h"
#include "pitch.h"
#define SCRATCH_SIZE 22
#define SF_LENGTH_4KHZ ( PE_SUBFR_LENGTH_MS * 4 )
#define SF_LENGTH_8KHZ ( PE_SUBFR_LENGTH_MS * 8 )
#define MIN_LAG_4KHZ ( PE_MIN_LAG_MS * 4 )
#define MIN_LAG_8KHZ ( PE_MIN_LAG_MS * 8 )
#define MAX_LAG_4KHZ ( PE_MAX_LAG_MS * 4 )
#define MAX_LAG_8KHZ ( PE_MAX_LAG_MS * 8 - 1 )
#define CSTRIDE_4KHZ ( MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ )
#define CSTRIDE_8KHZ ( MAX_LAG_8KHZ + 3 - ( MIN_LAG_8KHZ - 2 ) )
#define D_COMP_MIN ( MIN_LAG_8KHZ - 3 )
#define D_COMP_MAX ( MAX_LAG_8KHZ + 4 )
#define D_COMP_STRIDE ( D_COMP_MAX - D_COMP_MIN )
typedef opus_int32 silk_pe_stage3_vals[ PE_NB_STAGE3_LAGS ];
/************************************************************/
/* Internally used functions */
/************************************************************/
static void silk_P_Ana_calc_corr_st3(
silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */
const opus_int16 frame[], /* I vector to correlate */
opus_int start_lag, /* I lag offset to search around */
opus_int sf_length, /* I length of a 5 ms subframe */
opus_int nb_subfr, /* I number of subframes */
opus_int complexity, /* I Complexity setting */
int arch /* I Run-time architecture */
);
static void silk_P_Ana_calc_energy_st3(
silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */
const opus_int16 frame[], /* I vector to calc energy in */
opus_int start_lag, /* I lag offset to search around */
opus_int sf_length, /* I length of one 5 ms subframe */
opus_int nb_subfr, /* I number of subframes */
opus_int complexity, /* I Complexity setting */
int arch /* I Run-time architecture */
);
/*************************************************************/
/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */
/*************************************************************/
opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */
const opus_int16 *frame_unscaled, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
opus_int *pitch_out, /* O 4 pitch lag values */
opus_int16 *lagIndex, /* O Lag Index */
opus_int8 *contourIndex, /* O Pitch contour Index */
opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */
opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */
const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */
const opus_int Fs_kHz, /* I Sample frequency (kHz) */
const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
const opus_int nb_subfr, /* I number of 5 ms subframes */
int arch /* I Run-time architecture */
)
{
VARDECL( opus_int16, frame_8kHz_buf );
VARDECL( opus_int16, frame_4kHz );
VARDECL( opus_int16, frame_scaled );
opus_int32 filt_state[ 6 ];
const opus_int16 *frame, *frame_8kHz;
opus_int i, k, d, j;
VARDECL( opus_int16, C );
VARDECL( opus_int32, xcorr32 );
const opus_int16 *target_ptr, *basis_ptr;
opus_int32 cross_corr, normalizer, energy, energy_basis, energy_target;
opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp, shift;
VARDECL( opus_int16, d_comp );
opus_int32 sum, threshold, lag_counter;
opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new;
opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new;
VARDECL( silk_pe_stage3_vals, energies_st3 );
VARDECL( silk_pe_stage3_vals, cross_corr_st3 );
opus_int frame_length, frame_length_8kHz, frame_length_4kHz;
opus_int sf_length;
opus_int min_lag;
opus_int max_lag;
opus_int32 contour_bias_Q15, diff;
opus_int nb_cbk_search, cbk_size;
opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13;
const opus_int8 *Lag_CB_ptr;
SAVE_STACK;
/* Check for valid sampling frequency */
celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 );
/* Check for valid complexity setting */
celt_assert( complexity >= SILK_PE_MIN_COMPLEX );
celt_assert( complexity <= SILK_PE_MAX_COMPLEX );
silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) );
silk_assert( search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1<<13) );
/* Set up frame lengths max / min lag for the sampling frequency */
frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz;
frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4;
frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8;
sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz;
min_lag = PE_MIN_LAG_MS * Fs_kHz;
max_lag = PE_MAX_LAG_MS * Fs_kHz - 1;
/* Downscale input if necessary */
silk_sum_sqr_shift( &energy, &shift, frame_unscaled, frame_length );
shift += 3 - silk_CLZ32( energy ); /* at least two bits headroom */
ALLOC( frame_scaled, frame_length, opus_int16 );
if( shift > 0 ) {
shift = silk_RSHIFT( shift + 1, 1 );
for( i = 0; i < frame_length; i++ ) {
frame_scaled[ i ] = silk_RSHIFT( frame_unscaled[ i ], shift );
}
frame = frame_scaled;
} else {
frame = frame_unscaled;
}
ALLOC( frame_8kHz_buf, ( Fs_kHz == 8 ) ? 1 : frame_length_8kHz, opus_int16 );
/* Resample from input sampled at Fs_kHz to 8 kHz */
if( Fs_kHz == 16 ) {
silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
silk_resampler_down2( filt_state, frame_8kHz_buf, frame, frame_length );
frame_8kHz = frame_8kHz_buf;
} else if( Fs_kHz == 12 ) {
silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) );
silk_resampler_down2_3( filt_state, frame_8kHz_buf, frame, frame_length );
frame_8kHz = frame_8kHz_buf;
} else {
celt_assert( Fs_kHz == 8 );
frame_8kHz = frame;
}
/* Decimate again to 4 kHz */
silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */
ALLOC( frame_4kHz, frame_length_4kHz, opus_int16 );
silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz );
/* Low-pass filter */
for( i = frame_length_4kHz - 1; i > 0; i-- ) {
frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] );
}
/******************************************************************************
* FIRST STAGE, operating in 4 khz
******************************************************************************/
ALLOC( C, nb_subfr * CSTRIDE_8KHZ, opus_int16 );
ALLOC( xcorr32, MAX_LAG_4KHZ-MIN_LAG_4KHZ+1, opus_int32 );
silk_memset( C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ * sizeof( opus_int16 ) );
target_ptr = &frame_4kHz[ silk_LSHIFT( SF_LENGTH_4KHZ, 2 ) ];
for( k = 0; k < nb_subfr >> 1; k++ ) {
/* Check that we are within range of the array */
celt_assert( target_ptr >= frame_4kHz );
celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
basis_ptr = target_ptr - MIN_LAG_4KHZ;
/* Check that we are within range of the array */
celt_assert( basis_ptr >= frame_4kHz );
celt_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
celt_pitch_xcorr( target_ptr, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1, arch );
/* Calculate first vector products before loop */
cross_corr = xcorr32[ MAX_LAG_4KHZ - MIN_LAG_4KHZ ];
normalizer = silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch );
normalizer = silk_ADD32( normalizer, silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ) );
normalizer = silk_ADD32( normalizer, silk_SMULBB( SF_LENGTH_8KHZ, 4000 ) );
matrix_ptr( C, k, 0, CSTRIDE_4KHZ ) =
(opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */
/* From now on normalizer is computed recursively */
for( d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++ ) {
basis_ptr--;
/* Check that we are within range of the array */
silk_assert( basis_ptr >= frame_4kHz );
silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
cross_corr = xcorr32[ MAX_LAG_4KHZ - d ];
/* Add contribution of new sample and remove contribution from oldest sample */
normalizer = silk_ADD32( normalizer,
silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) -
silk_SMULBB( basis_ptr[ SF_LENGTH_8KHZ ], basis_ptr[ SF_LENGTH_8KHZ ] ) );
matrix_ptr( C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ) =
(opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */
}
/* Update target pointer */
target_ptr += SF_LENGTH_8KHZ;
}
/* Combine two subframes into single correlation measure and apply short-lag bias */
if( nb_subfr == PE_MAX_NB_SUBFR ) {
for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
sum = (opus_int32)matrix_ptr( C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ )
+ (opus_int32)matrix_ptr( C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ); /* Q14 */
sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */
C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */
}
} else {
/* Only short-lag bias */
for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
sum = silk_LSHIFT( (opus_int32)C[ i - MIN_LAG_4KHZ ], 1 ); /* Q14 */
sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */
C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */
}
}
/* Sort */
length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 );
celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH );
silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ,
length_d_srch );
/* Escape if correlation is very low already here */
Cmax = (opus_int)C[ 0 ]; /* Q14 */
if( Cmax < SILK_FIX_CONST( 0.2, 14 ) ) {
silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
*LTPCorr_Q15 = 0;
*lagIndex = 0;
*contourIndex = 0;
RESTORE_STACK;
return 1;
}
threshold = silk_SMULWB( search_thres1_Q16, Cmax );
for( i = 0; i < length_d_srch; i++ ) {
/* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
if( C[ i ] > threshold ) {
d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + MIN_LAG_4KHZ, 1 );
} else {
length_d_srch = i;
break;
}
}
celt_assert( length_d_srch > 0 );
ALLOC( d_comp, D_COMP_STRIDE, opus_int16 );
for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) {
d_comp[ i - D_COMP_MIN ] = 0;
}
for( i = 0; i < length_d_srch; i++ ) {
d_comp[ d_srch[ i ] - D_COMP_MIN ] = 1;
}
/* Convolution */
for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
d_comp[ i - D_COMP_MIN ] +=
d_comp[ i - 1 - D_COMP_MIN ] + d_comp[ i - 2 - D_COMP_MIN ];
}
length_d_srch = 0;
for( i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++ ) {
if( d_comp[ i + 1 - D_COMP_MIN ] > 0 ) {
d_srch[ length_d_srch ] = i;
length_d_srch++;
}
}
/* Convolution */
for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
d_comp[ i - D_COMP_MIN ] += d_comp[ i - 1 - D_COMP_MIN ]
+ d_comp[ i - 2 - D_COMP_MIN ] + d_comp[ i - 3 - D_COMP_MIN ];
}
length_d_comp = 0;
for( i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++ ) {
if( d_comp[ i - D_COMP_MIN ] > 0 ) {
d_comp[ length_d_comp ] = i - 2;
length_d_comp++;
}
}
/**********************************************************************************
** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
*************************************************************************************/
/*********************************************************************************
* Find energy of each subframe projected onto its history, for a range of delays
*********************************************************************************/
silk_memset( C, 0, nb_subfr * CSTRIDE_8KHZ * sizeof( opus_int16 ) );
target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ];
for( k = 0; k < nb_subfr; k++ ) {
/* Check that we are within range of the array */
celt_assert( target_ptr >= frame_8kHz );
celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ), 1 );
for( j = 0; j < length_d_comp; j++ ) {
d = d_comp[ j ];
basis_ptr = target_ptr - d;
/* Check that we are within range of the array */
silk_assert( basis_ptr >= frame_8kHz );
silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, SF_LENGTH_8KHZ, arch );
if( cross_corr > 0 ) {
energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch );
matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) =
(opus_int16)silk_DIV32_varQ( cross_corr,
silk_ADD32( energy_target,
energy_basis ),
13 + 1 ); /* Q13 */
} else {
matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = 0;
}
}
target_ptr += SF_LENGTH_8KHZ;
}
/* search over lag range and lags codebook */
/* scale factor for lag codebook, as a function of center lag */
CCmax = silk_int32_MIN;
CCmax_b = silk_int32_MIN;
CBimax = 0; /* To avoid returning undefined lag values */
lag = -1; /* To check if lag with strong enough correlation has been found */
if( prevLag > 0 ) {
if( Fs_kHz == 12 ) {
prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 );
} else if( Fs_kHz == 16 ) {
prevLag = silk_RSHIFT( prevLag, 1 );
}
prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag );
} else {
prevLag_log2_Q7 = 0;
}
silk_assert( search_thres2_Q13 == silk_SAT16( search_thres2_Q13 ) );
/* Set up stage 2 codebook based on number of subframes */
if( nb_subfr == PE_MAX_NB_SUBFR ) {
cbk_size = PE_NB_CBKS_STAGE2_EXT;
Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) {
/* If input is 8 khz use a larger codebook here because it is last stage */
nb_cbk_search = PE_NB_CBKS_STAGE2_EXT;
} else {
nb_cbk_search = PE_NB_CBKS_STAGE2;
}
} else {
cbk_size = PE_NB_CBKS_STAGE2_10MS;
Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
nb_cbk_search = PE_NB_CBKS_STAGE2_10MS;
}
for( k = 0; k < length_d_srch; k++ ) {
d = d_srch[ k ];
for( j = 0; j < nb_cbk_search; j++ ) {
CC[ j ] = 0;
for( i = 0; i < nb_subfr; i++ ) {
opus_int d_subfr;
/* Try all codebooks */
d_subfr = d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size );
CC[ j ] = CC[ j ]
+ (opus_int32)matrix_ptr( C, i,
d_subfr - ( MIN_LAG_8KHZ - 2 ),
CSTRIDE_8KHZ );
}
}
/* Find best codebook */
CCmax_new = silk_int32_MIN;
CBimax_new = 0;
for( i = 0; i < nb_cbk_search; i++ ) {
if( CC[ i ] > CCmax_new ) {
CCmax_new = CC[ i ];
CBimax_new = i;
}
}
/* Bias towards shorter lags */
lag_log2_Q7 = silk_lin2log( d ); /* Q7 */
silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) );
silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) ) );
CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ), lag_log2_Q7 ), 7 ); /* Q13 */
/* Bias towards previous lag */
silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) ) );
if( prevLag > 0 ) {
delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7;
silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) );
delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 );
prev_lag_bias_Q13 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ), *LTPCorr_Q15 ), 15 ); /* Q13 */
prev_lag_bias_Q13 = silk_DIV32( silk_MUL( prev_lag_bias_Q13, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + SILK_FIX_CONST( 0.5, 7 ) );
CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */
}
if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */
CCmax_new > silk_SMULBB( nb_subfr, search_thres2_Q13 ) && /* Correlation needs to be high enough to be voiced */
silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= MIN_LAG_8KHZ /* Lag must be in range */
) {
CCmax_b = CCmax_new_b;
CCmax = CCmax_new;
lag = d;
CBimax = CBimax_new;
}
}
if( lag == -1 ) {
/* No suitable candidate found */
silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
*LTPCorr_Q15 = 0;
*lagIndex = 0;
*contourIndex = 0;
RESTORE_STACK;
return 1;
}
/* Output normalized correlation */
*LTPCorr_Q15 = (opus_int)silk_LSHIFT( silk_DIV32_16( CCmax, nb_subfr ), 2 );
silk_assert( *LTPCorr_Q15 >= 0 );
if( Fs_kHz > 8 ) {
/* Search in original signal */
CBimax_old = CBimax;
/* Compensate for decimation */
silk_assert( lag == silk_SAT16( lag ) );
if( Fs_kHz == 12 ) {
lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 );
} else if( Fs_kHz == 16 ) {
lag = silk_LSHIFT( lag, 1 );
} else {
lag = silk_SMULBB( lag, 3 );
}
lag = silk_LIMIT_int( lag, min_lag, max_lag );
start_lag = silk_max_int( lag - 2, min_lag );
end_lag = silk_min_int( lag + 2, max_lag );
lag_new = lag; /* to avoid undefined lag */
CBimax = 0; /* to avoid undefined lag */
CCmax = silk_int32_MIN;
/* pitch lags according to second stage */
for( k = 0; k < nb_subfr; k++ ) {
pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ];
}
/* Set up codebook parameters according to complexity setting and frame length */
if( nb_subfr == PE_MAX_NB_SUBFR ) {
nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ];
cbk_size = PE_NB_CBKS_STAGE3_MAX;
Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
} else {
nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
cbk_size = PE_NB_CBKS_STAGE3_10MS;
Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
}
/* Calculate the correlations and energies needed in stage 3 */
ALLOC( energies_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
ALLOC( cross_corr_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch );
silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch );
lag_counter = 0;
silk_assert( lag == silk_SAT16( lag ) );
contour_bias_Q15 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 15 ), lag );
target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ];
energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, nb_subfr * sf_length, arch ), 1 );
for( d = start_lag; d <= end_lag; d++ ) {
for( j = 0; j < nb_cbk_search; j++ ) {
cross_corr = 0;
energy = energy_target;
for( k = 0; k < nb_subfr; k++ ) {
cross_corr = silk_ADD32( cross_corr,
matrix_ptr( cross_corr_st3, k, j,
nb_cbk_search )[ lag_counter ] );
energy = silk_ADD32( energy,
matrix_ptr( energies_st3, k, j,
nb_cbk_search )[ lag_counter ] );
silk_assert( energy >= 0 );
}
if( cross_corr > 0 ) {
CCmax_new = silk_DIV32_varQ( cross_corr, energy, 13 + 1 ); /* Q13 */
/* Reduce depending on flatness of contour */
diff = silk_int16_MAX - silk_MUL( contour_bias_Q15, j ); /* Q15 */
silk_assert( diff == silk_SAT16( diff ) );
CCmax_new = silk_SMULWB( CCmax_new, diff ); /* Q14 */
} else {
CCmax_new = 0;
}
if( CCmax_new > CCmax && ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) {
CCmax = CCmax_new;
lag_new = d;
CBimax = j;
}
}
lag_counter++;
}
for( k = 0; k < nb_subfr; k++ ) {
pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz );
}
*lagIndex = (opus_int16)( lag_new - min_lag);
*contourIndex = (opus_int8)CBimax;
} else { /* Fs_kHz == 8 */
/* Save Lags */
for( k = 0; k < nb_subfr; k++ ) {
pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], MIN_LAG_8KHZ, PE_MAX_LAG_MS * 8 );
}
*lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ );
*contourIndex = (opus_int8)CBimax;
}
celt_assert( *lagIndex >= 0 );
/* return as voiced */
RESTORE_STACK;
return 0;
}
/***********************************************************************
* Calculates the correlations used in stage 3 search. In order to cover
* the whole lag codebook for all the searched offset lags (lag +- 2),
* the following correlations are needed in each sub frame:
*
* sf1: lag range [-8,...,7] total 16 correlations
* sf2: lag range [-4,...,4] total 9 correlations
* sf3: lag range [-3,....4] total 8 correltions
* sf4: lag range [-6,....8] total 15 correlations
*
* In total 48 correlations. The direct implementation computed in worst
* case 4*12*5 = 240 correlations, but more likely around 120.
***********************************************************************/
static void silk_P_Ana_calc_corr_st3(
silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */
const opus_int16 frame[], /* I vector to correlate */
opus_int start_lag, /* I lag offset to search around */
opus_int sf_length, /* I length of a 5 ms subframe */
opus_int nb_subfr, /* I number of subframes */
opus_int complexity, /* I Complexity setting */
int arch /* I Run-time architecture */
)
{
const opus_int16 *target_ptr;
opus_int i, j, k, lag_counter, lag_low, lag_high;
opus_int nb_cbk_search, delta, idx, cbk_size;
VARDECL( opus_int32, scratch_mem );
VARDECL( opus_int32, xcorr32 );
const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
SAVE_STACK;
celt_assert( complexity >= SILK_PE_MIN_COMPLEX );
celt_assert( complexity <= SILK_PE_MAX_COMPLEX );
if( nb_subfr == PE_MAX_NB_SUBFR ) {
Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
cbk_size = PE_NB_CBKS_STAGE3_MAX;
} else {
celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
cbk_size = PE_NB_CBKS_STAGE3_10MS;
}
ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
ALLOC( xcorr32, SCRATCH_SIZE, opus_int32 );
target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */
for( k = 0; k < nb_subfr; k++ ) {
lag_counter = 0;
/* Calculate the correlations for each subframe */
lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 );
lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 );
celt_assert(lag_high-lag_low+1 <= SCRATCH_SIZE);
celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1, arch );
for( j = lag_low; j <= lag_high; j++ ) {
silk_assert( lag_counter < SCRATCH_SIZE );
scratch_mem[ lag_counter ] = xcorr32[ lag_high - j ];
lag_counter++;
}
delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
for( i = 0; i < nb_cbk_search; i++ ) {
/* Fill out the 3 dim array that stores the correlations for */
/* each code_book vector for each start lag */
idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
silk_assert( idx + j < SCRATCH_SIZE );
silk_assert( idx + j < lag_counter );
matrix_ptr( cross_corr_st3, k, i, nb_cbk_search )[ j ] =
scratch_mem[ idx + j ];
}
}
target_ptr += sf_length;
}
RESTORE_STACK;
}
/********************************************************************/
/* Calculate the energies for first two subframes. The energies are */
/* calculated recursively. */
/********************************************************************/
static void silk_P_Ana_calc_energy_st3(
silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */
const opus_int16 frame[], /* I vector to calc energy in */
opus_int start_lag, /* I lag offset to search around */
opus_int sf_length, /* I length of one 5 ms subframe */
opus_int nb_subfr, /* I number of subframes */
opus_int complexity, /* I Complexity setting */
int arch /* I Run-time architecture */
)
{
const opus_int16 *target_ptr, *basis_ptr;
opus_int32 energy;
opus_int k, i, j, lag_counter;
opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff;
VARDECL( opus_int32, scratch_mem );
const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
SAVE_STACK;
celt_assert( complexity >= SILK_PE_MIN_COMPLEX );
celt_assert( complexity <= SILK_PE_MAX_COMPLEX );
if( nb_subfr == PE_MAX_NB_SUBFR ) {
Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
cbk_size = PE_NB_CBKS_STAGE3_MAX;
} else {
celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
cbk_size = PE_NB_CBKS_STAGE3_10MS;
}
ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ];
for( k = 0; k < nb_subfr; k++ ) {
lag_counter = 0;
/* Calculate the energy for first lag */
basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) );
energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length, arch );
silk_assert( energy >= 0 );
scratch_mem[ lag_counter ] = energy;
lag_counter++;
lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 );
for( i = 1; i < lag_diff; i++ ) {
/* remove part outside new window */
energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] );
silk_assert( energy >= 0 );
/* add part that comes into window */
energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) );
silk_assert( energy >= 0 );
silk_assert( lag_counter < SCRATCH_SIZE );
scratch_mem[ lag_counter ] = energy;
lag_counter++;
}
delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
for( i = 0; i < nb_cbk_search; i++ ) {
/* Fill out the 3 dim array that stores the correlations for */
/* each code_book vector for each start lag */
idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
silk_assert( idx + j < SCRATCH_SIZE );
silk_assert( idx + j < lag_counter );
matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] =
scratch_mem[ idx + j ];
silk_assert(
matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] >= 0 );
}
}
target_ptr += sf_length;
}
RESTORE_STACK;
}

View file

@ -0,0 +1,117 @@
/***********************************************************************
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_FIX.h"
#include "tuning_parameters.h"
/* Processing of gains */
void silk_process_gains_FIX(
silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */
opus_int condCoding /* I The type of conditional coding to use */
)
{
silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
opus_int k;
opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10;
/* Gain reduction when LTP coding gain is high */
if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
/*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */
s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) );
for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 );
}
}
/* Limit the quantized signal */
/* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */
InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin(
silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length );
for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
/* Soft limit on ratio residual energy and squared gains */
ResNrg = psEncCtrl->ResNrg[ k ];
ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 );
if( psEncCtrl->ResNrgQ[ k ] > 0 ) {
ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] );
} else {
if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) {
ResNrgPart = silk_int32_MAX;
} else {
ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] );
}
}
gain = psEncCtrl->Gains_Q16[ k ];
gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) );
if( gain_squared < silk_int16_MAX ) {
/* recalculate with higher precision */
gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain );
silk_assert( gain_squared > 0 );
gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */
gain = silk_min( gain, silk_int32_MAX >> 8 );
psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */
} else {
gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */
gain = silk_min( gain, silk_int32_MAX >> 16 );
psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */
}
}
/* Save unquantized gains and gain Index */
silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
/* Quantize gains */
silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16,
&psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
/* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) {
psEnc->sCmn.indices.quantOffsetType = 0;
} else {
psEnc->sCmn.indices.quantOffsetType = 1;
}
}
/* Quantizer boundary adjustment */
quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ];
psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 )
+ silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision )
+ silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 )
+ silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 )
+ silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 )
+ silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 );
silk_assert( psEncCtrl->Lambda_Q10 > 0 );
silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) );
}

View file

@ -0,0 +1,47 @@
/***********************************************************************
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_FIX.h"
/* Add noise to matrix diagonal */
void silk_regularize_correlations_FIX(
opus_int32 *XX, /* I/O Correlation matrices */
opus_int32 *xx, /* I/O Correlation values */
opus_int32 noise, /* I Noise to add */
opus_int D /* I Dimension of XX */
)
{
opus_int i;
for( i = 0; i < D; i++ ) {
matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise );
}
xx[ 0 ] += noise;
}

View file

@ -0,0 +1,103 @@
/***********************************************************************
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_FIX.h"
/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
opus_int32 silk_residual_energy16_covar_FIX(
const opus_int16 *c, /* I Prediction vector */
const opus_int32 *wXX, /* I Correlation matrix */
const opus_int32 *wXx, /* I Correlation vector */
opus_int32 wxx, /* I Signal energy */
opus_int D, /* I Dimension */
opus_int cQ /* I Q value for c vector 0 - 15 */
)
{
opus_int i, j, lshifts, Qxtra;
opus_int32 c_max, w_max, tmp, tmp2, nrg;
opus_int cn[ MAX_MATRIX_SIZE ];
const opus_int32 *pRow;
/* Safety checks */
celt_assert( D >= 0 );
celt_assert( D <= 16 );
celt_assert( cQ > 0 );
celt_assert( cQ < 16 );
lshifts = 16 - cQ;
Qxtra = lshifts;
c_max = 0;
for( i = 0; i < D; i++ ) {
c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) );
}
Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 );
w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] );
Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 );
Qxtra = silk_max_int( Qxtra, 0 );
for( i = 0; i < D; i++ ) {
cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra );
silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */
}
lshifts -= Qxtra;
/* Compute wxx - 2 * wXx * c */
tmp = 0;
for( i = 0; i < D; i++ ) {
tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] );
}
nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */
/* Add c' * wXX * c, assuming wXX is symmetric */
tmp2 = 0;
for( i = 0; i < D; i++ ) {
tmp = 0;
pRow = &wXX[ i * D ];
for( j = i + 1; j < D; j++ ) {
tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] );
}
tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] );
tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] );
}
nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */
/* Keep one bit free always, because we add them for LSF interpolation */
if( nrg < 1 ) {
nrg = 1;
} else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) {
nrg = silk_int32_MAX >> 1;
} else {
nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */
}
return nrg;
}

View file

@ -0,0 +1,98 @@
/***********************************************************************
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_FIX.h"
#include "stack_alloc.h"
/* Calculates residual energies of input subframes where all subframes have LPC_order */
/* of preceding samples */
void silk_residual_energy_FIX(
opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */
const opus_int16 x[], /* I Input signal */
opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */
const opus_int subfr_length, /* I Subframe length */
const opus_int nb_subfr, /* I Number of subframes */
const opus_int LPC_order, /* I LPC order */
int arch /* I Run-time architecture */
)
{
opus_int offset, i, j, rshift, lz1, lz2;
opus_int16 *LPC_res_ptr;
VARDECL( opus_int16, LPC_res );
const opus_int16 *x_ptr;
opus_int32 tmp32;
SAVE_STACK;
x_ptr = x;
offset = LPC_order + subfr_length;
/* Filter input to create the LPC residual for each frame half, and measure subframe energies */
ALLOC( LPC_res, ( MAX_NB_SUBFR >> 1 ) * offset, opus_int16 );
celt_assert( ( nb_subfr >> 1 ) * ( MAX_NB_SUBFR >> 1 ) == nb_subfr );
for( i = 0; i < nb_subfr >> 1; i++ ) {
/* Calculate half frame LPC residual signal including preceding samples */
silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order, arch );
/* Point to first subframe of the just calculated LPC residual signal */
LPC_res_ptr = LPC_res + LPC_order;
for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) {
/* Measure subframe energy */
silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length );
/* Set Q values for the measured energy */
nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift;
/* Move to next subframe */
LPC_res_ptr += offset;
}
/* Move to next frame half */
x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset;
}
/* Apply the squared subframe gains */
for( i = 0; i < nb_subfr; i++ ) {
/* Fully upscale gains and energies */
lz1 = silk_CLZ32( nrgs[ i ] ) - 1;
lz2 = silk_CLZ32( gains[ i ] ) - 1;
tmp32 = silk_LSHIFT32( gains[ i ], lz2 );
/* Find squared gains */
tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/
/* Scale energies */
nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/
nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32;
}
RESTORE_STACK;
}

View file

@ -0,0 +1,93 @@
/***********************************************************************
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 "SigProc_FIX.h"
/* Slower than schur(), but more accurate. */
/* Uses SMULL(), available on armv4 */
opus_int32 silk_schur64( /* O returns residual energy */
opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */
const opus_int32 c[], /* I Correlations [order+1] */
opus_int32 order /* I Prediction order */
)
{
opus_int k, n;
opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31;
celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC );
/* Check for invalid input */
if( c[ 0 ] <= 0 ) {
silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) );
return 0;
}
k = 0;
do {
C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
} while( ++k <= order );
for( k = 0; k < order; k++ ) {
/* Check that we won't be getting an unstable rc, otherwise stop here. */
if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
if ( C[ k + 1 ][ 0 ] > 0 ) {
rc_Q16[ k ] = -SILK_FIX_CONST( .99f, 16 );
} else {
rc_Q16[ k ] = SILK_FIX_CONST( .99f, 16 );
}
k++;
break;
}
/* Get reflection coefficient: divide two Q30 values and get result in Q31 */
rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 );
/* Save the output */
rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 );
/* Update correlations */
for( n = 0; n < order - k; n++ ) {
Ctmp1_Q30 = C[ n + k + 1 ][ 0 ];
Ctmp2_Q30 = C[ n ][ 1 ];
/* Multiply and add the highest int32 */
C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 );
C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 );
}
}
for(; k < order; k++ ) {
rc_Q16[ k ] = 0;
}
return silk_max_32( 1, C[ 0 ][ 1 ] );
}

View file

@ -0,0 +1,107 @@
/***********************************************************************
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 "SigProc_FIX.h"
/* Faster than schur64(), but much less accurate. */
/* uses SMLAWB(), requiring armv5E and higher. */
opus_int32 silk_schur( /* O Returns residual energy */
opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */
const opus_int32 *c, /* I correlations [order+1] */
const opus_int32 order /* I prediction order */
)
{
opus_int k, n, lz;
opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
opus_int32 Ctmp1, Ctmp2, rc_tmp_Q15;
celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC );
/* Get number of leading zeros */
lz = silk_CLZ32( c[ 0 ] );
/* Copy correlations and adjust level to Q30 */
k = 0;
if( lz < 2 ) {
/* lz must be 1, so shift one to the right */
do {
C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 );
} while( ++k <= order );
} else if( lz > 2 ) {
/* Shift to the left */
lz -= 2;
do {
C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz );
} while( ++k <= order );
} else {
/* No need to shift */
do {
C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
} while( ++k <= order );
}
for( k = 0; k < order; k++ ) {
/* Check that we won't be getting an unstable rc, otherwise stop here. */
if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
if ( C[ k + 1 ][ 0 ] > 0 ) {
rc_Q15[ k ] = -SILK_FIX_CONST( .99f, 15 );
} else {
rc_Q15[ k ] = SILK_FIX_CONST( .99f, 15 );
}
k++;
break;
}
/* Get reflection coefficient */
rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) );
/* Clip (shouldn't happen for properly conditioned inputs) */
rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 );
/* Store */
rc_Q15[ k ] = (opus_int16)rc_tmp_Q15;
/* Update correlations */
for( n = 0; n < order - k; n++ ) {
Ctmp1 = C[ n + k + 1 ][ 0 ];
Ctmp2 = C[ n ][ 1 ];
C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 );
C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 );
}
}
for(; k < order; k++ ) {
rc_Q15[ k ] = 0;
}
/* return residual energy */
return silk_max_32( 1, C[ 0 ][ 1 ] );
}

View file

@ -0,0 +1,116 @@
/***********************************************************************
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.
***********************************************************************/
#ifndef SILK_STRUCTS_FIX_H
#define SILK_STRUCTS_FIX_H
#include "typedef.h"
#include "main.h"
#include "structs.h"
#ifdef __cplusplus
extern "C"
{
#endif
/********************************/
/* Noise shaping analysis state */
/********************************/
typedef struct {
opus_int8 LastGainIndex;
opus_int32 HarmBoost_smth_Q16;
opus_int32 HarmShapeGain_smth_Q16;
opus_int32 Tilt_smth_Q16;
} silk_shape_state_FIX;
/********************************/
/* Encoder state FIX */
/********************************/
typedef struct {
silk_encoder_state sCmn; /* Common struct, shared with floating-point code */
silk_shape_state_FIX sShape; /* Shape state */
/* Buffer for find pitch and noise shape analysis */
silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */
opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */
opus_int32 resNrgSmth;
} silk_encoder_state_FIX;
/************************/
/* Encoder control FIX */
/************************/
typedef struct {
/* Prediction and coding parameters */
opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
opus_int LTP_scale_Q14;
opus_int pitchL[ MAX_NB_SUBFR ];
/* Noise shaping parameters */
/* Testing */
silk_DWORD_ALIGN opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */
opus_int Tilt_Q14[ MAX_NB_SUBFR ];
opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ];
opus_int Lambda_Q10;
opus_int input_quality_Q14;
opus_int coding_quality_Q14;
/* measures */
opus_int32 predGain_Q16;
opus_int LTPredCodGain_Q7;
opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */
opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */
/* Parameters for CBR mode */
opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ];
opus_int8 lastGainIndexPrev;
} silk_encoder_control_FIX;
/************************/
/* Encoder Super Struct */
/************************/
typedef struct {
silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ];
stereo_enc_state sStereo;
opus_int32 nBitsUsedLBRR;
opus_int32 nBitsExceeded;
opus_int nChannelsAPI;
opus_int nChannelsInternal;
opus_int nPrevChannelsInternal;
opus_int timeSinceSwitchAllowed_ms;
opus_int allowBandwidthSwitch;
opus_int prev_decode_only_middle;
} silk_encoder;
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,102 @@
/***********************************************************************
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 "SigProc_FIX.h"
#include "pitch.h"
/* Copy and multiply a vector by a constant */
void silk_scale_copy_vector16(
opus_int16 *data_out,
const opus_int16 *data_in,
opus_int32 gain_Q16, /* I Gain in Q16 */
const opus_int dataSize /* I Length */
)
{
opus_int i;
opus_int32 tmp32;
for( i = 0; i < dataSize; i++ ) {
tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] );
data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 );
}
}
/* Multiply a vector by a constant */
void silk_scale_vector32_Q26_lshift_18(
opus_int32 *data1, /* I/O Q0/Q18 */
opus_int32 gain_Q26, /* I Q26 */
opus_int dataSize /* I length */
)
{
opus_int i;
for( i = 0; i < dataSize; i++ ) {
data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */
}
}
/* sum = for(i=0;i<len;i++)inVec1[i]*inVec2[i]; --- inner product */
/* Note for ARM asm: */
/* * inVec1 and inVec2 should be at least 2 byte aligned. */
/* * len should be positive 16bit integer. */
/* * only when len>6, memory access can be reduced by half. */
opus_int32 silk_inner_prod_aligned(
const opus_int16 *const inVec1, /* I input vector 1 */
const opus_int16 *const inVec2, /* I input vector 2 */
const opus_int len, /* I vector lengths */
int arch /* I Run-time architecture */
)
{
#ifdef FIXED_POINT
return celt_inner_prod(inVec1, inVec2, len, arch);
#else
opus_int i;
opus_int32 sum = 0;
for( i = 0; i < len; i++ ) {
sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] );
}
return sum;
#endif
}
opus_int64 silk_inner_prod16_aligned_64_c(
const opus_int16 *inVec1, /* I input vector 1 */
const opus_int16 *inVec2, /* I input vector 2 */
const opus_int len /* I vector lengths */
)
{
opus_int i;
opus_int64 sum = 0;
for( i = 0; i < len; i++ ) {
sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] );
}
return sum;
}

View file

@ -0,0 +1,90 @@
/***********************************************************************
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_FIX.h"
#if defined(MIPSr1_ASM)
#include "mips/warped_autocorrelation_FIX_mipsr1.h"
#endif
/* Autocorrelations for a warped frequency axis */
void silk_warped_autocorrelation_FIX_c(
opus_int32 *corr, /* O Result [order + 1] */
opus_int *scale, /* O Scaling of the correlation vector */
const opus_int16 *input, /* I Input data to correlate */
const opus_int warping_Q16, /* I Warping coefficient */
const opus_int length, /* I Length of input */
const opus_int order /* I Correlation order (even) */
)
{
opus_int n, i, lsh;
opus_int32 tmp1_QS, tmp2_QS;
opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
/* Order must be even */
celt_assert( ( order & 1 ) == 0 );
silk_assert( 2 * QS - QC >= 0 );
/* Loop over samples */
for( n = 0; n < length; n++ ) {
tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
/* Loop over allpass sections */
for( i = 0; i < order; i += 2 ) {
/* Output of allpass section */
tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
state_QS[ i ] = tmp1_QS;
corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
/* Output of allpass section */
tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
state_QS[ i + 1 ] = tmp2_QS;
corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC );
}
state_QS[ order ] = tmp1_QS;
corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
}
lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35;
lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC );
*scale = -( QC + lsh );
silk_assert( *scale >= -30 && *scale <= 12 );
if( lsh >= 0 ) {
for( i = 0; i < order + 1; i++ ) {
corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) );
}
} else {
for( i = 0; i < order + 1; i++ ) {
corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) );
}
}
silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
}

View file

@ -0,0 +1,377 @@
/* Copyright (c) 2014, Cisco Systems, INC
Written by XiangMingZhu WeiZhou MinPeng YanWang
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.
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 <xmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#include "SigProc_FIX.h"
#include "define.h"
#include "tuning_parameters.h"
#include "pitch.h"
#include "celt/x86/x86cpu.h"
#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
#define QA 25
#define N_BITS_HEAD_ROOM 2
#define MIN_RSHIFTS -16
#define MAX_RSHIFTS (32 - QA)
/* Compute reflection coefficients from input signal */
void silk_burg_modified_sse4_1(
opus_int32 *res_nrg, /* O Residual energy */
opus_int *res_nrg_Q, /* O Residual energy Q value */
opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
const opus_int nb_subfr, /* I Number of subframes stacked in x */
const opus_int D, /* I Order */
int arch /* I Run-time architecture */
)
{
opus_int k, n, s, lz, rshifts, rshifts_extra, reached_max_gain;
opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
const opus_int16 *x_ptr;
opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ];
opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ];
opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ];
opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ];
opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ];
opus_int32 xcorr[ SILK_MAX_ORDER_LPC ];
__m128i FIRST_3210, LAST_3210, ATMP_3210, TMP1_3210, TMP2_3210, T1_3210, T2_3210, PTR_3210, SUBFR_3210, X1_3210, X2_3210;
__m128i CONST1 = _mm_set1_epi32(1);
celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
/* Compute autocorrelations, added over subframes */
silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length );
if( rshifts > MAX_RSHIFTS ) {
C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS );
silk_assert( C0 > 0 );
rshifts = MAX_RSHIFTS;
} else {
lz = silk_CLZ32( C0 ) - 1;
rshifts_extra = N_BITS_HEAD_ROOM - lz;
if( rshifts_extra > 0 ) {
rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts );
C0 = silk_RSHIFT32( C0, rshifts_extra );
} else {
rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts );
C0 = silk_LSHIFT32( C0, -rshifts_extra );
}
rshifts += rshifts_extra;
}
CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
if( rshifts > 0 ) {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
for( n = 1; n < D + 1; n++ ) {
C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64(
silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts );
}
}
} else {
for( s = 0; s < nb_subfr; s++ ) {
int i;
opus_int32 d;
x_ptr = x + s * subfr_length;
celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch );
for( n = 1; n < D + 1; n++ ) {
for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ )
d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] );
xcorr[ n - 1 ] += d;
}
for( n = 1; n < D + 1; n++ ) {
C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts );
}
}
}
silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
/* Initialize */
CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
invGain_Q30 = (opus_int32)1 << 30;
reached_max_gain = 0;
for( n = 0; n < D; n++ ) {
/* Update first row of correlation matrix (without first element) */
/* Update last row of correlation matrix (without last element, stored in reversed order) */
/* Update C * Af */
/* Update C * flipud(Af) (stored in reversed order) */
if( rshifts > -2 ) {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */
x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */
tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */
tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */
for( k = 0; k < n; k++ ) {
C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
Atmp_QA = Af_QA[ k ];
tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */
tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */
}
tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */
tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */
for( k = 0; k <= n; k++ ) {
CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */
CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */
}
}
} else {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */
x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */
tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */
tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */
X1_3210 = _mm_set1_epi32( x1 );
X2_3210 = _mm_set1_epi32( x2 );
TMP1_3210 = _mm_setzero_si128();
TMP2_3210 = _mm_setzero_si128();
for( k = 0; k < n - 3; k += 4 ) {
PTR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 1 - 3 ] );
SUBFR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k ] );
FIRST_3210 = _mm_loadu_si128( (__m128i *)&C_first_row[ k ] );
PTR_3210 = _mm_shuffle_epi32( PTR_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) );
LAST_3210 = _mm_loadu_si128( (__m128i *)&C_last_row[ k ] );
ATMP_3210 = _mm_loadu_si128( (__m128i *)&Af_QA[ k ] );
T1_3210 = _mm_mullo_epi32( PTR_3210, X1_3210 );
T2_3210 = _mm_mullo_epi32( SUBFR_3210, X2_3210 );
ATMP_3210 = _mm_srai_epi32( ATMP_3210, 7 );
ATMP_3210 = _mm_add_epi32( ATMP_3210, CONST1 );
ATMP_3210 = _mm_srai_epi32( ATMP_3210, 1 );
FIRST_3210 = _mm_add_epi32( FIRST_3210, T1_3210 );
LAST_3210 = _mm_add_epi32( LAST_3210, T2_3210 );
PTR_3210 = _mm_mullo_epi32( ATMP_3210, PTR_3210 );
SUBFR_3210 = _mm_mullo_epi32( ATMP_3210, SUBFR_3210 );
_mm_storeu_si128( (__m128i *)&C_first_row[ k ], FIRST_3210 );
_mm_storeu_si128( (__m128i *)&C_last_row[ k ], LAST_3210 );
TMP1_3210 = _mm_add_epi32( TMP1_3210, PTR_3210 );
TMP2_3210 = _mm_add_epi32( TMP2_3210, SUBFR_3210 );
}
TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_unpackhi_epi64(TMP1_3210, TMP1_3210 ) );
TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_unpackhi_epi64(TMP2_3210, TMP2_3210 ) );
TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_shufflelo_epi16(TMP1_3210, 0x0E ) );
TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_shufflelo_epi16(TMP2_3210, 0x0E ) );
tmp1 += _mm_cvtsi128_si32( TMP1_3210 );
tmp2 += _mm_cvtsi128_si32( TMP2_3210 );
for( ; k < n; k++ ) {
C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */
tmp1 = silk_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */
tmp2 = silk_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */
}
tmp1 = -tmp1; /* Q17 */
tmp2 = -tmp2; /* Q17 */
{
__m128i xmm_tmp1, xmm_tmp2;
__m128i xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1;
__m128i xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1;
xmm_tmp1 = _mm_set1_epi32( tmp1 );
xmm_tmp2 = _mm_set1_epi32( tmp2 );
for( k = 0; k <= n - 3; k += 4 ) {
xmm_x_ptr_n_k_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 3 ] );
xmm_x_ptr_sub_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k - 1 ] );
xmm_x_ptr_n_k_x2x0 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 1, 2, 3 ) );
xmm_x_ptr_n_k_x2x0 = _mm_slli_epi32( xmm_x_ptr_n_k_x2x0, -rshifts - 1 );
xmm_x_ptr_sub_x2x0 = _mm_slli_epi32( xmm_x_ptr_sub_x2x0, -rshifts - 1 );
/* equal shift right 4 bytes, xmm_x_ptr_n_k_x3x1 = _mm_srli_si128(xmm_x_ptr_n_k_x2x0, 4)*/
xmm_x_ptr_n_k_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
xmm_x_ptr_sub_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_sub_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
xmm_x_ptr_n_k_x2x0 = _mm_mul_epi32( xmm_x_ptr_n_k_x2x0, xmm_tmp1 );
xmm_x_ptr_n_k_x3x1 = _mm_mul_epi32( xmm_x_ptr_n_k_x3x1, xmm_tmp1 );
xmm_x_ptr_sub_x2x0 = _mm_mul_epi32( xmm_x_ptr_sub_x2x0, xmm_tmp2 );
xmm_x_ptr_sub_x3x1 = _mm_mul_epi32( xmm_x_ptr_sub_x3x1, xmm_tmp2 );
xmm_x_ptr_n_k_x2x0 = _mm_srli_epi64( xmm_x_ptr_n_k_x2x0, 16 );
xmm_x_ptr_n_k_x3x1 = _mm_slli_epi64( xmm_x_ptr_n_k_x3x1, 16 );
xmm_x_ptr_sub_x2x0 = _mm_srli_epi64( xmm_x_ptr_sub_x2x0, 16 );
xmm_x_ptr_sub_x3x1 = _mm_slli_epi64( xmm_x_ptr_sub_x3x1, 16 );
xmm_x_ptr_n_k_x2x0 = _mm_blend_epi16( xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1, 0xCC );
xmm_x_ptr_sub_x2x0 = _mm_blend_epi16( xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1, 0xCC );
X1_3210 = _mm_loadu_si128( (__m128i *)&CAf[ k ] );
PTR_3210 = _mm_loadu_si128( (__m128i *)&CAb[ k ] );
X1_3210 = _mm_add_epi32( X1_3210, xmm_x_ptr_n_k_x2x0 );
PTR_3210 = _mm_add_epi32( PTR_3210, xmm_x_ptr_sub_x2x0 );
_mm_storeu_si128( (__m128i *)&CAf[ k ], X1_3210 );
_mm_storeu_si128( (__m128i *)&CAb[ k ], PTR_3210 );
}
for( ; k <= n; k++ ) {
CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1,
silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */
CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2,
silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */
}
}
}
}
/* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */
tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */
num = 0; /* Q( -rshifts ) */
nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */
for( k = 0; k < n; k++ ) {
Atmp_QA = Af_QA[ k ];
lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1;
lz = silk_min( 32 - QA, lz );
Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */
tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ),
Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */
}
CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */
CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */
num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */
num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */
/* Calculate the next order reflection (parcor) coefficient */
if( silk_abs( num ) < nrg ) {
rc_Q31 = silk_DIV32_varQ( num, nrg, 31 );
} else {
rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN;
}
/* Update inverse prediction gain */
tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 );
if( tmp1 <= minInvGain_Q30 ) {
/* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */
rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */
if( rc_Q31 > 0 ) {
/* Newton-Raphson iteration */
rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */
rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */
if( num < 0 ) {
/* Ensure adjusted reflection coefficients has the original sign */
rc_Q31 = -rc_Q31;
}
}
invGain_Q30 = minInvGain_Q30;
reached_max_gain = 1;
} else {
invGain_Q30 = tmp1;
}
/* Update the AR coefficients */
for( k = 0; k < (n + 1) >> 1; k++ ) {
tmp1 = Af_QA[ k ]; /* QA */
tmp2 = Af_QA[ n - k - 1 ]; /* QA */
Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */
Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */
}
Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */
if( reached_max_gain ) {
/* Reached max prediction gain; set remaining coefficients to zero and exit loop */
for( k = n + 1; k < D; k++ ) {
Af_QA[ k ] = 0;
}
break;
}
/* Update C * Af and C * Ab */
for( k = 0; k <= n + 1; k++ ) {
tmp1 = CAf[ k ]; /* Q( -rshifts ) */
tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */
CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */
CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */
}
}
if( reached_max_gain ) {
for( k = 0; k < D; k++ ) {
/* Scale coefficients */
A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );
}
/* Subtract energy of preceding samples from C0 */
if( rshifts > 0 ) {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts );
}
} else {
for( s = 0; s < nb_subfr; s++ ) {
x_ptr = x + s * subfr_length;
C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch ), -rshifts );
}
}
/* Approximate residual energy */
*res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 );
*res_nrg_Q = -rshifts;
} else {
/* Return residual energy */
nrg = CAf[ 0 ]; /* Q( -rshifts ) */
tmp1 = (opus_int32)1 << 16; /* Q16 */
for( k = 0; k < D; k++ ) {
Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */
nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */
tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */
A_Q16[ k ] = -Atmp1;
}
*res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
*res_nrg_Q = -rshifts;
}
}

View file

@ -0,0 +1,160 @@
/* Copyright (c) 2014, Cisco Systems, INC
Written by XiangMingZhu WeiZhou MinPeng YanWang
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.
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 <xmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#include "main.h"
#include "celt/x86/x86cpu.h"
void silk_warped_LPC_analysis_filter_FIX_sse4_1(
opus_int32 state[], /* I/O State [order + 1] */
opus_int32 res_Q2[], /* O Residual signal [length] */
const opus_int16 coef_Q13[], /* I Coefficients [order] */
const opus_int16 input[], /* I Input signal [length] */
const opus_int16 lambda_Q16, /* I Warping factor */
const opus_int length, /* I Length of input signal */
const opus_int order /* I Filter order (even) */
)
{
opus_int n, i;
opus_int32 acc_Q11, tmp1, tmp2;
/* Order must be even */
celt_assert( ( order & 1 ) == 0 );
if (order == 10)
{
if (0 == lambda_Q16)
{
__m128i coef_Q13_3210, coef_Q13_7654;
__m128i coef_Q13_0123, coef_Q13_4567;
__m128i state_0123, state_4567;
__m128i xmm_product1, xmm_product2;
__m128i xmm_tempa, xmm_tempb;
register opus_int32 sum;
register opus_int32 state_8, state_9, state_a;
register opus_int64 coef_Q13_8, coef_Q13_9;
celt_assert( length > 0 );
coef_Q13_3210 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 0 ] );
coef_Q13_7654 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 4 ] );
coef_Q13_0123 = _mm_shuffle_epi32( coef_Q13_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) );
coef_Q13_4567 = _mm_shuffle_epi32( coef_Q13_7654, _MM_SHUFFLE( 0, 1, 2, 3 ) );
coef_Q13_8 = (opus_int64) coef_Q13[ 8 ];
coef_Q13_9 = (opus_int64) coef_Q13[ 9 ];
state_0123 = _mm_loadu_si128( (__m128i *)(&state[ 0 ] ) );
state_4567 = _mm_loadu_si128( (__m128i *)(&state[ 4 ] ) );
state_0123 = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) );
state_4567 = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) );
state_8 = state[ 8 ];
state_9 = state[ 9 ];
state_a = 0;
for( n = 0; n < length; n++ )
{
xmm_product1 = _mm_mul_epi32( coef_Q13_0123, state_0123 ); /* 64-bit multiply, only 2 pairs */
xmm_product2 = _mm_mul_epi32( coef_Q13_4567, state_4567 );
xmm_tempa = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) );
xmm_tempb = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) );
xmm_product1 = _mm_srli_epi64( xmm_product1, 16 ); /* >> 16, zero extending works */
xmm_product2 = _mm_srli_epi64( xmm_product2, 16 );
xmm_tempa = _mm_mul_epi32( coef_Q13_3210, xmm_tempa );
xmm_tempb = _mm_mul_epi32( coef_Q13_7654, xmm_tempb );
xmm_tempa = _mm_srli_epi64( xmm_tempa, 16 );
xmm_tempb = _mm_srli_epi64( xmm_tempb, 16 );
xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_product1 );
xmm_tempb = _mm_add_epi32( xmm_tempb, xmm_product2 );
xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_tempb );
sum = (opus_int32)((coef_Q13_8 * state_8) >> 16);
sum += (opus_int32)((coef_Q13_9 * state_9) >> 16);
xmm_tempa = _mm_add_epi32( xmm_tempa, _mm_shuffle_epi32( xmm_tempa, _MM_SHUFFLE( 0, 0, 0, 2 ) ) );
sum += _mm_cvtsi128_si32( xmm_tempa);
res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( ( 5 + sum ), 9);
/* move right */
state_a = state_9;
state_9 = state_8;
state_8 = _mm_cvtsi128_si32( state_4567 );
state_4567 = _mm_alignr_epi8( state_0123, state_4567, 4 );
state_0123 = _mm_alignr_epi8( _mm_cvtsi32_si128( silk_LSHIFT( input[ n ], 14 ) ), state_0123, 4 );
}
_mm_storeu_si128( (__m128i *)( &state[ 0 ] ), _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ) );
_mm_storeu_si128( (__m128i *)( &state[ 4 ] ), _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ) );
state[ 8 ] = state_8;
state[ 9 ] = state_9;
state[ 10 ] = state_a;
return;
}
}
for( n = 0; n < length; n++ ) {
/* Output of lowpass section */
tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 );
state[ 0 ] = silk_LSHIFT( input[ n ], 14 );
/* Output of allpass section */
tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 );
state[ 1 ] = tmp2;
acc_Q11 = silk_RSHIFT( order, 1 );
acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] );
/* Loop over allpass sections */
for( i = 2; i < order; i += 2 ) {
/* Output of allpass section */
tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 );
state[ i ] = tmp1;
acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] );
/* Output of allpass section */
tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 );
state[ i + 1 ] = tmp2;
acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] );
}
state[ order ] = tmp1;
acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] );
res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 );
}
}

View file

@ -0,0 +1,88 @@
/* Copyright (c) 2014, Cisco Systems, INC
Written by XiangMingZhu WeiZhou MinPeng YanWang
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.
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 <xmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#include "main.h"
#include "SigProc_FIX.h"
#include "pitch.h"
opus_int64 silk_inner_prod16_aligned_64_sse4_1(
const opus_int16 *inVec1, /* I input vector 1 */
const opus_int16 *inVec2, /* I input vector 2 */
const opus_int len /* I vector lengths */
)
{
opus_int i, dataSize8;
opus_int64 sum;
__m128i xmm_tempa;
__m128i inVec1_76543210, acc1;
__m128i inVec2_76543210, acc2;
sum = 0;
dataSize8 = len & ~7;
acc1 = _mm_setzero_si128();
acc2 = _mm_setzero_si128();
for( i = 0; i < dataSize8; i += 8 ) {
inVec1_76543210 = _mm_loadu_si128( (__m128i *)(&inVec1[i + 0] ) );
inVec2_76543210 = _mm_loadu_si128( (__m128i *)(&inVec2[i + 0] ) );
/* only when all 4 operands are -32768 (0x8000), this results in wrap around */
inVec1_76543210 = _mm_madd_epi16( inVec1_76543210, inVec2_76543210 );
xmm_tempa = _mm_cvtepi32_epi64( inVec1_76543210 );
/* equal shift right 8 bytes */
inVec1_76543210 = _mm_shuffle_epi32( inVec1_76543210, _MM_SHUFFLE( 0, 0, 3, 2 ) );
inVec1_76543210 = _mm_cvtepi32_epi64( inVec1_76543210 );
acc1 = _mm_add_epi64( acc1, xmm_tempa );
acc2 = _mm_add_epi64( acc2, inVec1_76543210 );
}
acc1 = _mm_add_epi64( acc1, acc2 );
/* equal shift right 8 bytes */
acc2 = _mm_shuffle_epi32( acc1, _MM_SHUFFLE( 0, 0, 3, 2 ) );
acc1 = _mm_add_epi64( acc1, acc2 );
_mm_storel_epi64( (__m128i *)&sum, acc1 );
for( ; i < len; i++ ) {
sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] );
}
return sum;
}

View file

@ -0,0 +1,249 @@
/***********************************************************************
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 <stdlib.h>
#include "main_FLP.h"
/************************************************/
/* LPC analysis filter */
/* NB! State is kept internally and the */
/* filter always starts with zero state */
/* first Order output samples are set to zero */
/************************************************/
/* 16th order LPC analysis filter, does not write first 16 samples */
static OPUS_INLINE void silk_LPC_analysis_filter16_FLP(
silk_float r_LPC[], /* O LPC residual signal */
const silk_float PredCoef[], /* I LPC coefficients */
const silk_float s[], /* I Input signal */
const opus_int length /* I Length of input signal */
)
{
opus_int ix;
silk_float LPC_pred;
const silk_float *s_ptr;
for( ix = 16; ix < length; ix++ ) {
s_ptr = &s[ix - 1];
/* short-term prediction */
LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
s_ptr[ -1 ] * PredCoef[ 1 ] +
s_ptr[ -2 ] * PredCoef[ 2 ] +
s_ptr[ -3 ] * PredCoef[ 3 ] +
s_ptr[ -4 ] * PredCoef[ 4 ] +
s_ptr[ -5 ] * PredCoef[ 5 ] +
s_ptr[ -6 ] * PredCoef[ 6 ] +
s_ptr[ -7 ] * PredCoef[ 7 ] +
s_ptr[ -8 ] * PredCoef[ 8 ] +
s_ptr[ -9 ] * PredCoef[ 9 ] +
s_ptr[ -10 ] * PredCoef[ 10 ] +
s_ptr[ -11 ] * PredCoef[ 11 ] +
s_ptr[ -12 ] * PredCoef[ 12 ] +
s_ptr[ -13 ] * PredCoef[ 13 ] +
s_ptr[ -14 ] * PredCoef[ 14 ] +
s_ptr[ -15 ] * PredCoef[ 15 ];
/* prediction error */
r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
}
}
/* 12th order LPC analysis filter, does not write first 12 samples */
static OPUS_INLINE void silk_LPC_analysis_filter12_FLP(
silk_float r_LPC[], /* O LPC residual signal */
const silk_float PredCoef[], /* I LPC coefficients */
const silk_float s[], /* I Input signal */
const opus_int length /* I Length of input signal */
)
{
opus_int ix;
silk_float LPC_pred;
const silk_float *s_ptr;
for( ix = 12; ix < length; ix++ ) {
s_ptr = &s[ix - 1];
/* short-term prediction */
LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
s_ptr[ -1 ] * PredCoef[ 1 ] +
s_ptr[ -2 ] * PredCoef[ 2 ] +
s_ptr[ -3 ] * PredCoef[ 3 ] +
s_ptr[ -4 ] * PredCoef[ 4 ] +
s_ptr[ -5 ] * PredCoef[ 5 ] +
s_ptr[ -6 ] * PredCoef[ 6 ] +
s_ptr[ -7 ] * PredCoef[ 7 ] +
s_ptr[ -8 ] * PredCoef[ 8 ] +
s_ptr[ -9 ] * PredCoef[ 9 ] +
s_ptr[ -10 ] * PredCoef[ 10 ] +
s_ptr[ -11 ] * PredCoef[ 11 ];
/* prediction error */
r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
}
}
/* 10th order LPC analysis filter, does not write first 10 samples */
static OPUS_INLINE void silk_LPC_analysis_filter10_FLP(
silk_float r_LPC[], /* O LPC residual signal */
const silk_float PredCoef[], /* I LPC coefficients */
const silk_float s[], /* I Input signal */
const opus_int length /* I Length of input signal */
)
{
opus_int ix;
silk_float LPC_pred;
const silk_float *s_ptr;
for( ix = 10; ix < length; ix++ ) {
s_ptr = &s[ix - 1];
/* short-term prediction */
LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
s_ptr[ -1 ] * PredCoef[ 1 ] +
s_ptr[ -2 ] * PredCoef[ 2 ] +
s_ptr[ -3 ] * PredCoef[ 3 ] +
s_ptr[ -4 ] * PredCoef[ 4 ] +
s_ptr[ -5 ] * PredCoef[ 5 ] +
s_ptr[ -6 ] * PredCoef[ 6 ] +
s_ptr[ -7 ] * PredCoef[ 7 ] +
s_ptr[ -8 ] * PredCoef[ 8 ] +
s_ptr[ -9 ] * PredCoef[ 9 ];
/* prediction error */
r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
}
}
/* 8th order LPC analysis filter, does not write first 8 samples */
static OPUS_INLINE void silk_LPC_analysis_filter8_FLP(
silk_float r_LPC[], /* O LPC residual signal */
const silk_float PredCoef[], /* I LPC coefficients */
const silk_float s[], /* I Input signal */
const opus_int length /* I Length of input signal */
)
{
opus_int ix;
silk_float LPC_pred;
const silk_float *s_ptr;
for( ix = 8; ix < length; ix++ ) {
s_ptr = &s[ix - 1];
/* short-term prediction */
LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
s_ptr[ -1 ] * PredCoef[ 1 ] +
s_ptr[ -2 ] * PredCoef[ 2 ] +
s_ptr[ -3 ] * PredCoef[ 3 ] +
s_ptr[ -4 ] * PredCoef[ 4 ] +
s_ptr[ -5 ] * PredCoef[ 5 ] +
s_ptr[ -6 ] * PredCoef[ 6 ] +
s_ptr[ -7 ] * PredCoef[ 7 ];
/* prediction error */
r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
}
}
/* 6th order LPC analysis filter, does not write first 6 samples */
static OPUS_INLINE void silk_LPC_analysis_filter6_FLP(
silk_float r_LPC[], /* O LPC residual signal */
const silk_float PredCoef[], /* I LPC coefficients */
const silk_float s[], /* I Input signal */
const opus_int length /* I Length of input signal */
)
{
opus_int ix;
silk_float LPC_pred;
const silk_float *s_ptr;
for( ix = 6; ix < length; ix++ ) {
s_ptr = &s[ix - 1];
/* short-term prediction */
LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
s_ptr[ -1 ] * PredCoef[ 1 ] +
s_ptr[ -2 ] * PredCoef[ 2 ] +
s_ptr[ -3 ] * PredCoef[ 3 ] +
s_ptr[ -4 ] * PredCoef[ 4 ] +
s_ptr[ -5 ] * PredCoef[ 5 ];
/* prediction error */
r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
}
}
/************************************************/
/* LPC analysis filter */
/* NB! State is kept internally and the */
/* filter always starts with zero state */
/* first Order output samples are set to zero */
/************************************************/
void silk_LPC_analysis_filter_FLP(
silk_float r_LPC[], /* O LPC residual signal */
const silk_float PredCoef[], /* I LPC coefficients */
const silk_float s[], /* I Input signal */
const opus_int length, /* I Length of input signal */
const opus_int Order /* I LPC order */
)
{
celt_assert( Order <= length );
switch( Order ) {
case 6:
silk_LPC_analysis_filter6_FLP( r_LPC, PredCoef, s, length );
break;
case 8:
silk_LPC_analysis_filter8_FLP( r_LPC, PredCoef, s, length );
break;
case 10:
silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length );
break;
case 12:
silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length );
break;
case 16:
silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length );
break;
default:
celt_assert( 0 );
break;
}
/* Set first Order output samples to zero */
silk_memset( r_LPC, 0, Order * sizeof( silk_float ) );
}

View file

@ -0,0 +1,73 @@
/***********************************************************************
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 "SigProc_FIX.h"
#include "SigProc_FLP.h"
#include "define.h"
/* compute inverse of LPC prediction gain, and */
/* test if LPC coefficients are stable (all poles within unit circle) */
/* this code is based on silk_a2k_FLP() */
silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */
const silk_float *A, /* I prediction coefficients [order] */
opus_int32 order /* I prediction order */
)
{
opus_int k, n;
double invGain, rc, rc_mult1, rc_mult2, tmp1, tmp2;
silk_float Atmp[ SILK_MAX_ORDER_LPC ];
silk_memcpy( Atmp, A, order * sizeof(silk_float) );
invGain = 1.0;
for( k = order - 1; k > 0; k-- ) {
rc = -Atmp[ k ];
rc_mult1 = 1.0f - rc * rc;
invGain *= rc_mult1;
if( invGain * MAX_PREDICTION_POWER_GAIN < 1.0f ) {
return 0.0f;
}
rc_mult2 = 1.0f / rc_mult1;
for( n = 0; n < (k + 1) >> 1; n++ ) {
tmp1 = Atmp[ n ];
tmp2 = Atmp[ k - n - 1 ];
Atmp[ n ] = (silk_float)( ( tmp1 - tmp2 * rc ) * rc_mult2 );
Atmp[ k - n - 1 ] = (silk_float)( ( tmp2 - tmp1 * rc ) * rc_mult2 );
}
}
rc = -Atmp[ 0 ];
rc_mult1 = 1.0f - rc * rc;
invGain *= rc_mult1;
if( invGain * MAX_PREDICTION_POWER_GAIN < 1.0f ) {
return 0.0f;
}
return (silk_float)invGain;
}

View file

@ -0,0 +1,75 @@
/***********************************************************************
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_FLP.h"
void silk_LTP_analysis_filter_FLP(
silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */
const silk_float *x, /* I Input signal, with preceding samples */
const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */
const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */
const opus_int subfr_length, /* I Length of each subframe */
const opus_int nb_subfr, /* I number of subframes */
const opus_int pre_length /* I Preceding samples for each subframe */
)
{
const silk_float *x_ptr, *x_lag_ptr;
silk_float Btmp[ LTP_ORDER ];
silk_float *LTP_res_ptr;
silk_float inv_gain;
opus_int k, i, j;
x_ptr = x;
LTP_res_ptr = LTP_res;
for( k = 0; k < nb_subfr; k++ ) {
x_lag_ptr = x_ptr - pitchL[ k ];
inv_gain = invGains[ k ];
for( i = 0; i < LTP_ORDER; i++ ) {
Btmp[ i ] = B[ k * LTP_ORDER + i ];
}
/* LTP analysis FIR filter */
for( i = 0; i < subfr_length + pre_length; i++ ) {
LTP_res_ptr[ i ] = x_ptr[ i ];
/* Subtract long-term prediction */
for( j = 0; j < LTP_ORDER; j++ ) {
LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ];
}
LTP_res_ptr[ i ] *= inv_gain;
x_lag_ptr++;
}
/* Update pointers */
LTP_res_ptr += subfr_length + pre_length;
x_ptr += subfr_length;
}
}

View file

@ -0,0 +1,52 @@
/***********************************************************************
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_FLP.h"
void silk_LTP_scale_ctrl_FLP(
silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
opus_int condCoding /* I The type of conditional coding to use */
)
{
opus_int round_loss;
if( condCoding == CODE_INDEPENDENTLY ) {
/* Only scale if first frame in packet */
round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket;
psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( round_loss * psEncCtrl->LTPredCodGain * 0.1f, 0.0f, 2.0f );
} else {
/* Default is minimum scaling */
psEnc->sCmn.indices.LTP_scaleIndex = 0;
}
psEncCtrl->LTP_scale = (silk_float)silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ] / 16384.0f;
}

View file

@ -0,0 +1,197 @@
/***********************************************************************
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.
***********************************************************************/
#ifndef SILK_SIGPROC_FLP_H
#define SILK_SIGPROC_FLP_H
#include "SigProc_FIX.h"
#include "float_cast.h"
#include <math.h>
#ifdef __cplusplus
extern "C"
{
#endif
/********************************************************************/
/* SIGNAL PROCESSING FUNCTIONS */
/********************************************************************/
/* Chirp (bw expand) LP AR filter */
void silk_bwexpander_FLP(
silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */
const opus_int d, /* I length of ar */
const silk_float chirp /* I chirp factor (typically in range (0..1) ) */
);
/* compute inverse of LPC prediction gain, and */
/* test if LPC coefficients are stable (all poles within unit circle) */
/* this code is based on silk_FLP_a2k() */
silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */
const silk_float *A, /* I prediction coefficients [order] */
opus_int32 order /* I prediction order */
);
silk_float silk_schur_FLP( /* O returns residual energy */
silk_float refl_coef[], /* O reflection coefficients (length order) */
const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */
opus_int order /* I order */
);
void silk_k2a_FLP(
silk_float *A, /* O prediction coefficients [order] */
const silk_float *rc, /* I reflection coefficients [order] */
opus_int32 order /* I prediction order */
);
/* compute autocorrelation */
void silk_autocorrelation_FLP(
silk_float *results, /* O result (length correlationCount) */
const silk_float *inputData, /* I input data to correlate */
opus_int inputDataSize, /* I length of input */
opus_int correlationCount /* I number of correlation taps to compute */
);
opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */
const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */
opus_int16 *lagIndex, /* O Lag Index */
opus_int8 *contourIndex, /* O Pitch contour Index */
silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */
opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */
const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */
const opus_int Fs_kHz, /* I sample frequency (kHz) */
const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
const opus_int nb_subfr, /* I Number of 5 ms subframes */
int arch /* I Run-time architecture */
);
void silk_insertion_sort_decreasing_FLP(
silk_float *a, /* I/O Unsorted / Sorted vector */
opus_int *idx, /* O Index vector for the sorted elements */
const opus_int L, /* I Vector length */
const opus_int K /* I Number of correctly sorted positions */
);
/* Compute reflection coefficients from input signal */
silk_float silk_burg_modified_FLP( /* O returns residual energy */
silk_float A[], /* O prediction coefficients (length order) */
const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */
const silk_float minInvGain, /* I minimum inverse prediction gain */
const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */
const opus_int nb_subfr, /* I number of subframes stacked in x */
const opus_int D /* I order */
);
/* multiply a vector by a constant */
void silk_scale_vector_FLP(
silk_float *data1,
silk_float gain,
opus_int dataSize
);
/* copy and multiply a vector by a constant */
void silk_scale_copy_vector_FLP(
silk_float *data_out,
const silk_float *data_in,
silk_float gain,
opus_int dataSize
);
/* inner product of two silk_float arrays, with result as double */
double silk_inner_product_FLP(
const silk_float *data1,
const silk_float *data2,
opus_int dataSize
);
/* sum of squares of a silk_float array, with result as double */
double silk_energy_FLP(
const silk_float *data,
opus_int dataSize
);
/********************************************************************/
/* MACROS */
/********************************************************************/
#define PI (3.1415926536f)
#define silk_min_float( a, b ) (((a) < (b)) ? (a) : (b))
#define silk_max_float( a, b ) (((a) > (b)) ? (a) : (b))
#define silk_abs_float( a ) ((silk_float)fabs(a))
/* sigmoid function */
static OPUS_INLINE silk_float silk_sigmoid( silk_float x )
{
return (silk_float)(1.0 / (1.0 + exp(-x)));
}
/* floating-point to integer conversion (rounding) */
static OPUS_INLINE opus_int32 silk_float2int( silk_float x )
{
return (opus_int32)float2int( x );
}
/* floating-point to integer conversion (rounding) */
static OPUS_INLINE void silk_float2short_array(
opus_int16 *out,
const silk_float *in,
opus_int32 length
)
{
opus_int32 k;
for( k = length - 1; k >= 0; k-- ) {
out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) );
}
}
/* integer to floating-point conversion */
static OPUS_INLINE void silk_short2float_array(
silk_float *out,
const opus_int16 *in,
opus_int32 length
)
{
opus_int32 k;
for( k = length - 1; k >= 0; k-- ) {
out[k] = (silk_float)in[k];
}
}
/* using log2() helps the fixed-point conversion */
static OPUS_INLINE silk_float silk_log2( double x )
{
return ( silk_float )( 3.32192809488736 * log10( x ) );
}
#ifdef __cplusplus
}
#endif
#endif /* SILK_SIGPROC_FLP_H */

View file

@ -0,0 +1,81 @@
/***********************************************************************
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_FLP.h"
/* Apply sine window to signal vector */
/* Window types: */
/* 1 -> sine window from 0 to pi/2 */
/* 2 -> sine window from pi/2 to pi */
void silk_apply_sine_window_FLP(
silk_float px_win[], /* O Pointer to windowed signal */
const silk_float px[], /* I Pointer to input signal */
const opus_int win_type, /* I Selects a window type */
const opus_int length /* I Window length, multiple of 4 */
)
{
opus_int k;
silk_float freq, c, S0, S1;
celt_assert( win_type == 1 || win_type == 2 );
/* Length must be multiple of 4 */
celt_assert( ( length & 3 ) == 0 );
freq = PI / ( length + 1 );
/* Approximation of 2 * cos(f) */
c = 2.0f - freq * freq;
/* Initialize state */
if( win_type < 2 ) {
/* Start from 0 */
S0 = 0.0f;
/* Approximation of sin(f) */
S1 = freq;
} else {
/* Start from 1 */
S0 = 1.0f;
/* Approximation of cos(f) */
S1 = 0.5f * c;
}
/* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */
/* 4 samples at a time */
for( k = 0; k < length; k += 4 ) {
px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 );
px_win[ k + 1 ] = px[ k + 1 ] * S1;
S0 = c * S1 - S0;
px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 );
px_win[ k + 3 ] = px[ k + 3 ] * S0;
S1 = c * S0 - S1;
}
}

View file

@ -0,0 +1,52 @@
/***********************************************************************
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 "typedef.h"
#include "SigProc_FLP.h"
/* compute autocorrelation */
void silk_autocorrelation_FLP(
silk_float *results, /* O result (length correlationCount) */
const silk_float *inputData, /* I input data to correlate */
opus_int inputDataSize, /* I length of input */
opus_int correlationCount /* I number of correlation taps to compute */
)
{
opus_int i;
if( correlationCount > inputDataSize ) {
correlationCount = inputDataSize;
}
for( i = 0; i < correlationCount; i++ ) {
results[ i ] = (silk_float)silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i );
}
}

Some files were not shown because too many files have changed in this diff Show more