1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libopus/silk/CNG.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,172 @@ 1.4 +/*********************************************************************** 1.5 +Copyright (c) 2006-2011, Skype Limited. All rights reserved. 1.6 +Redistribution and use in source and binary forms, with or without 1.7 +modification, are permitted provided that the following conditions 1.8 +are met: 1.9 +- Redistributions of source code must retain the above copyright notice, 1.10 +this list of conditions and the following disclaimer. 1.11 +- Redistributions in binary form must reproduce the above copyright 1.12 +notice, this list of conditions and the following disclaimer in the 1.13 +documentation and/or other materials provided with the distribution. 1.14 +- Neither the name of Internet Society, IETF or IETF Trust, nor the 1.15 +names of specific contributors, may be used to endorse or promote 1.16 +products derived from this software without specific prior written 1.17 +permission. 1.18 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.19 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.20 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.21 +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 1.22 +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.23 +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.24 +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.25 +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.26 +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.27 +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.28 +POSSIBILITY OF SUCH DAMAGE. 1.29 +***********************************************************************/ 1.30 + 1.31 +#ifdef HAVE_CONFIG_H 1.32 +#include "config.h" 1.33 +#endif 1.34 + 1.35 +#include "main.h" 1.36 +#include "stack_alloc.h" 1.37 + 1.38 +/* Generates excitation for CNG LPC synthesis */ 1.39 +static OPUS_INLINE void silk_CNG_exc( 1.40 + opus_int32 residual_Q10[], /* O CNG residual signal Q10 */ 1.41 + opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */ 1.42 + opus_int32 Gain_Q16, /* I Gain to apply */ 1.43 + opus_int length, /* I Length */ 1.44 + opus_int32 *rand_seed /* I/O Seed to random index generator */ 1.45 +) 1.46 +{ 1.47 + opus_int32 seed; 1.48 + opus_int i, idx, exc_mask; 1.49 + 1.50 + exc_mask = CNG_BUF_MASK_MAX; 1.51 + while( exc_mask > length ) { 1.52 + exc_mask = silk_RSHIFT( exc_mask, 1 ); 1.53 + } 1.54 + 1.55 + seed = *rand_seed; 1.56 + for( i = 0; i < length; i++ ) { 1.57 + seed = silk_RAND( seed ); 1.58 + idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask ); 1.59 + silk_assert( idx >= 0 ); 1.60 + silk_assert( idx <= CNG_BUF_MASK_MAX ); 1.61 + residual_Q10[ i ] = (opus_int16)silk_SAT16( silk_SMULWW( exc_buf_Q14[ idx ], Gain_Q16 >> 4 ) ); 1.62 + } 1.63 + *rand_seed = seed; 1.64 +} 1.65 + 1.66 +void silk_CNG_Reset( 1.67 + silk_decoder_state *psDec /* I/O Decoder state */ 1.68 +) 1.69 +{ 1.70 + opus_int i, NLSF_step_Q15, NLSF_acc_Q15; 1.71 + 1.72 + NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 ); 1.73 + NLSF_acc_Q15 = 0; 1.74 + for( i = 0; i < psDec->LPC_order; i++ ) { 1.75 + NLSF_acc_Q15 += NLSF_step_Q15; 1.76 + psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15; 1.77 + } 1.78 + psDec->sCNG.CNG_smth_Gain_Q16 = 0; 1.79 + psDec->sCNG.rand_seed = 3176576; 1.80 +} 1.81 + 1.82 +/* Updates CNG estimate, and applies the CNG when packet was lost */ 1.83 +void silk_CNG( 1.84 + silk_decoder_state *psDec, /* I/O Decoder state */ 1.85 + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ 1.86 + opus_int16 frame[], /* I/O Signal */ 1.87 + opus_int length /* I Length of residual */ 1.88 +) 1.89 +{ 1.90 + opus_int i, subfr; 1.91 + opus_int32 sum_Q6, max_Gain_Q16; 1.92 + opus_int16 A_Q12[ MAX_LPC_ORDER ]; 1.93 + silk_CNG_struct *psCNG = &psDec->sCNG; 1.94 + SAVE_STACK; 1.95 + 1.96 + if( psDec->fs_kHz != psCNG->fs_kHz ) { 1.97 + /* Reset state */ 1.98 + silk_CNG_Reset( psDec ); 1.99 + 1.100 + psCNG->fs_kHz = psDec->fs_kHz; 1.101 + } 1.102 + if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) { 1.103 + /* Update CNG parameters */ 1.104 + 1.105 + /* Smoothing of LSF's */ 1.106 + for( i = 0; i < psDec->LPC_order; i++ ) { 1.107 + psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 ); 1.108 + } 1.109 + /* Find the subframe with the highest gain */ 1.110 + max_Gain_Q16 = 0; 1.111 + subfr = 0; 1.112 + for( i = 0; i < psDec->nb_subfr; i++ ) { 1.113 + if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) { 1.114 + max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; 1.115 + subfr = i; 1.116 + } 1.117 + } 1.118 + /* Update CNG excitation buffer with excitation from this subframe */ 1.119 + silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) ); 1.120 + silk_memcpy( psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) ); 1.121 + 1.122 + /* Smooth gains */ 1.123 + for( i = 0; i < psDec->nb_subfr; i++ ) { 1.124 + psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); 1.125 + } 1.126 + } 1.127 + 1.128 + /* Add CNG when packet is lost or during DTX */ 1.129 + if( psDec->lossCnt ) { 1.130 + VARDECL( opus_int32, CNG_sig_Q10 ); 1.131 + 1.132 + ALLOC( CNG_sig_Q10, length + MAX_LPC_ORDER, opus_int32 ); 1.133 + 1.134 + /* Generate CNG excitation */ 1.135 + silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed ); 1.136 + 1.137 + /* Convert CNG NLSF to filter representation */ 1.138 + silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order ); 1.139 + 1.140 + /* Generate CNG signal, by synthesis filtering */ 1.141 + silk_memcpy( CNG_sig_Q10, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) ); 1.142 + for( i = 0; i < length; i++ ) { 1.143 + silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); 1.144 + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ 1.145 + sum_Q6 = silk_RSHIFT( psDec->LPC_order, 1 ); 1.146 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); 1.147 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); 1.148 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); 1.149 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); 1.150 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); 1.151 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); 1.152 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); 1.153 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); 1.154 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); 1.155 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); 1.156 + if( psDec->LPC_order == 16 ) { 1.157 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] ); 1.158 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] ); 1.159 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] ); 1.160 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] ); 1.161 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] ); 1.162 + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] ); 1.163 + } 1.164 + 1.165 + /* Update states */ 1.166 + CNG_sig_Q10[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q10[ MAX_LPC_ORDER + i ], sum_Q6, 4 ); 1.167 + 1.168 + frame[ i ] = silk_ADD_SAT16( frame[ i ], silk_RSHIFT_ROUND( sum_Q6, 6 ) ); 1.169 + } 1.170 + silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q10[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); 1.171 + } else { 1.172 + silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) ); 1.173 + } 1.174 + RESTORE_STACK; 1.175 +}