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