Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : /*====================================================================================
34 : EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
35 : ====================================================================================*/
36 : #include <stdint.h>
37 : #include "options.h" /* Compilation switches */
38 : #include "cnst.h" /* Common constants */
39 : #include "rom_com.h" /* Static table prototypes */
40 : #include "prot_fx.h" /* Function prototypes */
41 : #include "prot_fx_enc.h" /* Function prototypes */
42 :
43 : /*--------------------------------------------------------------------------*/
44 : /* Function hp_filter */
45 : /* ~~~~~~~~~~~~~~~~~~~~ */
46 : /* */
47 : /* High pass filter */
48 : /*--------------------------------------------------------------------------*/
49 : /* float x (i) in Q_new input to filter */
50 : /* float y (o) in Q_new +2 output of filter */
51 : /* float *oldy (i/o) previous output of filter */
52 : /* float *oldx (i/o) in Q_memx previous input of filter */
53 : /* short L (i) in Q_memx +2 length (32 or 48 kHz) */
54 : /*--------------------------------------------------------------------------*/
55 :
56 20607 : static void hp_filter_fx(
57 : const Word16 *x, /*Q_new */
58 : Word16 *y, /*Q_new */
59 : Word16 *oldy, /*Q_new */
60 : Word16 *oldx, /*Q_new */
61 : const Word16 L /*Q0*/ )
62 : {
63 : Word16 i;
64 : Word32 L_tmp;
65 : #ifndef ISSUE_1867_replace_overflow_libenc
66 : #ifdef BASOP_NOGLOB_DECLARE_LOCAL
67 : Flag Overflow = 0;
68 : move32();
69 : #endif
70 : #endif
71 :
72 :
73 : /*y[0] = 0.4931f * *oldy + 0.7466f*(x[0] - *oldx); */
74 : #ifdef ISSUE_1867_replace_overflow_libenc
75 20607 : L_tmp = L_mult( sub_sat( x[0], *oldx ), 24465 /*0.7466f in Q15*/ ); /*Q_new+16 */
76 : #else
77 : L_tmp = L_mult( sub_o( x[0], *oldx, &Overflow ), 24465 /*0.7466f in Q15*/ ); /*Q_new+16 */
78 : #endif
79 20607 : L_tmp = L_mac_sat( L_tmp, *oldy, 16158 /*0.4931f in Q15*/ ); /*Q_new+16 */
80 20607 : y[0] = round_fx_sat( L_tmp ); /*Q_new */
81 11920320 : FOR( i = 1; i < L; i++ )
82 : {
83 : /*y[i] = 0.4931f*y[i-1] + 0.7466f*(x[i] - x[i-1]); */
84 : #ifdef ISSUE_1867_replace_overflow_libenc
85 11899713 : L_tmp = L_mult( sub_sat( x[i], x[i - 1] ), 24465 /*0.7466f in Q15*/ ); /*Q_new+16 */
86 11899713 : L_tmp = L_mac_sat( L_tmp, y[i - 1], 16158 /*0.4931f in Q15*/ ); /*Q_new+16 */
87 11899713 : y[i] = round_fx_sat( L_tmp ); /*Q_new */
88 : #else
89 : L_tmp = L_mult( sub_o( x[i], x[i - 1], &Overflow ), 24465 /*0.7466f in Q15*/ ); /*Q_new+16 */
90 : L_tmp = L_mac_o( L_tmp, y[i - 1], 16158 /*0.4931f in Q15*/, &Overflow ); /*Q_new+16 */
91 : y[i] = round_fx_o( L_tmp, &Overflow ); /*Q_new */
92 : #endif
93 : }
94 :
95 20607 : *oldx = x[L - 1];
96 20607 : move16(); /*Q_new */
97 20607 : *oldy = y[L - 1];
98 20607 : move16(); /*Q_new */
99 20607 : }
100 : /*--------------------------------------------------------------------------*/
101 : /* Function detect_transient */
102 : /* ~~~~~~~~~~~~~~~~~~~~~~~~~~ */
103 : /* */
104 : /* Detect if the signal is a transient */
105 : /*--------------------------------------------------------------------------*/
106 : /* float in[] (i) input signal Q_new */
107 : /* Encoder_State *st (i/o) state of coder */
108 : /* short L (i) length (32 or 48 kHz) */
109 : /*--------------------------------------------------------------------------*/
110 : /* short return (o) result of transient check */
111 : /*--------------------------------------------------------------------------*/
112 :
113 20607 : Word16 detect_transient_fx(
114 : const Word16 *in_fx, /*Q_new */
115 : const Word16 L, /*Q0*/
116 : Word16 Q_new,
117 : Encoder_State *st_fx )
118 : {
119 : Word32 Energy, L_tmp;
120 : Word32 EnergyLT;
121 : Word16 i, blk;
122 : Word16 IsTransient;
123 : Word16 out_filt_fx[L_FRAME48k];
124 20607 : Word16 position = 0;
125 : Word16 thr;
126 : Word32 L_tmp2;
127 : Word16 shift;
128 20607 : Word32 Energy_fx, E_in_fx = 0, E_out_fx = 0, Energy_in_fx[5] = { 0, 0, 0, 0, 0 }; /* Energy_fx can be replaced by Energy */
129 : Word32 E_low_fx, E_high_fx;
130 20607 : Word16 temp16, Thres_fx = 0;
131 : Word16 exp;
132 : #ifdef ISSUE_1867_replace_overflow_libenc
133 : #ifdef BASOP_NOGLOB_DECLARE_LOCAL
134 20607 : Flag Overflow = 0;
135 20607 : move32();
136 : #endif
137 : #endif
138 :
139 20607 : shift = 0;
140 20607 : move16();
141 :
142 20607 : IsTransient = 0;
143 20607 : move16();
144 20607 : IF( NE_16( st_fx->last_extl, st_fx->extl ) )
145 : {
146 2291 : st_fx->TransientHangOver = 0;
147 2291 : move16();
148 2291 : st_fx->old_hpfilt_in_fx = 0;
149 2291 : move16();
150 2291 : st_fx->old_hpfilt_out_fx = 0;
151 2291 : move16();
152 : }
153 :
154 : /* High pass filter */
155 20607 : hp_filter_fx( in_fx, out_filt_fx, &( st_fx->old_hpfilt_in_fx ), &( st_fx->old_hpfilt_out_fx ), L );
156 :
157 : /* Long term energy */
158 20607 : test();
159 20607 : test();
160 20607 : test();
161 20607 : IF( NE_16( st_fx->last_extl, st_fx->extl ) || ( EQ_16( st_fx->last_extl, st_fx->extl ) && NE_16( st_fx->last_core, st_fx->core ) ) || EQ_16( st_fx->last_codec_mode, MODE2 ) )
162 : {
163 : /*EnergyLT = EPSILON_FX; */
164 9967 : EnergyLT = L_deposit_l( 0 );
165 1981167 : FOR( i = 0; i < L / 4; i++ )
166 : {
167 : /*EnergyLT += out_filt[i] * out_filt[i]; */
168 : #ifdef ISSUE_1867_replace_overflow_libenc
169 1971200 : EnergyLT = L_mac0_sat( EnergyLT, out_filt_fx[i], out_filt_fx[i] ); /*2Q_new */
170 : #else
171 : EnergyLT = L_mac0_o( EnergyLT, out_filt_fx[i], out_filt_fx[i], &Overflow ); /*2Q_new */
172 : #endif
173 : }
174 : }
175 : ELSE
176 : {
177 10640 : EnergyLT = L_add( st_fx->EnergyLT_fx, 0 ); /*2Q_new */
178 : }
179 20607 : IF( EQ_16( L, L_FRAME8k ) )
180 : {
181 0 : Energy_in_fx[0] = st_fx->Energy_Old_fx; /*Q0*/
182 0 : move32();
183 : /* Compute block energy */
184 0 : FOR( blk = 0; blk < 4; blk++ )
185 : {
186 0 : Energy_fx = L_deposit_l( 0 );
187 0 : Energy_in_fx[blk + 1] = L_deposit_l( 0 );
188 0 : FOR( i = 0; i < L / 4; i++ )
189 : {
190 0 : temp16 = extract_l( L_shr( out_filt_fx[i + blk * ( L / 4 )], 12 ) );
191 : #ifdef ISSUE_1867_replace_overflow_libenc
192 0 : Energy_fx = L_add_sat( Energy_fx, L_mult0( temp16, temp16 ) );
193 : #else
194 : Energy_fx = L_add_o( Energy_fx, L_mult0( temp16, temp16 ), &Overflow );
195 : #endif
196 0 : temp16 = shr( in_fx[i + blk * ( L / 4 )], Q_new ); /*Q0*/
197 : #ifdef ISSUE_1867_replace_overflow_libenc
198 0 : Energy_in_fx[blk + 1] = L_add_sat( Energy_in_fx[blk + 1], L_mult0( temp16, temp16 ) ); /*Q0*/
199 : #else
200 : Energy_in_fx[blk + 1] = L_add_o( Energy_in_fx[blk + 1], L_mult0( temp16, temp16 ), &Overflow ); /*Q0*/
201 : #endif
202 0 : move32();
203 : }
204 :
205 : #ifdef ISSUE_1867_replace_overflow_libenc
206 0 : E_in_fx = L_add_sat( E_in_fx, Energy_in_fx[blk + 1] ); /*Q0*/
207 0 : E_out_fx = L_add_sat( E_out_fx, Energy_fx ); /*Q0*/
208 : #else
209 : E_in_fx = L_add_o( E_in_fx, Energy_in_fx[blk + 1], &Overflow ); /*Q0*/
210 : E_out_fx = L_add_o( E_out_fx, Energy_fx, &Overflow ); /*Q0*/
211 : #endif
212 :
213 0 : Thres_fx = 2185; /*1 /15 Q15*/
214 0 : move16();
215 0 : IF( GT_32( Mult_32_16( Energy_fx, 5461 ), EnergyLT ) )
216 : {
217 0 : IsTransient = 1;
218 0 : move16();
219 0 : position = blk;
220 0 : move16();
221 : }
222 :
223 0 : EnergyLT = L_add( Mult_32_16( EnergyLT, 24576 /*Q15*/ ), Mult_32_16( Energy_fx, 8192 /*Q15*/ ) ); /*2Q_new*/
224 : }
225 : }
226 : ELSE
227 : {
228 : /* Compute block energy */
229 103035 : FOR( blk = 0; blk < 4; blk++ )
230 : {
231 82428 : L_tmp = L_deposit_l( 0 );
232 6042588 : FOR( i = 0; i < L / 8; i++ )
233 : {
234 : /*Energy += out_filt_fx[i + blk*(L/4)] * out_filt_fx[i + blk*(L/4)]; */
235 : #ifdef ISSUE_1867_replace_overflow_libenc
236 5960160 : L_tmp = L_mac0_sat( L_tmp, out_filt_fx[i + blk * ( L / 4 )], out_filt_fx[i + blk * ( L / 4 )] ); /*2Q_new */
237 : #else
238 : L_tmp = L_mac0_o( L_tmp, out_filt_fx[i + blk * ( L / 4 )], out_filt_fx[i + blk * ( L / 4 )], &Overflow ); /*2Q_new */
239 : #endif
240 : }
241 82428 : L_tmp2 = L_deposit_l( 0 );
242 6042588 : FOR( ; i < L / 4; i++ )
243 : {
244 : /*Energy += out_filt_fx[i + blk*(L/4)] * out_filt_fx[i + blk*(L/4)]; */
245 : #ifdef ISSUE_1867_replace_overflow_libenc
246 5960160 : L_tmp2 = L_mac0_sat( L_tmp2, out_filt_fx[i + blk * ( L / 4 )], out_filt_fx[i + blk * ( L / 4 )] ); /*2Q_new */
247 : #else
248 : L_tmp2 = L_mac0_o( L_tmp2, out_filt_fx[i + blk * ( L / 4 )], out_filt_fx[i + blk * ( L / 4 )], &Overflow ); /*2Q_new */
249 : #endif
250 : }
251 82428 : Overflow = 0;
252 82428 : move16();
253 82428 : Energy = L_add_o( L_tmp, L_tmp2, &Overflow ); /*2Q_new */
254 82428 : shift = 0;
255 82428 : if ( Overflow != 0 )
256 : {
257 757 : shift = 1;
258 757 : move16();
259 : }
260 : #ifndef ISSUE_1867_replace_overflow_libenc
261 : Overflow = 0;
262 : move16();
263 :
264 : Energy = L_add_o( L_shr( L_tmp, shift ), L_shr( L_tmp2, shift ), &Overflow ); /*2Q_new - shift*/
265 : #else
266 82428 : Energy = L_add_sat( L_shr( L_tmp, shift ), L_shr( L_tmp2, shift ) ); /*2Q_new - shift*/
267 : #endif
268 82428 : test();
269 82428 : IF( EQ_16( st_fx->extl, SWB_BWE ) || EQ_16( st_fx->extl, FB_BWE ) )
270 : {
271 : /*Calculate shift to get to Q0*/
272 46804 : test();
273 46804 : test();
274 46804 : IF( ( GT_32( Mult_32_16( Energy, shl( 2427, shift ) ), EnergyLT ) ) || ( GT_32( Mult_32_16( Energy, shl( 3277, shift ) ), EnergyLT ) && EQ_16( st_fx->core, ACELP_CORE ) && EQ_16( st_fx->coder_type, INACTIVE ) ) )
275 : {
276 432 : IsTransient = 1;
277 432 : move16();
278 432 : position = blk;
279 432 : move16();
280 : }
281 : }
282 : ELSE
283 : {
284 35624 : test();
285 35624 : IF( LE_32( st_fx->total_brate, HQ_16k40 ) && EQ_16( st_fx->bwidth, SWB ) )
286 : {
287 156 : thr = 2427;
288 156 : move16();
289 : }
290 : ELSE
291 : {
292 35468 : thr = 5461;
293 35468 : move16();
294 : }
295 35624 : thr = shl( thr, shift );
296 : /*if(Energy > L_shr(Mult_32_16(EnergyLT,22624),shift_cnt)) //getting in Q0 32*16 = Q_inp1+Q_inp2+1-16 */
297 35624 : IF( GT_32( Mult_32_16( Energy, thr ), EnergyLT ) )
298 : /*if(Energy > 6.0f * EnergyLT) */
299 : {
300 342 : IsTransient = 1;
301 342 : move16();
302 342 : position = blk;
303 342 : move16();
304 : }
305 : }
306 : /*EnergyLT = 0.75f*EnergyLT + 0.25f*Energy; */
307 : /*0.75f*EnergyLT in Q0 //0.25f*Energy in Q0 */
308 : #ifdef ISSUE_1867_replace_overflow_libenc
309 82428 : EnergyLT = L_add_sat( Mult_32_16( EnergyLT, 24576 /*0.75f in Q15*/ ), Mult_32_16( Energy, shl( 8192 /*0.25 in Q15*/, shift ) ) ); /*2Q_new */
310 : #else
311 : EnergyLT = L_add_o( Mult_32_16( EnergyLT, 24576 /*0.75f in Q15*/ ), Mult_32_16( Energy, shl( 8192 /*0.25 in Q15*/, shift ) ), &Overflow ); /*2Q_new */
312 : #endif
313 : }
314 : }
315 20607 : st_fx->EnergyLT_fx = EnergyLT;
316 20607 : move32();
317 :
318 20607 : test();
319 20607 : test();
320 20607 : test();
321 20607 : test();
322 20607 : test();
323 40118 : if ( ( NE_16( st_fx->last_extl, SWB_BWE ) && NE_16( st_fx->last_extl, SWB_TBE ) && EQ_16( st_fx->extl, SWB_BWE ) ) ||
324 34493 : ( NE_16( st_fx->last_extl, FB_BWE ) && NE_16( st_fx->last_extl, FB_TBE ) && EQ_16( st_fx->extl, FB_BWE ) ) )
325 : {
326 1173 : IsTransient = 0;
327 1173 : move16();
328 : }
329 :
330 20607 : test();
331 20607 : IF( IsTransient && L == L_FRAME8k )
332 : {
333 0 : blk = 0;
334 0 : move16();
335 0 : E_low_fx = L_deposit_l( 0 );
336 0 : FOR( i = 0; i < position + 1; i++ )
337 : {
338 : /*blk++; */
339 0 : blk = add( blk, 1 );
340 0 : E_low_fx = L_add_sat( E_low_fx, Energy_in_fx[i] ); /*Q0*/
341 : }
342 :
343 0 : exp = norm_s( blk );
344 0 : temp16 = div_s( 16384, shl( blk, exp ) ); /* 15 + 14 - exp; */
345 0 : exp = 15 + 14 - exp;
346 0 : temp16 = shl( temp16, sub( 15, exp ) );
347 0 : E_low_fx = Mult_32_16( E_low_fx, temp16 );
348 :
349 0 : blk = 0;
350 0 : move16();
351 0 : E_high_fx = L_deposit_l( 0 );
352 0 : FOR( i = position + 1; i < 5; i++ )
353 : {
354 : /*blk++; */
355 0 : blk = add( blk, 1 );
356 0 : E_high_fx = L_add_sat( E_high_fx, Energy_in_fx[i] ); /*Q0*/
357 : }
358 :
359 0 : exp = norm_s( blk );
360 0 : temp16 = div_s( 16384, shl( blk, exp ) ); /* 15 + 14 - exp; */
361 0 : exp = 15 + 14 - exp;
362 0 : temp16 = shl( temp16, 15 - exp );
363 0 : E_high_fx = Mult_32_16( E_high_fx, temp16 );
364 :
365 0 : test();
366 0 : test();
367 0 : IF( LT_32( L_shr( E_high_fx, 1 ), E_low_fx ) && GT_32( E_high_fx, Mult_32_16( E_low_fx, 22938 /*0.7 in Q15*/ ) ) && GT_32( Mult_32_16( E_in_fx, Thres_fx ), E_out_fx ) )
368 : {
369 0 : IsTransient = 0;
370 0 : move16();
371 : }
372 : }
373 20607 : IF( EQ_32( st_fx->core_brate, ACELP_24k40 ) )
374 : {
375 78 : test();
376 78 : IF( NE_16( st_fx->last_core, HQ_CORE ) || NE_32( st_fx->last_core_brate, ACELP_24k40 ) )
377 : {
378 78 : st_fx->TransientHangOver = 0;
379 78 : move16();
380 78 : IsTransient = 0;
381 78 : move16();
382 : }
383 : ELSE
384 : {
385 0 : IF( IsTransient )
386 : {
387 0 : if ( EQ_16( position, 3 ) )
388 : {
389 : /* Set Hangover */
390 0 : st_fx->TransientHangOver = 1;
391 0 : move16();
392 : }
393 : }
394 : ELSE
395 : {
396 0 : IF( st_fx->TransientHangOver )
397 : {
398 0 : st_fx->TransientHangOver = 0;
399 0 : move16();
400 0 : IsTransient = 1;
401 0 : move16();
402 : }
403 : }
404 : }
405 : }
406 : ELSE
407 : {
408 20529 : IF( IsTransient )
409 : {
410 424 : st_fx->TransientHangOver = 1;
411 424 : move16();
412 : }
413 : ELSE
414 : {
415 20105 : IF( st_fx->TransientHangOver )
416 : {
417 304 : st_fx->TransientHangOver = 0;
418 304 : move16();
419 304 : IsTransient = 1;
420 304 : move16();
421 : }
422 : }
423 : }
424 :
425 20607 : if ( EQ_16( L, L_FRAME8k ) )
426 : {
427 0 : st_fx->Energy_Old_fx = Energy_in_fx[4]; /*Q0*/
428 0 : move32();
429 : }
430 :
431 20607 : return IsTransient;
432 : }
|