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 : #include <stdint.h>
34 : #include "options.h"
35 : #include "math.h"
36 : #include "wmc_auto.h"
37 : #include "prot_fx.h"
38 : #include "ivas_cnst.h"
39 : #include "ivas_prot_fx.h"
40 : #include "ivas_stat_com.h"
41 :
42 : /*------------------------------------------------------------------------------------------*
43 : * Local constants
44 : *------------------------------------------------------------------------------------------*/
45 :
46 : #define IVAS_TDET_PARM_ENV_EPS ( 1e-5f )
47 : #define IVAS_TDET_PARM_ENV_EPS_fx 21474 // Q31
48 :
49 : #define IVAS_TDET_DUCK_MULT_FAC ( 590558003 ) // Q29
50 : #define IVAS_TDET_PARM_TRANS_THR ( 107374182 ) // Q30
51 : #define IVAS_POINT_ONE_ONE_IN_Q30 ( 118111601 ) // Q30
52 :
53 : #define IVAS_TDET_ONLY ( 1 )
54 :
55 : /*env_hpf*/
56 : #define IVAS_C_HPF_48k ( 0.675231906655777f )
57 : #define IVAS_C_HPF_32k ( 0.554854910159853f )
58 : #define IVAS_C_HPF_16k ( 0.307863971328499f )
59 :
60 : #define IVAS_C_HPF_48k_fx ( 0x2b370000 )
61 : #define IVAS_C_HPF_32k_fx ( 0x2382be40 )
62 : #define IVAS_C_HPF_16k_fx ( 0x13b40b20 )
63 :
64 : /*env_fast*/
65 : #define IVAS_C_FAST_48k ( 0.995842001845110f )
66 : #define IVAS_C_FAST_32k ( 0.993769490623395f )
67 : #define IVAS_C_FAST_16k ( 0.987577800493881f )
68 :
69 : #define IVAS_C_FAST_48k_fx ( 0x3fbbe000 )
70 : #define IVAS_C_FAST_32k_fx ( 0x3f99eb40 )
71 : #define IVAS_C_FAST_16k_fx ( 0x3f347980 )
72 :
73 : /*env_slow*/
74 : #define IVAS_C_SLOW_48k ( 0.999739617238810f )
75 : #define IVAS_C_SLOW_32k ( 0.999609451284012f )
76 : #define IVAS_C_SLOW_16k ( 0.999219055096324f )
77 :
78 : #define IVAS_C_SLOW_48k_fx ( 0x3ffbbc00 )
79 : #define IVAS_C_SLOW_32k_fx ( 0x3ff99a00 )
80 : #define IVAS_C_SLOW_16k_fx ( 0x3ff33480 )
81 :
82 : /*induck*/
83 : #define IVAS_C_IN_DUCK_48k_fx ( 1073294525 ) // Q30
84 : #define IVAS_C_IN_DUCK_32k_fx ( 1073070945 ) // Q30
85 : #define IVAS_C_IN_DUCK_16k_fx ( 1072400485 ) // Q30
86 :
87 : /*outduck*/
88 : #define IVAS_C_OUT_DUCK_48k_fx ( 1073294525 ) // Q30
89 : #define IVAS_C_OUT_DUCK_32k_fx ( 1073070945 ) // Q30
90 : #define IVAS_C_OUT_DUCK_16k_fx ( 1072400485 ) // Q30
91 :
92 : /*-----------------------------------------------------------------------------------------*
93 : * Function ivas_transient_det_init()
94 : *
95 : * Trans det init fucntion
96 : *-----------------------------------------------------------------------------------------*/
97 :
98 1418 : static void ivas_transient_det_init(
99 : ivas_trans_det_state_t *hTranDet, /* i/o: Transient detector handle */
100 : const Word32 sampling_rate /* i : sampling rate Q0*/
101 : )
102 : {
103 : Word16 i;
104 : Word32 filt_coeff_arr_fx[3][IVAS_BIQUAD_FILT_LEN << 1];
105 1418 : const Word16 *filt_coeff_arr_e = NULL;
106 :
107 1418 : hTranDet->in_duck_gain = 1073741824; // Q30
108 1418 : move32();
109 1418 : hTranDet->out_duck_gain = 1073741824; // Q30
110 1418 : move32();
111 :
112 5672 : FOR( i = 0; i < 3; i++ )
113 : {
114 4254 : set32_fx( filt_coeff_arr_fx[i], 0, IVAS_BIQUAD_FILT_LEN << 1 );
115 : }
116 :
117 1418 : SWITCH( sampling_rate )
118 : {
119 912 : case 48000:
120 : /*env_hpf*/
121 912 : filt_coeff_arr_fx[0][0] = IVAS_C_HPF_48k_fx; /*Q30*/
122 912 : move32();
123 912 : filt_coeff_arr_fx[0][1] = L_negate( IVAS_C_HPF_48k_fx ); /*Q30*/
124 912 : move32();
125 912 : filt_coeff_arr_fx[0][3] = ONE_IN_Q30; /*Q30*/
126 912 : move32();
127 912 : filt_coeff_arr_fx[0][4] = L_negate( IVAS_C_HPF_48k_fx ); /*Q30*/
128 912 : move32();
129 :
130 : /*env_fast*/
131 912 : filt_coeff_arr_fx[1][0] = L_sub( ONE_IN_Q30, IVAS_C_FAST_48k_fx ); /*Q30*/
132 912 : move32();
133 912 : filt_coeff_arr_fx[1][3] = ONE_IN_Q30; /*Q30*/
134 912 : move32();
135 912 : filt_coeff_arr_fx[1][4] = L_negate( IVAS_C_FAST_48k_fx ); /*Q30*/
136 912 : move32();
137 :
138 : /*env_slow*/
139 912 : filt_coeff_arr_fx[2][0] = L_sub( ONE_IN_Q30, IVAS_C_SLOW_48k_fx ); /*Q30*/
140 912 : move32();
141 912 : filt_coeff_arr_fx[2][3] = ONE_IN_Q30; /*Q30*/
142 912 : move32();
143 912 : filt_coeff_arr_fx[2][4] = L_negate( IVAS_C_SLOW_48k_fx ); /*Q30*/
144 912 : move32();
145 :
146 912 : hTranDet->in_duck_coeff = IVAS_C_IN_DUCK_48k_fx; /*Q30*/
147 912 : move32();
148 912 : hTranDet->out_duck_coeff = IVAS_C_OUT_DUCK_48k_fx; /*Q30*/
149 912 : move32();
150 :
151 :
152 912 : BREAK;
153 468 : case 32000:
154 : /*env_hpf*/
155 468 : filt_coeff_arr_fx[0][0] = IVAS_C_HPF_32k_fx; /*Q30*/
156 468 : move32();
157 468 : filt_coeff_arr_fx[0][1] = L_negate( IVAS_C_HPF_32k_fx ); /*Q30*/
158 468 : move32();
159 468 : filt_coeff_arr_fx[0][3] = ONE_IN_Q30; /*Q30*/
160 468 : move32();
161 468 : filt_coeff_arr_fx[0][4] = L_negate( IVAS_C_HPF_32k_fx ); /*Q30*/
162 468 : move32();
163 :
164 : /*env_fast*/
165 468 : filt_coeff_arr_fx[1][0] = L_sub( ONE_IN_Q30, IVAS_C_FAST_32k_fx ); /*Q30*/
166 468 : move32();
167 468 : filt_coeff_arr_fx[1][3] = ONE_IN_Q30; /*Q30*/
168 468 : move32();
169 468 : filt_coeff_arr_fx[1][4] = L_negate( IVAS_C_FAST_32k_fx ); /*Q30*/
170 468 : move32();
171 :
172 :
173 : /*env_slow*/
174 468 : filt_coeff_arr_fx[2][0] = L_sub( ONE_IN_Q30, IVAS_C_SLOW_32k_fx ); /*Q30*/
175 468 : move32();
176 468 : filt_coeff_arr_fx[2][3] = ONE_IN_Q30; /*Q30*/
177 468 : move32();
178 468 : filt_coeff_arr_fx[2][4] = L_negate( IVAS_C_SLOW_32k_fx ); /*Q30*/
179 468 : move32();
180 468 : hTranDet->in_duck_coeff = IVAS_C_IN_DUCK_32k_fx; /*Q30*/
181 468 : move32();
182 468 : hTranDet->out_duck_coeff = IVAS_C_OUT_DUCK_32k_fx; /*Q30*/
183 468 : move32();
184 :
185 :
186 468 : BREAK;
187 38 : case 16000:
188 : /*env_hpf*/
189 38 : filt_coeff_arr_fx[0][0] = IVAS_C_HPF_16k_fx; /*Q30*/
190 38 : move32();
191 38 : filt_coeff_arr_fx[0][1] = L_negate( IVAS_C_HPF_16k_fx ); /*Q30*/
192 38 : move32();
193 38 : filt_coeff_arr_fx[0][3] = ONE_IN_Q30; /*Q30*/
194 38 : move32();
195 38 : filt_coeff_arr_fx[0][4] = L_negate( IVAS_C_HPF_16k_fx ); /*Q30*/
196 38 : move32();
197 :
198 :
199 : /*env_fast*/
200 38 : filt_coeff_arr_fx[1][0] = L_sub( ONE_IN_Q30, IVAS_C_FAST_16k_fx ); /*Q30*/
201 38 : move32();
202 38 : filt_coeff_arr_fx[1][3] = ONE_IN_Q30; /*Q30*/
203 38 : move32();
204 38 : filt_coeff_arr_fx[1][4] = L_negate( IVAS_C_FAST_16k_fx ); /*Q30*/
205 38 : move32();
206 :
207 :
208 : /*env_slow*/
209 38 : filt_coeff_arr_fx[2][0] = L_sub( ONE_IN_Q30, IVAS_C_SLOW_16k_fx ); /*Q30*/
210 38 : move32();
211 38 : filt_coeff_arr_fx[2][3] = ONE_IN_Q30; /*Q30*/
212 38 : move32();
213 38 : filt_coeff_arr_fx[2][4] = L_negate( IVAS_C_SLOW_16k_fx ); /*Q30*/
214 38 : move32();
215 :
216 38 : hTranDet->in_duck_coeff = IVAS_C_IN_DUCK_16k_fx; /*Q30*/
217 38 : move32();
218 38 : hTranDet->out_duck_coeff = IVAS_C_OUT_DUCK_16k_fx; /*Q30*/
219 38 : move32();
220 :
221 :
222 38 : BREAK;
223 : }
224 :
225 1418 : ivas_filters_init_fx( &hTranDet->env_hpf, (const Word32 *) filt_coeff_arr_fx[0], filt_coeff_arr_e, IVAS_FILTER_ORDER_1 );
226 1418 : ivas_filters_init_fx( &hTranDet->env_fast, (const Word32 *) filt_coeff_arr_fx[1], filt_coeff_arr_e, IVAS_FILTER_ORDER_1 );
227 1418 : ivas_filters_init_fx( &hTranDet->env_slow, (const Word32 *) filt_coeff_arr_fx[2], filt_coeff_arr_e, IVAS_FILTER_ORDER_1 );
228 :
229 1418 : hTranDet->duck_mult_fac = IVAS_TDET_DUCK_MULT_FAC; /*Q29*/
230 1418 : move32();
231 :
232 1418 : return;
233 : }
234 :
235 : /*-------------------------------------------------------------------------
236 : * ivas_transient_det_open()
237 : *
238 : * Allocate and initialize SPAR TD handle
239 : *------------------------------------------------------------------------*/
240 1418 : ivas_error ivas_transient_det_open_fx(
241 : ivas_trans_det_state_t **hTranDet_in, /* i/o: Transient detector handle */
242 : const Word32 sampling_rate /* i : sampling rate Q0*/
243 : )
244 : {
245 : ivas_trans_det_state_t *hTranDet;
246 :
247 1418 : IF( ( hTranDet = (ivas_trans_det_state_t *) malloc( sizeof( ivas_trans_det_state_t ) ) ) == NULL )
248 : {
249 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for SPAR TD\n" );
250 : }
251 :
252 1418 : ivas_transient_det_init( hTranDet, sampling_rate );
253 :
254 1418 : *hTranDet_in = hTranDet;
255 :
256 1418 : return IVAS_ERR_OK;
257 : }
258 :
259 :
260 : /*-------------------------------------------------------------------------
261 : * ivas_transient_det_close()
262 : *
263 : * Deallocate and initialize Transient detector handle
264 : *------------------------------------------------------------------------*/
265 1418 : void ivas_transient_det_close_fx(
266 : ivas_trans_det_state_t **hTranDet /* i/o: Transient detector handle */
267 : )
268 : {
269 1418 : test();
270 1418 : IF( hTranDet == NULL || *hTranDet == NULL )
271 : {
272 0 : return;
273 : }
274 :
275 1418 : free( *hTranDet );
276 1418 : *hTranDet = NULL;
277 :
278 1418 : return;
279 : }
280 :
281 : /*-----------------------------------------------------------------------------------------*
282 : * Function ivas_transient_det_process_fx()
283 : *
284 : * Transient detection process call
285 : *-----------------------------------------------------------------------------------------*/
286 :
287 0 : void ivas_transient_det_process_fx(
288 : ivas_trans_det_state_t *hTranDet, /* i/o: SPAR TD handle */
289 : Word32 *pIn_pcm, /* i : input audio channels Q11*/
290 : const Word16 frame_len, /* i : frame length in samples Q0*/
291 : Word16 transient_det[2] /* o : transient det outputs Q0*/
292 : )
293 : {
294 : Word32 in_duck_gain[L_FRAME48k];
295 : Word16 num_sf, sf, sf_samp, idx;
296 0 : Word32 mem = hTranDet->in_duck_gain; /*Q30*/
297 0 : move32();
298 :
299 0 : ivas_td_decorr_get_ducking_gains_fx( hTranDet, pIn_pcm, in_duck_gain, NULL, frame_len, IVAS_TDET_ONLY );
300 0 : transient_det[0] = 0;
301 0 : move16();
302 0 : transient_det[1] = 0;
303 0 : move16();
304 0 : if ( GT_32( L_sub( mem, hTranDet->in_duck_gain ), IVAS_TDET_PARM_TRANS_THR ) )
305 : {
306 0 : transient_det[0] = 1;
307 0 : move16();
308 : }
309 :
310 0 : num_sf = 16; /*Q0*/
311 0 : move16();
312 0 : sf_samp = idiv1616( frame_len, num_sf ); /*Q0*/
313 0 : FOR( sf = 1; sf <= num_sf; sf++ )
314 : {
315 0 : idx = sub( imult1616( sf_samp, sf ), 1 );
316 0 : if ( GT_32( L_sub( mem, in_duck_gain[idx] ), IVAS_POINT_ONE_ONE_IN_Q30 ) )
317 : {
318 0 : transient_det[1] = 1;
319 0 : move16();
320 : }
321 0 : mem = in_duck_gain[idx]; /*Q30*/
322 0 : move32();
323 : }
324 :
325 0 : return;
326 : }
327 : /*-----------------------------------------------------------------------------------------*
328 : * Function ivas_calc_duck_gain_fx()
329 : *
330 : * Calculate ducking gain utility
331 : *-----------------------------------------------------------------------------------------*/
332 :
333 137928520 : static Word32 ivas_calc_duck_gain_fx(
334 : const Word32 duck_gain, /*Q30*/
335 : const Word32 duck_coeff, /*Q30*/
336 : const Word32 env_1, /*exp : env1_e*/
337 : const Word16 env1_e,
338 : const Word32 env_2, /*exp : env2_e*/
339 : const Word16 env2_e,
340 : const Word32 duck_mult_fac /*Q29*/ )
341 : {
342 : Word32 duck_gain_out, L_tmp;
343 : Word16 tmp_e;
344 :
345 137928520 : duck_gain_out = L_add( Mpy_32_32( L_sub( duck_gain, ONE_IN_Q30 ), duck_coeff ), ONE_IN_Q29 ); /*Q29*/
346 :
347 137928520 : IF( LT_64( W_mult0_32_32( duck_mult_fac, env_1 ), W_shr( W_mult0_32_32( duck_gain_out, env_2 ), sub( env1_e, env2_e ) ) ) )
348 : {
349 :
350 9972497 : duck_gain_out = 0;
351 9972497 : move32();
352 :
353 9972497 : test();
354 9972497 : IF( ( env_1 != 0 ) && ( env_2 != 0 ) )
355 : {
356 9972497 : L_tmp = BASOP_Util_Divide3232_Scale_newton( env_1, env_2, &tmp_e );
357 9972497 : L_tmp = L_shl( L_tmp, add( sub( env1_e, env2_e ), tmp_e ) );
358 :
359 9972497 : duck_gain_out = Mpy_32_32( duck_mult_fac, L_tmp ); /*Q29*/
360 : }
361 : }
362 :
363 137928520 : duck_gain_out = L_shl( duck_gain_out, Q1 ); /*Q30*/
364 :
365 137928520 : return duck_gain_out; /*Q30*/
366 : }
367 : /*-----------------------------------------------------------------------------------------*
368 : * Function ivas_td_decorr_get_ducking_gains_fx()
369 : *
370 : * Calculate in/out ducking gains
371 : *-----------------------------------------------------------------------------------------*/
372 :
373 86130 : void ivas_td_decorr_get_ducking_gains_fx(
374 : ivas_trans_det_state_t *hTranDet, /* i/o: Transient detector handle */
375 : Word32 *pIn_pcm, /*Q11*/
376 : Word32 *pIn_duck_gains, /*Q30*/
377 : Word32 *pOut_duck_gains, /*Q30*/
378 : const Word16 frame_len, /*Q0*/
379 : const Word16 tdet_flag /*Q0*/ )
380 : {
381 : Word16 i;
382 : Word32 e_fast_fx[L_FRAME48k], e_slow_fx[L_FRAME48k];
383 : Word16 e_fast_e[L_FRAME48k], e_slow_e[L_FRAME48k];
384 86130 : Word32 in_duck_gain = hTranDet->in_duck_gain; /*Q30*/
385 86130 : move32();
386 86130 : Word32 out_duck_gain = hTranDet->out_duck_gain; /*Q30*/
387 86130 : move32();
388 86130 : Word32 in_duck_coeff = hTranDet->in_duck_coeff; /*Q30*/
389 86130 : move32();
390 86130 : Word32 out_duck_coeff = hTranDet->out_duck_coeff; /*Q30*/
391 86130 : move32();
392 86130 : Word32 duck_mult_fac = hTranDet->duck_mult_fac; /*Q29*/
393 86130 : move32();
394 :
395 86130 : Copy32( pIn_pcm, e_fast_fx, frame_len ); /*Q11*/
396 :
397 86130 : set16_fx( e_fast_e, 31 - Q11, L_FRAME48k );
398 :
399 : /* env hpf */
400 86130 : ivas_filter_process_exp_fx( &hTranDet->env_hpf, e_fast_fx, frame_len, e_fast_e );
401 :
402 :
403 69050390 : FOR( i = 0; i < frame_len; i++ )
404 : {
405 : // e_fast_fx[i] = L_add( L_abs( e_fast_fx[i] ), L_shr( IVAS_TDET_PARM_ENV_EPS_fx, q_factor_diff ) ); /*Q14*/
406 68964260 : e_fast_fx[i] = BASOP_Util_Add_Mant32Exp( L_abs( e_fast_fx[i] ), e_fast_e[i], IVAS_TDET_PARM_ENV_EPS_fx, 0, &e_fast_e[i] );
407 68964260 : move32();
408 68964260 : e_slow_fx[i] = e_fast_fx[i];
409 68964260 : move32();
410 68964260 : e_slow_e[i] = e_fast_e[i];
411 68964260 : move16();
412 : }
413 :
414 : /* env fast*/
415 86130 : ivas_filter_process_exp_fx( &hTranDet->env_fast, e_fast_fx, frame_len, e_fast_e );
416 :
417 : /* env slow */
418 86130 : ivas_filter_process_exp_fx( &hTranDet->env_slow, e_slow_fx, frame_len, e_slow_e );
419 :
420 86130 : IF( tdet_flag )
421 : {
422 0 : FOR( i = 0; i < frame_len; i++ )
423 : {
424 0 : in_duck_gain = ivas_calc_duck_gain_fx( in_duck_gain, in_duck_coeff, e_slow_fx[i], e_slow_e[i], e_fast_fx[i], e_fast_e[i], duck_mult_fac ); /*Q30*/
425 0 : pIn_duck_gains[i] = in_duck_gain; /*Q30*/
426 0 : move32();
427 : }
428 0 : hTranDet->in_duck_gain = in_duck_gain; /*Q30*/
429 0 : move32();
430 : }
431 : ELSE
432 : {
433 69050390 : FOR( i = 0; i < frame_len; i++ )
434 : {
435 68964260 : in_duck_gain = ivas_calc_duck_gain_fx( in_duck_gain, in_duck_coeff, e_slow_fx[i], e_slow_e[i], e_fast_fx[i], e_fast_e[i], duck_mult_fac ); /*Q30*/
436 68964260 : pIn_duck_gains[i] = in_duck_gain; /*Q30*/
437 68964260 : move32();
438 68964260 : out_duck_gain = ivas_calc_duck_gain_fx( out_duck_gain, out_duck_coeff, e_fast_fx[i], e_fast_e[i], e_slow_fx[i], e_slow_e[i], duck_mult_fac ); /*Q30*/
439 68964260 : pOut_duck_gains[i] = out_duck_gain; /*Q30*/
440 68964260 : move32();
441 : }
442 86130 : hTranDet->in_duck_gain = in_duck_gain; /*Q30*/
443 86130 : move32();
444 86130 : hTranDet->out_duck_gain = out_duck_gain; /*Q30*/
445 86130 : move32();
446 : }
447 :
448 86130 : return;
449 : }
|