/src/mozilla-central/media/libopus/silk/PLC.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*********************************************************************** |
2 | | Copyright (c) 2006-2011, Skype Limited. All rights reserved. |
3 | | Redistribution and use in source and binary forms, with or without |
4 | | modification, are permitted provided that the following conditions |
5 | | are met: |
6 | | - Redistributions of source code must retain the above copyright notice, |
7 | | this list of conditions and the following disclaimer. |
8 | | - Redistributions in binary form must reproduce the above copyright |
9 | | notice, this list of conditions and the following disclaimer in the |
10 | | documentation and/or other materials provided with the distribution. |
11 | | - Neither the name of Internet Society, IETF or IETF Trust, nor the |
12 | | names of specific contributors, may be used to endorse or promote |
13 | | products derived from this software without specific prior written |
14 | | permission. |
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 | | POSSIBILITY OF SUCH DAMAGE. |
26 | | ***********************************************************************/ |
27 | | |
28 | | #ifdef HAVE_CONFIG_H |
29 | | #include "config.h" |
30 | | #endif |
31 | | |
32 | | #include "main.h" |
33 | | #include "stack_alloc.h" |
34 | | #include "PLC.h" |
35 | | |
36 | 0 | #define NB_ATT 2 |
37 | | static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ |
38 | | static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ |
39 | | static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ |
40 | | |
41 | | static OPUS_INLINE void silk_PLC_update( |
42 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
43 | | silk_decoder_control *psDecCtrl /* I/O Decoder control */ |
44 | | ); |
45 | | |
46 | | static OPUS_INLINE void silk_PLC_conceal( |
47 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
48 | | silk_decoder_control *psDecCtrl, /* I/O Decoder control */ |
49 | | opus_int16 frame[], /* O LPC residual signal */ |
50 | | int arch /* I Run-time architecture */ |
51 | | ); |
52 | | |
53 | | |
54 | | void silk_PLC_Reset( |
55 | | silk_decoder_state *psDec /* I/O Decoder state */ |
56 | | ) |
57 | 0 | { |
58 | 0 | psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); |
59 | 0 | psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); |
60 | 0 | psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); |
61 | 0 | psDec->sPLC.subfr_length = 20; |
62 | 0 | psDec->sPLC.nb_subfr = 2; |
63 | 0 | } |
64 | | |
65 | | void silk_PLC( |
66 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
67 | | silk_decoder_control *psDecCtrl, /* I/O Decoder control */ |
68 | | opus_int16 frame[], /* I/O signal */ |
69 | | opus_int lost, /* I Loss flag */ |
70 | | int arch /* I Run-time architecture */ |
71 | | ) |
72 | 0 | { |
73 | 0 | /* PLC control function */ |
74 | 0 | if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { |
75 | 0 | silk_PLC_Reset( psDec ); |
76 | 0 | psDec->sPLC.fs_kHz = psDec->fs_kHz; |
77 | 0 | } |
78 | 0 |
|
79 | 0 | if( lost ) { |
80 | 0 | /****************************/ |
81 | 0 | /* Generate Signal */ |
82 | 0 | /****************************/ |
83 | 0 | silk_PLC_conceal( psDec, psDecCtrl, frame, arch ); |
84 | 0 |
|
85 | 0 | psDec->lossCnt++; |
86 | 0 | } else { |
87 | 0 | /****************************/ |
88 | 0 | /* Update state */ |
89 | 0 | /****************************/ |
90 | 0 | silk_PLC_update( psDec, psDecCtrl ); |
91 | 0 | } |
92 | 0 | } |
93 | | |
94 | | /**************************************************/ |
95 | | /* Update state of PLC */ |
96 | | /**************************************************/ |
97 | | static OPUS_INLINE void silk_PLC_update( |
98 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
99 | | silk_decoder_control *psDecCtrl /* I/O Decoder control */ |
100 | | ) |
101 | 0 | { |
102 | 0 | opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; |
103 | 0 | opus_int i, j; |
104 | 0 | silk_PLC_struct *psPLC; |
105 | 0 |
|
106 | 0 | psPLC = &psDec->sPLC; |
107 | 0 |
|
108 | 0 | /* Update parameters used in case of packet loss */ |
109 | 0 | psDec->prevSignalType = psDec->indices.signalType; |
110 | 0 | LTP_Gain_Q14 = 0; |
111 | 0 | if( psDec->indices.signalType == TYPE_VOICED ) { |
112 | 0 | /* Find the parameters for the last subframe which contains a pitch pulse */ |
113 | 0 | for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { |
114 | 0 | if( j == psDec->nb_subfr ) { |
115 | 0 | break; |
116 | 0 | } |
117 | 0 | temp_LTP_Gain_Q14 = 0; |
118 | 0 | for( i = 0; i < LTP_ORDER; i++ ) { |
119 | 0 | temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; |
120 | 0 | } |
121 | 0 | if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { |
122 | 0 | LTP_Gain_Q14 = temp_LTP_Gain_Q14; |
123 | 0 | silk_memcpy( psPLC->LTPCoef_Q14, |
124 | 0 | &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], |
125 | 0 | LTP_ORDER * sizeof( opus_int16 ) ); |
126 | 0 |
|
127 | 0 | psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); |
128 | 0 | } |
129 | 0 | } |
130 | 0 |
|
131 | 0 | silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); |
132 | 0 | psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; |
133 | 0 |
|
134 | 0 | /* Limit LT coefs */ |
135 | 0 | if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { |
136 | 0 | opus_int scale_Q10; |
137 | 0 | opus_int32 tmp; |
138 | 0 |
|
139 | 0 | tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); |
140 | 0 | scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); |
141 | 0 | for( i = 0; i < LTP_ORDER; i++ ) { |
142 | 0 | psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); |
143 | 0 | } |
144 | 0 | } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { |
145 | 0 | opus_int scale_Q14; |
146 | 0 | opus_int32 tmp; |
147 | 0 |
|
148 | 0 | tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); |
149 | 0 | scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); |
150 | 0 | for( i = 0; i < LTP_ORDER; i++ ) { |
151 | 0 | psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); |
152 | 0 | } |
153 | 0 | } |
154 | 0 | } else { |
155 | 0 | psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); |
156 | 0 | silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); |
157 | 0 | } |
158 | 0 |
|
159 | 0 | /* Save LPC coeficients */ |
160 | 0 | silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); |
161 | 0 | psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; |
162 | 0 |
|
163 | 0 | /* Save last two gains */ |
164 | 0 | silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); |
165 | 0 |
|
166 | 0 | psPLC->subfr_length = psDec->subfr_length; |
167 | 0 | psPLC->nb_subfr = psDec->nb_subfr; |
168 | 0 | } |
169 | | |
170 | | static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2, |
171 | | const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr) |
172 | 0 | { |
173 | 0 | int i, k; |
174 | 0 | VARDECL( opus_int16, exc_buf ); |
175 | 0 | opus_int16 *exc_buf_ptr; |
176 | 0 | SAVE_STACK; |
177 | 0 | ALLOC( exc_buf, 2*subfr_length, opus_int16 ); |
178 | 0 | /* Find random noise component */ |
179 | 0 | /* Scale previous excitation signal */ |
180 | 0 | exc_buf_ptr = exc_buf; |
181 | 0 | for( k = 0; k < 2; k++ ) { |
182 | 0 | for( i = 0; i < subfr_length; i++ ) { |
183 | 0 | exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( |
184 | 0 | silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) ); |
185 | 0 | } |
186 | 0 | exc_buf_ptr += subfr_length; |
187 | 0 | } |
188 | 0 | /* Find the subframe with lowest energy of the last two and use that as random noise generator */ |
189 | 0 | silk_sum_sqr_shift( energy1, shift1, exc_buf, subfr_length ); |
190 | 0 | silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length ); |
191 | 0 | RESTORE_STACK; |
192 | 0 | } |
193 | | |
194 | | static OPUS_INLINE void silk_PLC_conceal( |
195 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
196 | | silk_decoder_control *psDecCtrl, /* I/O Decoder control */ |
197 | | opus_int16 frame[], /* O LPC residual signal */ |
198 | | int arch /* I Run-time architecture */ |
199 | | ) |
200 | 0 | { |
201 | 0 | opus_int i, j, k; |
202 | 0 | opus_int lag, idx, sLTP_buf_idx, shift1, shift2; |
203 | 0 | opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; |
204 | 0 | opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; |
205 | 0 | opus_int32 LPC_pred_Q10, LTP_pred_Q12; |
206 | 0 | opus_int16 rand_scale_Q14; |
207 | 0 | opus_int16 *B_Q14; |
208 | 0 | opus_int32 *sLPC_Q14_ptr; |
209 | 0 | opus_int16 A_Q12[ MAX_LPC_ORDER ]; |
210 | | #ifdef SMALL_FOOTPRINT |
211 | | opus_int16 *sLTP; |
212 | | #else |
213 | 0 | VARDECL( opus_int16, sLTP ); |
214 | 0 | #endif |
215 | 0 | VARDECL( opus_int32, sLTP_Q14 ); |
216 | 0 | silk_PLC_struct *psPLC = &psDec->sPLC; |
217 | 0 | opus_int32 prevGain_Q10[2]; |
218 | 0 | SAVE_STACK; |
219 | 0 |
|
220 | 0 | ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); |
221 | | #ifdef SMALL_FOOTPRINT |
222 | | /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */ |
223 | | sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length; |
224 | | #else |
225 | 0 | ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); |
226 | 0 | #endif |
227 | 0 |
|
228 | 0 | prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); |
229 | 0 | prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); |
230 | 0 |
|
231 | 0 | if( psDec->first_frame_after_reset ) { |
232 | 0 | silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); |
233 | 0 | } |
234 | 0 |
|
235 | 0 | silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr); |
236 | 0 |
|
237 | 0 | if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { |
238 | 0 | /* First sub-frame has lowest energy */ |
239 | 0 | rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; |
240 | 0 | } else { |
241 | 0 | /* Second sub-frame has lowest energy */ |
242 | 0 | rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; |
243 | 0 | } |
244 | 0 |
|
245 | 0 | /* Set up Gain to random noise component */ |
246 | 0 | B_Q14 = psPLC->LTPCoef_Q14; |
247 | 0 | rand_scale_Q14 = psPLC->randScale_Q14; |
248 | 0 |
|
249 | 0 | /* Set up attenuation gains */ |
250 | 0 | harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; |
251 | 0 | if( psDec->prevSignalType == TYPE_VOICED ) { |
252 | 0 | rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; |
253 | 0 | } else { |
254 | 0 | rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; |
255 | 0 | } |
256 | 0 |
|
257 | 0 | /* LPC concealment. Apply BWE to previous LPC */ |
258 | 0 | silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); |
259 | 0 |
|
260 | 0 | /* Preload LPC coeficients to array on stack. Gives small performance gain */ |
261 | 0 | silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); |
262 | 0 |
|
263 | 0 | /* First Lost frame */ |
264 | 0 | if( psDec->lossCnt == 0 ) { |
265 | 0 | rand_scale_Q14 = 1 << 14; |
266 | 0 |
|
267 | 0 | /* Reduce random noise Gain for voiced frames */ |
268 | 0 | if( psDec->prevSignalType == TYPE_VOICED ) { |
269 | 0 | for( i = 0; i < LTP_ORDER; i++ ) { |
270 | 0 | rand_scale_Q14 -= B_Q14[ i ]; |
271 | 0 | } |
272 | 0 | rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ |
273 | 0 | rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); |
274 | 0 | } else { |
275 | 0 | /* Reduce random noise for unvoiced frames with high LPC gain */ |
276 | 0 | opus_int32 invGain_Q30, down_scale_Q30; |
277 | 0 |
|
278 | 0 | invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch ); |
279 | 0 |
|
280 | 0 | down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); |
281 | 0 | down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); |
282 | 0 | down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); |
283 | 0 |
|
284 | 0 | rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); |
285 | 0 | } |
286 | 0 | } |
287 | 0 |
|
288 | 0 | rand_seed = psPLC->rand_seed; |
289 | 0 | lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); |
290 | 0 | sLTP_buf_idx = psDec->ltp_mem_length; |
291 | 0 |
|
292 | 0 | /* Rewhiten LTP state */ |
293 | 0 | idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; |
294 | 0 | celt_assert( idx > 0 ); |
295 | 0 | silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch ); |
296 | 0 | /* Scale LTP state */ |
297 | 0 | inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); |
298 | 0 | inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); |
299 | 0 | for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { |
300 | 0 | sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); |
301 | 0 | } |
302 | 0 |
|
303 | 0 | /***************************/ |
304 | 0 | /* LTP synthesis filtering */ |
305 | 0 | /***************************/ |
306 | 0 | for( k = 0; k < psDec->nb_subfr; k++ ) { |
307 | 0 | /* Set up pointer */ |
308 | 0 | pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; |
309 | 0 | for( i = 0; i < psDec->subfr_length; i++ ) { |
310 | 0 | /* Unrolled loop */ |
311 | 0 | /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ |
312 | 0 | LTP_pred_Q12 = 2; |
313 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); |
314 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); |
315 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); |
316 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); |
317 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); |
318 | 0 | pred_lag_ptr++; |
319 | 0 |
|
320 | 0 | /* Generate LPC excitation */ |
321 | 0 | rand_seed = silk_RAND( rand_seed ); |
322 | 0 | idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; |
323 | 0 | sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); |
324 | 0 | sLTP_buf_idx++; |
325 | 0 | } |
326 | 0 |
|
327 | 0 | /* Gradually reduce LTP gain */ |
328 | 0 | for( j = 0; j < LTP_ORDER; j++ ) { |
329 | 0 | B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); |
330 | 0 | } |
331 | 0 | if ( psDec->indices.signalType != TYPE_NO_VOICE_ACTIVITY ) { |
332 | 0 | /* Gradually reduce excitation gain */ |
333 | 0 | rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); |
334 | 0 | } |
335 | 0 |
|
336 | 0 | /* Slowly increase pitch lag */ |
337 | 0 | psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); |
338 | 0 | psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); |
339 | 0 | lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); |
340 | 0 | } |
341 | 0 |
|
342 | 0 | /***************************/ |
343 | 0 | /* LPC synthesis filtering */ |
344 | 0 | /***************************/ |
345 | 0 | sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; |
346 | 0 |
|
347 | 0 | /* Copy LPC state */ |
348 | 0 | silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); |
349 | 0 |
|
350 | 0 | celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ |
351 | 0 | for( i = 0; i < psDec->frame_length; i++ ) { |
352 | 0 | /* partly unrolled */ |
353 | 0 | /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ |
354 | 0 | LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); |
355 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); |
356 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); |
357 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); |
358 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); |
359 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); |
360 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); |
361 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); |
362 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); |
363 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); |
364 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); |
365 | 0 | for( j = 10; j < psDec->LPC_order; j++ ) { |
366 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); |
367 | 0 | } |
368 | 0 |
|
369 | 0 | /* Add prediction to LPC excitation */ |
370 | 0 | sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], |
371 | 0 | silk_LSHIFT_SAT32( LPC_pred_Q10, 4 )); |
372 | 0 |
|
373 | 0 | /* Scale with Gain */ |
374 | 0 | frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); |
375 | 0 | } |
376 | 0 |
|
377 | 0 | /* Save LPC state */ |
378 | 0 | silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); |
379 | 0 |
|
380 | 0 | /**************************************/ |
381 | 0 | /* Update states */ |
382 | 0 | /**************************************/ |
383 | 0 | psPLC->rand_seed = rand_seed; |
384 | 0 | psPLC->randScale_Q14 = rand_scale_Q14; |
385 | 0 | for( i = 0; i < MAX_NB_SUBFR; i++ ) { |
386 | 0 | psDecCtrl->pitchL[ i ] = lag; |
387 | 0 | } |
388 | 0 | RESTORE_STACK; |
389 | 0 | } |
390 | | |
391 | | /* Glues concealed frames with new good received frames */ |
392 | | void silk_PLC_glue_frames( |
393 | | silk_decoder_state *psDec, /* I/O decoder state */ |
394 | | opus_int16 frame[], /* I/O signal */ |
395 | | opus_int length /* I length of signal */ |
396 | | ) |
397 | 0 | { |
398 | 0 | opus_int i, energy_shift; |
399 | 0 | opus_int32 energy; |
400 | 0 | silk_PLC_struct *psPLC; |
401 | 0 | psPLC = &psDec->sPLC; |
402 | 0 |
|
403 | 0 | if( psDec->lossCnt ) { |
404 | 0 | /* Calculate energy in concealed residual */ |
405 | 0 | silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); |
406 | 0 |
|
407 | 0 | psPLC->last_frame_lost = 1; |
408 | 0 | } else { |
409 | 0 | if( psDec->sPLC.last_frame_lost ) { |
410 | 0 | /* Calculate residual in decoded signal if last frame was lost */ |
411 | 0 | silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); |
412 | 0 |
|
413 | 0 | /* Normalize energies */ |
414 | 0 | if( energy_shift > psPLC->conc_energy_shift ) { |
415 | 0 | psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); |
416 | 0 | } else if( energy_shift < psPLC->conc_energy_shift ) { |
417 | 0 | energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); |
418 | 0 | } |
419 | 0 |
|
420 | 0 | /* Fade in the energy difference */ |
421 | 0 | if( energy > psPLC->conc_energy ) { |
422 | 0 | opus_int32 frac_Q24, LZ; |
423 | 0 | opus_int32 gain_Q16, slope_Q16; |
424 | 0 |
|
425 | 0 | LZ = silk_CLZ32( psPLC->conc_energy ); |
426 | 0 | LZ = LZ - 1; |
427 | 0 | psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); |
428 | 0 | energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); |
429 | 0 |
|
430 | 0 | frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); |
431 | 0 |
|
432 | 0 | gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); |
433 | 0 | slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); |
434 | 0 | /* Make slope 4x steeper to avoid missing onsets after DTX */ |
435 | 0 | slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); |
436 | 0 |
|
437 | 0 | for( i = 0; i < length; i++ ) { |
438 | 0 | frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); |
439 | 0 | gain_Q16 += slope_Q16; |
440 | 0 | if( gain_Q16 > (opus_int32)1 << 16 ) { |
441 | 0 | break; |
442 | 0 | } |
443 | 0 | } |
444 | 0 | } |
445 | 0 | } |
446 | 0 | psPLC->last_frame_lost = 0; |
447 | 0 | } |
448 | 0 | } |