summaryrefslogtreecommitdiff
path: root/silk/LPC_inv_pred_gain.c
diff options
context:
space:
mode:
authorJean-Marc Valin <jmvalin@jmvalin.ca>2011-09-16 01:16:53 -0700
committerJean-Marc Valin <jmvalin@jmvalin.ca>2011-09-16 01:16:53 -0700
commit1c2f5633d101c08b5ef8095a8682d3d52cbd952d (patch)
tree66f80e67f075db5fa5233759a89f475d8bedade2 /silk/LPC_inv_pred_gain.c
parentfb3a437c9dabb4aafe4a3927158161590ed745ab (diff)
downloadopus-1c2f5633d101c08b5ef8095a8682d3d52cbd952d.tar.gz
Removed all the silk_ prefixes in source file names (not symbols)
Diffstat (limited to 'silk/LPC_inv_pred_gain.c')
-rw-r--r--silk/LPC_inv_pred_gain.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/silk/LPC_inv_pred_gain.c b/silk/LPC_inv_pred_gain.c
new file mode 100644
index 00000000..1669745d
--- /dev/null
+++ b/silk/LPC_inv_pred_gain.c
@@ -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, (subject to the limitations in the disclaimer below)
+are permitted provided that the following conditions are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Skype Limited, nor the names of specific
+contributors, may be used to endorse or promote products derived from
+this software without specific prior written permission.
+NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED
+BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+#define QA 16
+#define A_LIMIT SILK_FIX_CONST( 0.99975, QA )
+
+/* Compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+static opus_int LPC_inverse_pred_gain_QA( /* O: Returns 1 if unstable, otherwise 0 */
+ opus_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */
+ opus_int32 A_QA[ 2 ][ SILK_MAX_ORDER_LPC ],
+ /* I: Prediction coefficients */
+ const opus_int order /* I: Prediction order */
+)
+{
+ opus_int k, n, headrm;
+ opus_int32 rc_Q31, rc_mult1_Q30, rc_mult2_Q16, tmp_QA;
+ opus_int32 *Aold_QA, *Anew_QA;
+
+ Anew_QA = A_QA[ order & 1 ];
+
+ *invGain_Q30 = ( 1 << 30 );
+ for( k = order - 1; k > 0; k-- ) {
+ /* Check for stability */
+ if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) {
+ return 1;
+ }
+
+ /* Set RC equal to negated AR coef */
+ rc_Q31 = -silk_LSHIFT( Anew_QA[ k ], 31 - QA );
+
+ /* rc_mult1_Q30 range: [ 1 : 2^30-1 ] */
+ rc_mult1_Q30 = ( silk_int32_MAX >> 1 ) - 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_Q16 range: [ 2^16 : silk_int32_MAX ] */
+ rc_mult2_Q16 = silk_INVERSE32_varQ( rc_mult1_Q30, 46 ); /* 16 = 46 - 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 ) );
+
+ /* Swap pointers */
+ Aold_QA = Anew_QA;
+ Anew_QA = A_QA[ k & 1 ];
+
+ /* Update AR coefficient */
+ headrm = silk_CLZ32( rc_mult2_Q16 ) - 1;
+ rc_mult2_Q16 = silk_LSHIFT( rc_mult2_Q16, headrm ); /* Q: 16 + headrm */
+ for( n = 0; n < k; n++ ) {
+ tmp_QA = Aold_QA[ n ] - silk_LSHIFT( silk_SMMUL( Aold_QA[ k - n - 1 ], rc_Q31 ), 1 );
+ Anew_QA[ n ] = silk_LSHIFT( silk_SMMUL( tmp_QA, rc_mult2_Q16 ), 16 - headrm );
+ }
+ }
+
+ /* Check for stability */
+ if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) {
+ return 1;
+ }
+
+ /* Set RC equal to negated AR coef */
+ rc_Q31 = -silk_LSHIFT( Anew_QA[ 0 ], 31 - QA );
+
+ /* Range: [ 1 : 2^30 ] */
+ rc_mult1_Q30 = ( silk_int32_MAX >> 1 ) - 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 );
+
+ return 0;
+}
+
+/* For input in Q12 domain */
+opus_int silk_LPC_inverse_pred_gain( /* O: Returns 1 if unstable, otherwise 0 */
+ opus_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */
+ 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;
+
+ Anew_QA = Atmp_QA[ order & 1 ];
+
+ /* Increase Q domain of the AR coefficients */
+ for( k = 0; k < order; k++ ) {
+ Anew_QA[ k ] = silk_LSHIFT( (opus_int32)A_Q12[ k ], QA - 12 );
+ }
+
+ return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order );
+}
+
+/* For input in Q24 domain */
+opus_int silk_LPC_inverse_pred_gain_Q24( /* O: Returns 1 if unstable, otherwise 0 */
+ opus_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */
+ const opus_int32 *A_Q24, /* I: Prediction coefficients, Q24 [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_RSHIFT_ROUND( A_Q24[ k ], 24 - QA );
+ }
+
+ return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order );
+}
+