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 20639 : 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 : #ifdef BASOP_NOGLOB_DECLARE_LOCAL
66 20639 : Flag Overflow = 0;
67 20639 : move32();
68 : #endif
69 :
70 :
71 : /*y[0] = 0.4931f * *oldy + 0.7466f*(x[0] - *oldx); */
72 20639 : L_tmp = L_mult( sub_o( x[0], *oldx, &Overflow ), 24465 /*0.7466f in Q15*/ ); /*Q_new+16 */
73 20639 : L_tmp = L_mac_sat( L_tmp, *oldy, 16158 /*0.4931f in Q15*/ ); /*Q_new+16 */
74 20639 : y[0] = round_fx_sat( L_tmp ); /*Q_new */
75 11915840 : FOR( i = 1; i < L; i++ )
76 : {
77 : /*y[i] = 0.4931f*y[i-1] + 0.7466f*(x[i] - x[i-1]); */
78 11895201 : L_tmp = L_mult( sub_o( x[i], x[i - 1], &Overflow ), 24465 /*0.7466f in Q15*/ ); /*Q_new+16 */
79 11895201 : L_tmp = L_mac_o( L_tmp, y[i - 1], 16158 /*0.4931f in Q15*/, &Overflow ); /*Q_new+16 */
80 11895201 : y[i] = round_fx_o( L_tmp, &Overflow ); /*Q_new */
81 : }
82 :
83 20639 : *oldx = x[L - 1];
84 20639 : move16(); /*Q_new */
85 20639 : *oldy = y[L - 1];
86 20639 : move16(); /*Q_new */
87 20639 : }
88 : /*--------------------------------------------------------------------------*/
89 : /* Function detect_transient */
90 : /* ~~~~~~~~~~~~~~~~~~~~~~~~~~ */
91 : /* */
92 : /* Detect if the signal is a transient */
93 : /*--------------------------------------------------------------------------*/
94 : /* float in[] (i) input signal Q_new */
95 : /* Encoder_State *st (i/o) state of coder */
96 : /* short L (i) length (32 or 48 kHz) */
97 : /*--------------------------------------------------------------------------*/
98 : /* short return (o) result of transient check */
99 : /*--------------------------------------------------------------------------*/
100 :
101 20639 : Word16 detect_transient_fx(
102 : const Word16 *in_fx, /*Q_new */
103 : const Word16 L, /*Q0*/
104 : Word16 Q_new,
105 : Encoder_State *st_fx )
106 : {
107 : Word32 Energy, L_tmp;
108 : Word32 EnergyLT;
109 : Word16 i, blk;
110 : Word16 IsTransient;
111 : Word16 out_filt_fx[L_FRAME48k];
112 20639 : Word16 position = 0;
113 : Word16 thr;
114 : Word32 L_tmp2;
115 : Word16 shift;
116 20639 : 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 */
117 : Word32 E_low_fx, E_high_fx;
118 20639 : Word16 temp16, Thres_fx = 0;
119 : Word16 exp;
120 : #ifdef BASOP_NOGLOB_DECLARE_LOCAL
121 20639 : Flag Overflow = 0;
122 20639 : move32();
123 : #endif
124 :
125 20639 : shift = 0;
126 20639 : move16();
127 :
128 20639 : IsTransient = 0;
129 20639 : move16();
130 20639 : IF( NE_16( st_fx->last_extl, st_fx->extl ) )
131 : {
132 2257 : st_fx->TransientHangOver = 0;
133 2257 : move16();
134 2257 : st_fx->old_hpfilt_in_fx = 0;
135 2257 : move16();
136 2257 : st_fx->old_hpfilt_out_fx = 0;
137 2257 : move16();
138 : }
139 :
140 : /* High pass filter */
141 20639 : hp_filter_fx( in_fx, out_filt_fx, &( st_fx->old_hpfilt_in_fx ), &( st_fx->old_hpfilt_out_fx ), L );
142 :
143 : /* Long term energy */
144 20639 : test();
145 20639 : test();
146 20639 : test();
147 20639 : 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 ) )
148 : {
149 : /*EnergyLT = EPSILON_FX; */
150 9929 : EnergyLT = L_deposit_l( 0 );
151 1974489 : FOR( i = 0; i < L / 4; i++ )
152 : {
153 : /*EnergyLT += out_filt[i] * out_filt[i]; */
154 1964560 : EnergyLT = L_mac0_o( EnergyLT, out_filt_fx[i], out_filt_fx[i], &Overflow ); /*2Q_new */
155 : }
156 : }
157 : ELSE
158 : {
159 10710 : EnergyLT = L_add( st_fx->EnergyLT_fx, 0 ); /*2Q_new */
160 : }
161 20639 : IF( EQ_16( L, L_FRAME8k ) )
162 : {
163 0 : Energy_in_fx[0] = st_fx->Energy_Old_fx; /*Q0*/
164 0 : move32();
165 : /* Compute block energy */
166 0 : FOR( blk = 0; blk < 4; blk++ )
167 : {
168 0 : Energy_fx = L_deposit_l( 0 );
169 0 : Energy_in_fx[blk + 1] = L_deposit_l( 0 );
170 0 : FOR( i = 0; i < L / 4; i++ )
171 : {
172 0 : temp16 = extract_l( L_shr( out_filt_fx[i + blk * ( L / 4 )], 12 ) );
173 0 : Energy_fx = L_add_o( Energy_fx, L_mult0( temp16, temp16 ), &Overflow );
174 0 : temp16 = shr( in_fx[i + blk * ( L / 4 )], Q_new ); /*Q0*/
175 0 : Energy_in_fx[blk + 1] = L_add_o( Energy_in_fx[blk + 1], L_mult0( temp16, temp16 ), &Overflow ); /*Q0*/
176 0 : move32();
177 : }
178 :
179 0 : E_in_fx = L_add_o( E_in_fx, Energy_in_fx[blk + 1], &Overflow ); /*Q0*/
180 0 : E_out_fx = L_add_o( E_out_fx, Energy_fx, &Overflow ); /*Q0*/
181 :
182 0 : Thres_fx = 2185; /*1 /15 Q15*/
183 0 : move16();
184 0 : IF( GT_32( Mult_32_16( Energy_fx, 5461 ), EnergyLT ) )
185 : {
186 0 : IsTransient = 1;
187 0 : move16();
188 0 : position = blk;
189 0 : move16();
190 : }
191 :
192 0 : EnergyLT = L_add( Mult_32_16( EnergyLT, 24576 /*Q15*/ ), Mult_32_16( Energy_fx, 8192 /*Q15*/ ) ); /*2Q_new*/
193 : }
194 : }
195 : ELSE
196 : {
197 : /* Compute block energy */
198 103195 : FOR( blk = 0; blk < 4; blk++ )
199 : {
200 82556 : L_tmp = L_deposit_l( 0 );
201 6040476 : FOR( i = 0; i < L / 8; i++ )
202 : {
203 : /*Energy += out_filt_fx[i + blk*(L/4)] * out_filt_fx[i + blk*(L/4)]; */
204 5957920 : L_tmp = L_mac0_o( L_tmp, out_filt_fx[i + blk * ( L / 4 )], out_filt_fx[i + blk * ( L / 4 )], &Overflow ); /*2Q_new */
205 : }
206 82556 : L_tmp2 = L_deposit_l( 0 );
207 6040476 : FOR( ; i < L / 4; i++ )
208 : {
209 : /*Energy += out_filt_fx[i + blk*(L/4)] * out_filt_fx[i + blk*(L/4)]; */
210 5957920 : L_tmp2 = L_mac0_o( L_tmp2, out_filt_fx[i + blk * ( L / 4 )], out_filt_fx[i + blk * ( L / 4 )], &Overflow ); /*2Q_new */
211 : }
212 82556 : Overflow = 0;
213 82556 : move16();
214 82556 : Energy = L_add_o( L_tmp, L_tmp2, &Overflow ); /*2Q_new */
215 82556 : shift = 0;
216 82556 : if ( Overflow != 0 )
217 : {
218 793 : shift = 1;
219 793 : move16();
220 : }
221 82556 : Overflow = 0;
222 82556 : move16();
223 :
224 82556 : Energy = L_add_o( L_shr( L_tmp, shift ), L_shr( L_tmp2, shift ), &Overflow ); /*2Q_new - shift*/
225 82556 : test();
226 82556 : IF( EQ_16( st_fx->extl, SWB_BWE ) || EQ_16( st_fx->extl, FB_BWE ) )
227 : {
228 : /*Calculate shift to get to Q0*/
229 46972 : test();
230 46972 : test();
231 46972 : 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 ) ) )
232 : {
233 431 : IsTransient = 1;
234 431 : move16();
235 431 : position = blk;
236 431 : move16();
237 : }
238 : }
239 : ELSE
240 : {
241 35584 : test();
242 35584 : IF( LE_32( st_fx->total_brate, HQ_16k40 ) && EQ_16( st_fx->bwidth, SWB ) )
243 : {
244 148 : thr = 2427;
245 148 : move16();
246 : }
247 : ELSE
248 : {
249 35436 : thr = 5461;
250 35436 : move16();
251 : }
252 35584 : thr = shl( thr, shift );
253 : /*if(Energy > L_shr(Mult_32_16(EnergyLT,22624),shift_cnt)) //getting in Q0 32*16 = Q_inp1+Q_inp2+1-16 */
254 35584 : IF( GT_32( Mult_32_16( Energy, thr ), EnergyLT ) )
255 : /*if(Energy > 6.0f * EnergyLT) */
256 : {
257 341 : IsTransient = 1;
258 341 : move16();
259 341 : position = blk;
260 341 : move16();
261 : }
262 : }
263 : /*EnergyLT = 0.75f*EnergyLT + 0.25f*Energy; */
264 : /*0.75f*EnergyLT in Q0 //0.25f*Energy in Q0 */
265 82556 : 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 */
266 : }
267 : }
268 20639 : st_fx->EnergyLT_fx = EnergyLT;
269 20639 : move32();
270 :
271 20639 : test();
272 20639 : test();
273 20639 : test();
274 20639 : test();
275 20639 : test();
276 40184 : if ( ( NE_16( st_fx->last_extl, SWB_BWE ) && NE_16( st_fx->last_extl, SWB_TBE ) && EQ_16( st_fx->extl, SWB_BWE ) ) ||
277 34562 : ( NE_16( st_fx->last_extl, FB_BWE ) && NE_16( st_fx->last_extl, FB_TBE ) && EQ_16( st_fx->extl, FB_BWE ) ) )
278 : {
279 1167 : IsTransient = 0;
280 1167 : move16();
281 : }
282 :
283 20639 : test();
284 20639 : IF( IsTransient && L == L_FRAME8k )
285 : {
286 0 : blk = 0;
287 0 : move16();
288 0 : E_low_fx = L_deposit_l( 0 );
289 0 : FOR( i = 0; i < position + 1; i++ )
290 : {
291 : /*blk++; */
292 0 : blk = add( blk, 1 );
293 0 : E_low_fx = L_add_sat( E_low_fx, Energy_in_fx[i] ); /*Q0*/
294 : }
295 :
296 0 : exp = norm_s( blk );
297 0 : temp16 = div_s( 16384, shl( blk, exp ) ); /* 15 + 14 - exp; */
298 0 : exp = 15 + 14 - exp;
299 0 : temp16 = shl( temp16, sub( 15, exp ) );
300 0 : E_low_fx = Mult_32_16( E_low_fx, temp16 );
301 :
302 0 : blk = 0;
303 0 : move16();
304 0 : E_high_fx = L_deposit_l( 0 );
305 0 : FOR( i = position + 1; i < 5; i++ )
306 : {
307 : /*blk++; */
308 0 : blk = add( blk, 1 );
309 0 : E_high_fx = L_add_sat( E_high_fx, Energy_in_fx[i] ); /*Q0*/
310 : }
311 :
312 0 : exp = norm_s( blk );
313 0 : temp16 = div_s( 16384, shl( blk, exp ) ); /* 15 + 14 - exp; */
314 0 : exp = 15 + 14 - exp;
315 0 : temp16 = shl( temp16, 15 - exp );
316 0 : E_high_fx = Mult_32_16( E_high_fx, temp16 );
317 :
318 0 : test();
319 0 : test();
320 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 ) )
321 : {
322 0 : IsTransient = 0;
323 0 : move16();
324 : }
325 : }
326 20639 : IF( EQ_32( st_fx->core_brate, ACELP_24k40 ) )
327 : {
328 53 : test();
329 53 : IF( NE_16( st_fx->last_core, HQ_CORE ) || NE_32( st_fx->last_core_brate, ACELP_24k40 ) )
330 : {
331 53 : st_fx->TransientHangOver = 0;
332 53 : move16();
333 53 : IsTransient = 0;
334 53 : move16();
335 : }
336 : ELSE
337 : {
338 0 : IF( IsTransient )
339 : {
340 0 : if ( EQ_16( position, 3 ) )
341 : {
342 : /* Set Hangover */
343 0 : st_fx->TransientHangOver = 1;
344 0 : move16();
345 : }
346 : }
347 : ELSE
348 : {
349 0 : IF( st_fx->TransientHangOver )
350 : {
351 0 : st_fx->TransientHangOver = 0;
352 0 : move16();
353 0 : IsTransient = 1;
354 0 : move16();
355 : }
356 : }
357 : }
358 : }
359 : ELSE
360 : {
361 20586 : IF( IsTransient )
362 : {
363 423 : st_fx->TransientHangOver = 1;
364 423 : move16();
365 : }
366 : ELSE
367 : {
368 20163 : IF( st_fx->TransientHangOver )
369 : {
370 304 : st_fx->TransientHangOver = 0;
371 304 : move16();
372 304 : IsTransient = 1;
373 304 : move16();
374 : }
375 : }
376 : }
377 :
378 20639 : if ( EQ_16( L, L_FRAME8k ) )
379 : {
380 0 : st_fx->Energy_Old_fx = Energy_in_fx[4]; /*Q0*/
381 0 : move32();
382 : }
383 :
384 20639 : return IsTransient;
385 : }
|