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 | | #ifdef ENABLE_DEEP_PLC |
37 | | #include "lpcnet.h" |
38 | | #endif |
39 | | |
40 | 0 | #define NB_ATT 2 |
41 | | static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ |
42 | | static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ |
43 | | static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ |
44 | | |
45 | | static OPUS_INLINE void silk_PLC_update( |
46 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
47 | | silk_decoder_control *psDecCtrl /* I/O Decoder control */ |
48 | | ); |
49 | | |
50 | | static OPUS_INLINE void silk_PLC_conceal( |
51 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
52 | | silk_decoder_control *psDecCtrl, /* I/O Decoder control */ |
53 | | opus_int16 frame[], /* O LPC residual signal */ |
54 | | #ifdef ENABLE_DEEP_PLC |
55 | | LPCNetPLCState *lpcnet, |
56 | | #endif |
57 | | int arch /* I Run-time architecture */ |
58 | | ); |
59 | | |
60 | | |
61 | | void silk_PLC_Reset( |
62 | | silk_decoder_state *psDec /* I/O Decoder state */ |
63 | | ) |
64 | 0 | { |
65 | 0 | psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); |
66 | 0 | psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); |
67 | 0 | psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); |
68 | 0 | psDec->sPLC.subfr_length = 20; |
69 | 0 | psDec->sPLC.nb_subfr = 2; |
70 | 0 | } |
71 | | |
72 | | void silk_PLC( |
73 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
74 | | silk_decoder_control *psDecCtrl, /* I/O Decoder control */ |
75 | | opus_int16 frame[], /* I/O signal */ |
76 | | opus_int lost, /* I Loss flag */ |
77 | | #ifdef ENABLE_DEEP_PLC |
78 | | LPCNetPLCState *lpcnet, |
79 | | #endif |
80 | | int arch /* I Run-time architecture */ |
81 | | ) |
82 | 0 | { |
83 | | /* PLC control function */ |
84 | 0 | if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { |
85 | 0 | silk_PLC_Reset( psDec ); |
86 | 0 | psDec->sPLC.fs_kHz = psDec->fs_kHz; |
87 | 0 | } |
88 | |
|
89 | 0 | if( lost ) { |
90 | | /****************************/ |
91 | | /* Generate Signal */ |
92 | | /****************************/ |
93 | 0 | silk_PLC_conceal( psDec, psDecCtrl, frame, |
94 | | #ifdef ENABLE_DEEP_PLC |
95 | | lpcnet, |
96 | | #endif |
97 | 0 | arch ); |
98 | |
|
99 | 0 | psDec->lossCnt++; |
100 | 0 | } else { |
101 | | /****************************/ |
102 | | /* Update state */ |
103 | | /****************************/ |
104 | 0 | silk_PLC_update( psDec, psDecCtrl ); |
105 | | #ifdef ENABLE_DEEP_PLC |
106 | | if ( lpcnet != NULL && psDec->sPLC.fs_kHz == 16 ) { |
107 | | int k; |
108 | | for( k = 0; k < psDec->nb_subfr; k += 2 ) { |
109 | | lpcnet_plc_update( lpcnet, frame + k * psDec->subfr_length ); |
110 | | } |
111 | | } |
112 | | #endif |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | | /**************************************************/ |
117 | | /* Update state of PLC */ |
118 | | /**************************************************/ |
119 | | static OPUS_INLINE void silk_PLC_update( |
120 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
121 | | silk_decoder_control *psDecCtrl /* I/O Decoder control */ |
122 | | ) |
123 | 0 | { |
124 | 0 | opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; |
125 | 0 | opus_int i, j; |
126 | 0 | silk_PLC_struct *psPLC; |
127 | |
|
128 | 0 | psPLC = &psDec->sPLC; |
129 | | |
130 | | /* Update parameters used in case of packet loss */ |
131 | 0 | psDec->prevSignalType = psDec->indices.signalType; |
132 | 0 | LTP_Gain_Q14 = 0; |
133 | 0 | if( psDec->indices.signalType == TYPE_VOICED ) { |
134 | | /* Find the parameters for the last subframe which contains a pitch pulse */ |
135 | 0 | for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { |
136 | 0 | if( j == psDec->nb_subfr ) { |
137 | 0 | break; |
138 | 0 | } |
139 | 0 | temp_LTP_Gain_Q14 = 0; |
140 | 0 | for( i = 0; i < LTP_ORDER; i++ ) { |
141 | 0 | temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; |
142 | 0 | } |
143 | 0 | if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { |
144 | 0 | LTP_Gain_Q14 = temp_LTP_Gain_Q14; |
145 | 0 | silk_memcpy( psPLC->LTPCoef_Q14, |
146 | 0 | &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], |
147 | 0 | LTP_ORDER * sizeof( opus_int16 ) ); |
148 | |
|
149 | 0 | psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); |
150 | 0 | } |
151 | 0 | } |
152 | |
|
153 | 0 | silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); |
154 | 0 | psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; |
155 | | |
156 | | /* Limit LT coefs */ |
157 | 0 | if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { |
158 | 0 | opus_int scale_Q10; |
159 | 0 | opus_int32 tmp; |
160 | |
|
161 | 0 | tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); |
162 | 0 | scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); |
163 | 0 | for( i = 0; i < LTP_ORDER; i++ ) { |
164 | 0 | psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); |
165 | 0 | } |
166 | 0 | } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { |
167 | 0 | opus_int scale_Q14; |
168 | 0 | opus_int32 tmp; |
169 | |
|
170 | 0 | tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); |
171 | 0 | scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); |
172 | 0 | for( i = 0; i < LTP_ORDER; i++ ) { |
173 | 0 | psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); |
174 | 0 | } |
175 | 0 | } |
176 | 0 | } else { |
177 | 0 | psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); |
178 | 0 | silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); |
179 | 0 | } |
180 | | |
181 | | /* Save LPC coeficients */ |
182 | 0 | silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); |
183 | 0 | psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; |
184 | | |
185 | | /* Save last two gains */ |
186 | 0 | silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); |
187 | |
|
188 | 0 | psPLC->subfr_length = psDec->subfr_length; |
189 | 0 | psPLC->nb_subfr = psDec->nb_subfr; |
190 | 0 | } |
191 | | |
192 | | static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2, |
193 | | const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr) |
194 | 0 | { |
195 | 0 | int i, k; |
196 | 0 | VARDECL( opus_int16, exc_buf ); |
197 | 0 | opus_int16 *exc_buf_ptr; |
198 | 0 | SAVE_STACK; |
199 | 0 | ALLOC( exc_buf, 2*subfr_length, opus_int16 ); |
200 | | /* Find random noise component */ |
201 | | /* Scale previous excitation signal */ |
202 | 0 | exc_buf_ptr = exc_buf; |
203 | 0 | for( k = 0; k < 2; k++ ) { |
204 | 0 | for( i = 0; i < subfr_length; i++ ) { |
205 | 0 | exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( |
206 | 0 | silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) ); |
207 | 0 | } |
208 | 0 | exc_buf_ptr += subfr_length; |
209 | 0 | } |
210 | | /* Find the subframe with lowest energy of the last two and use that as random noise generator */ |
211 | 0 | silk_sum_sqr_shift( energy1, shift1, exc_buf, subfr_length ); |
212 | 0 | silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length ); |
213 | 0 | RESTORE_STACK; |
214 | 0 | } |
215 | | |
216 | | static OPUS_INLINE void silk_PLC_conceal( |
217 | | silk_decoder_state *psDec, /* I/O Decoder state */ |
218 | | silk_decoder_control *psDecCtrl, /* I/O Decoder control */ |
219 | | opus_int16 frame[], /* O LPC residual signal */ |
220 | | #ifdef ENABLE_DEEP_PLC |
221 | | LPCNetPLCState *lpcnet, |
222 | | #endif |
223 | | int arch /* I Run-time architecture */ |
224 | | ) |
225 | 0 | { |
226 | 0 | opus_int i, j, k; |
227 | 0 | opus_int lag, idx, sLTP_buf_idx, shift1, shift2; |
228 | 0 | opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; |
229 | 0 | opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; |
230 | 0 | opus_int32 LPC_pred_Q10, LTP_pred_Q12; |
231 | 0 | opus_int16 rand_scale_Q14; |
232 | 0 | opus_int16 *B_Q14; |
233 | 0 | opus_int32 *sLPC_Q14_ptr; |
234 | 0 | opus_int16 A_Q12[ MAX_LPC_ORDER ]; |
235 | | #ifdef SMALL_FOOTPRINT |
236 | | opus_int16 *sLTP; |
237 | | #else |
238 | 0 | VARDECL( opus_int16, sLTP ); |
239 | 0 | #endif |
240 | 0 | VARDECL( opus_int32, sLTP_Q14 ); |
241 | 0 | silk_PLC_struct *psPLC = &psDec->sPLC; |
242 | 0 | opus_int32 prevGain_Q10[2]; |
243 | 0 | SAVE_STACK; |
244 | |
|
245 | 0 | ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); |
246 | | #ifdef SMALL_FOOTPRINT |
247 | | /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */ |
248 | | sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length; |
249 | | #else |
250 | 0 | ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); |
251 | 0 | #endif |
252 | |
|
253 | 0 | prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); |
254 | 0 | prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); |
255 | |
|
256 | 0 | if( psDec->first_frame_after_reset ) { |
257 | 0 | silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); |
258 | 0 | } |
259 | |
|
260 | 0 | silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr); |
261 | |
|
262 | 0 | if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { |
263 | | /* First sub-frame has lowest energy */ |
264 | 0 | rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; |
265 | 0 | } else { |
266 | | /* Second sub-frame has lowest energy */ |
267 | 0 | rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; |
268 | 0 | } |
269 | | |
270 | | /* Set up Gain to random noise component */ |
271 | 0 | B_Q14 = psPLC->LTPCoef_Q14; |
272 | 0 | rand_scale_Q14 = psPLC->randScale_Q14; |
273 | | |
274 | | /* Set up attenuation gains */ |
275 | 0 | harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; |
276 | 0 | if( psDec->prevSignalType == TYPE_VOICED ) { |
277 | 0 | rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; |
278 | 0 | } else { |
279 | 0 | rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; |
280 | 0 | } |
281 | | |
282 | | /* LPC concealment. Apply BWE to previous LPC */ |
283 | 0 | silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); |
284 | | |
285 | | /* Preload LPC coeficients to array on stack. Gives small performance gain */ |
286 | 0 | silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); |
287 | | |
288 | | /* First Lost frame */ |
289 | 0 | if( psDec->lossCnt == 0 ) { |
290 | 0 | rand_scale_Q14 = 1 << 14; |
291 | | |
292 | | /* Reduce random noise Gain for voiced frames */ |
293 | 0 | if( psDec->prevSignalType == TYPE_VOICED ) { |
294 | 0 | for( i = 0; i < LTP_ORDER; i++ ) { |
295 | 0 | rand_scale_Q14 -= B_Q14[ i ]; |
296 | 0 | } |
297 | 0 | rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ |
298 | 0 | rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); |
299 | 0 | } else { |
300 | | /* Reduce random noise for unvoiced frames with high LPC gain */ |
301 | 0 | opus_int32 invGain_Q30, down_scale_Q30; |
302 | |
|
303 | 0 | invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch ); |
304 | |
|
305 | 0 | down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); |
306 | 0 | down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); |
307 | 0 | down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); |
308 | |
|
309 | 0 | rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); |
310 | 0 | } |
311 | 0 | } |
312 | |
|
313 | 0 | rand_seed = psPLC->rand_seed; |
314 | 0 | lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); |
315 | 0 | sLTP_buf_idx = psDec->ltp_mem_length; |
316 | | |
317 | | /* Rewhiten LTP state */ |
318 | 0 | idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; |
319 | 0 | celt_assert( idx > 0 ); |
320 | 0 | silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch ); |
321 | | /* Scale LTP state */ |
322 | 0 | inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); |
323 | 0 | inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); |
324 | 0 | for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { |
325 | 0 | sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); |
326 | 0 | } |
327 | | |
328 | | /***************************/ |
329 | | /* LTP synthesis filtering */ |
330 | | /***************************/ |
331 | 0 | for( k = 0; k < psDec->nb_subfr; k++ ) { |
332 | | /* Set up pointer */ |
333 | 0 | pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; |
334 | 0 | for( i = 0; i < psDec->subfr_length; i++ ) { |
335 | | /* Unrolled loop */ |
336 | | /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ |
337 | 0 | LTP_pred_Q12 = 2; |
338 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); |
339 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); |
340 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); |
341 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); |
342 | 0 | LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); |
343 | 0 | pred_lag_ptr++; |
344 | | |
345 | | /* Generate LPC excitation */ |
346 | 0 | rand_seed = silk_RAND( rand_seed ); |
347 | 0 | idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; |
348 | 0 | sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); |
349 | 0 | sLTP_buf_idx++; |
350 | 0 | } |
351 | | |
352 | | /* Gradually reduce LTP gain */ |
353 | 0 | for( j = 0; j < LTP_ORDER; j++ ) { |
354 | 0 | B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); |
355 | 0 | } |
356 | | /* Gradually reduce excitation gain */ |
357 | 0 | rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); |
358 | | |
359 | | /* Slowly increase pitch lag */ |
360 | 0 | psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); |
361 | 0 | psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); |
362 | 0 | lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); |
363 | 0 | } |
364 | | |
365 | | /***************************/ |
366 | | /* LPC synthesis filtering */ |
367 | | /***************************/ |
368 | 0 | sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; |
369 | | |
370 | | /* Copy LPC state */ |
371 | 0 | silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); |
372 | |
|
373 | 0 | celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ |
374 | 0 | for( i = 0; i < psDec->frame_length; i++ ) { |
375 | | /* partly unrolled */ |
376 | | /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ |
377 | 0 | LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); |
378 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); |
379 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); |
380 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); |
381 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); |
382 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); |
383 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); |
384 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); |
385 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); |
386 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); |
387 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); |
388 | 0 | for( j = 10; j < psDec->LPC_order; j++ ) { |
389 | 0 | LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); |
390 | 0 | } |
391 | | |
392 | | /* Add prediction to LPC excitation */ |
393 | 0 | sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], |
394 | 0 | silk_LSHIFT_SAT32( LPC_pred_Q10, 4 )); |
395 | | |
396 | | /* Scale with Gain */ |
397 | 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 ) ) ); |
398 | 0 | } |
399 | | #ifdef ENABLE_DEEP_PLC |
400 | | if ( lpcnet != NULL && lpcnet->loaded && psDec->sPLC.fs_kHz == 16 ) { |
401 | | int run_deep_plc = psDec->sPLC.enable_deep_plc || lpcnet->fec_fill_pos != 0; |
402 | | if( run_deep_plc ) { |
403 | | for( k = 0; k < psDec->nb_subfr; k += 2 ) { |
404 | | lpcnet_plc_conceal( lpcnet, frame + k * psDec->subfr_length ); |
405 | | } |
406 | | /* We *should* be able to copy only from psDec->frame_length-MAX_LPC_ORDER, i.e. the last MAX_LPC_ORDER samples. */ |
407 | | for( i = 0; i < psDec->frame_length; i++ ) { |
408 | | sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = (int)floor(.5 + frame[ i ] * (float)(1 << 24) / prevGain_Q10[ 1 ] ); |
409 | | } |
410 | | } else { |
411 | | for( k = 0; k < psDec->nb_subfr; k += 2 ) { |
412 | | lpcnet_plc_update( lpcnet, frame + k * psDec->subfr_length ); |
413 | | } |
414 | | } |
415 | | } |
416 | | #endif |
417 | | |
418 | | /* Save LPC state */ |
419 | 0 | silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); |
420 | | |
421 | | /**************************************/ |
422 | | /* Update states */ |
423 | | /**************************************/ |
424 | 0 | psPLC->rand_seed = rand_seed; |
425 | 0 | psPLC->randScale_Q14 = rand_scale_Q14; |
426 | 0 | for( i = 0; i < MAX_NB_SUBFR; i++ ) { |
427 | 0 | psDecCtrl->pitchL[ i ] = lag; |
428 | 0 | } |
429 | 0 | RESTORE_STACK; |
430 | 0 | } |
431 | | |
432 | | /* Glues concealed frames with new good received frames */ |
433 | | void silk_PLC_glue_frames( |
434 | | silk_decoder_state *psDec, /* I/O decoder state */ |
435 | | opus_int16 frame[], /* I/O signal */ |
436 | | opus_int length /* I length of signal */ |
437 | | ) |
438 | 0 | { |
439 | 0 | opus_int i, energy_shift; |
440 | 0 | opus_int32 energy; |
441 | 0 | silk_PLC_struct *psPLC; |
442 | 0 | psPLC = &psDec->sPLC; |
443 | |
|
444 | 0 | if( psDec->lossCnt ) { |
445 | | /* Calculate energy in concealed residual */ |
446 | 0 | silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); |
447 | |
|
448 | 0 | psPLC->last_frame_lost = 1; |
449 | 0 | } else { |
450 | 0 | if( psDec->sPLC.last_frame_lost ) { |
451 | | /* Calculate residual in decoded signal if last frame was lost */ |
452 | 0 | silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); |
453 | | |
454 | | /* Normalize energies */ |
455 | 0 | if( energy_shift > psPLC->conc_energy_shift ) { |
456 | 0 | psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); |
457 | 0 | } else if( energy_shift < psPLC->conc_energy_shift ) { |
458 | 0 | energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); |
459 | 0 | } |
460 | | |
461 | | /* Fade in the energy difference */ |
462 | 0 | if( energy > psPLC->conc_energy ) { |
463 | 0 | opus_int32 frac_Q24, LZ; |
464 | 0 | opus_int32 gain_Q16, slope_Q16; |
465 | |
|
466 | 0 | LZ = silk_CLZ32( psPLC->conc_energy ); |
467 | 0 | LZ = LZ - 1; |
468 | 0 | psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); |
469 | 0 | energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); |
470 | |
|
471 | 0 | frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); |
472 | |
|
473 | 0 | gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); |
474 | 0 | slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); |
475 | | /* Make slope 4x steeper to avoid missing onsets after DTX */ |
476 | 0 | slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); |
477 | | #ifdef ENABLE_DEEP_PLC |
478 | | if ( psDec->sPLC.fs_kHz != 16 ) |
479 | | #endif |
480 | 0 | { |
481 | 0 | for( i = 0; i < length; i++ ) { |
482 | 0 | frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); |
483 | 0 | gain_Q16 += slope_Q16; |
484 | 0 | if( gain_Q16 > (opus_int32)1 << 16 ) { |
485 | 0 | break; |
486 | 0 | } |
487 | 0 | } |
488 | 0 | } |
489 | 0 | } |
490 | 0 | } |
491 | 0 | psPLC->last_frame_lost = 0; |
492 | 0 | } |
493 | 0 | } |