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 1793 : 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 1793 : const Word16 *filt_coeff_arr_e = NULL;
106 :
107 1793 : hTranDet->in_duck_gain = 1073741824; // Q30
108 1793 : move32();
109 1793 : hTranDet->out_duck_gain = 1073741824; // Q30
110 1793 : move32();
111 :
112 7172 : FOR( i = 0; i < 3; i++ )
113 : {
114 5379 : set32_fx( filt_coeff_arr_fx[i], 0, IVAS_BIQUAD_FILT_LEN << 1 );
115 : }
116 :
117 1793 : SWITCH( sampling_rate )
118 : {
119 1131 : case 48000:
120 : /*env_hpf*/
121 1131 : filt_coeff_arr_fx[0][0] = IVAS_C_HPF_48k_fx; /*Q30*/
122 1131 : move32();
123 1131 : filt_coeff_arr_fx[0][1] = L_negate( IVAS_C_HPF_48k_fx ); /*Q30*/
124 1131 : move32();
125 1131 : filt_coeff_arr_fx[0][3] = ONE_IN_Q30; /*Q30*/
126 1131 : move32();
127 1131 : filt_coeff_arr_fx[0][4] = L_negate( IVAS_C_HPF_48k_fx ); /*Q30*/
128 1131 : move32();
129 :
130 : /*env_fast*/
131 1131 : filt_coeff_arr_fx[1][0] = L_sub( ONE_IN_Q30, IVAS_C_FAST_48k_fx ); /*Q30*/
132 1131 : move32();
133 1131 : filt_coeff_arr_fx[1][3] = ONE_IN_Q30; /*Q30*/
134 1131 : move32();
135 1131 : filt_coeff_arr_fx[1][4] = L_negate( IVAS_C_FAST_48k_fx ); /*Q30*/
136 1131 : move32();
137 :
138 : /*env_slow*/
139 1131 : filt_coeff_arr_fx[2][0] = L_sub( ONE_IN_Q30, IVAS_C_SLOW_48k_fx ); /*Q30*/
140 1131 : move32();
141 1131 : filt_coeff_arr_fx[2][3] = ONE_IN_Q30; /*Q30*/
142 1131 : move32();
143 1131 : filt_coeff_arr_fx[2][4] = L_negate( IVAS_C_SLOW_48k_fx ); /*Q30*/
144 1131 : move32();
145 :
146 1131 : hTranDet->in_duck_coeff = IVAS_C_IN_DUCK_48k_fx; /*Q30*/
147 1131 : move32();
148 1131 : hTranDet->out_duck_coeff = IVAS_C_OUT_DUCK_48k_fx; /*Q30*/
149 1131 : move32();
150 :
151 :
152 1131 : BREAK;
153 585 : case 32000:
154 : /*env_hpf*/
155 585 : filt_coeff_arr_fx[0][0] = IVAS_C_HPF_32k_fx; /*Q30*/
156 585 : move32();
157 585 : filt_coeff_arr_fx[0][1] = L_negate( IVAS_C_HPF_32k_fx ); /*Q30*/
158 585 : move32();
159 585 : filt_coeff_arr_fx[0][3] = ONE_IN_Q30; /*Q30*/
160 585 : move32();
161 585 : filt_coeff_arr_fx[0][4] = L_negate( IVAS_C_HPF_32k_fx ); /*Q30*/
162 585 : move32();
163 :
164 : /*env_fast*/
165 585 : filt_coeff_arr_fx[1][0] = L_sub( ONE_IN_Q30, IVAS_C_FAST_32k_fx ); /*Q30*/
166 585 : move32();
167 585 : filt_coeff_arr_fx[1][3] = ONE_IN_Q30; /*Q30*/
168 585 : move32();
169 585 : filt_coeff_arr_fx[1][4] = L_negate( IVAS_C_FAST_32k_fx ); /*Q30*/
170 585 : move32();
171 :
172 :
173 : /*env_slow*/
174 585 : filt_coeff_arr_fx[2][0] = L_sub( ONE_IN_Q30, IVAS_C_SLOW_32k_fx ); /*Q30*/
175 585 : move32();
176 585 : filt_coeff_arr_fx[2][3] = ONE_IN_Q30; /*Q30*/
177 585 : move32();
178 585 : filt_coeff_arr_fx[2][4] = L_negate( IVAS_C_SLOW_32k_fx ); /*Q30*/
179 585 : move32();
180 585 : hTranDet->in_duck_coeff = IVAS_C_IN_DUCK_32k_fx; /*Q30*/
181 585 : move32();
182 585 : hTranDet->out_duck_coeff = IVAS_C_OUT_DUCK_32k_fx; /*Q30*/
183 585 : move32();
184 :
185 :
186 585 : BREAK;
187 77 : case 16000:
188 : /*env_hpf*/
189 77 : filt_coeff_arr_fx[0][0] = IVAS_C_HPF_16k_fx; /*Q30*/
190 77 : move32();
191 77 : filt_coeff_arr_fx[0][1] = L_negate( IVAS_C_HPF_16k_fx ); /*Q30*/
192 77 : move32();
193 77 : filt_coeff_arr_fx[0][3] = ONE_IN_Q30; /*Q30*/
194 77 : move32();
195 77 : filt_coeff_arr_fx[0][4] = L_negate( IVAS_C_HPF_16k_fx ); /*Q30*/
196 77 : move32();
197 :
198 :
199 : /*env_fast*/
200 77 : filt_coeff_arr_fx[1][0] = L_sub( ONE_IN_Q30, IVAS_C_FAST_16k_fx ); /*Q30*/
201 77 : move32();
202 77 : filt_coeff_arr_fx[1][3] = ONE_IN_Q30; /*Q30*/
203 77 : move32();
204 77 : filt_coeff_arr_fx[1][4] = L_negate( IVAS_C_FAST_16k_fx ); /*Q30*/
205 77 : move32();
206 :
207 :
208 : /*env_slow*/
209 77 : filt_coeff_arr_fx[2][0] = L_sub( ONE_IN_Q30, IVAS_C_SLOW_16k_fx ); /*Q30*/
210 77 : move32();
211 77 : filt_coeff_arr_fx[2][3] = ONE_IN_Q30; /*Q30*/
212 77 : move32();
213 77 : filt_coeff_arr_fx[2][4] = L_negate( IVAS_C_SLOW_16k_fx ); /*Q30*/
214 77 : move32();
215 :
216 77 : hTranDet->in_duck_coeff = IVAS_C_IN_DUCK_16k_fx; /*Q30*/
217 77 : move32();
218 77 : hTranDet->out_duck_coeff = IVAS_C_OUT_DUCK_16k_fx; /*Q30*/
219 77 : move32();
220 :
221 :
222 77 : BREAK;
223 : }
224 :
225 1793 : ivas_filters_init_fx( &hTranDet->env_hpf, (const Word32 *) filt_coeff_arr_fx[0], filt_coeff_arr_e, IVAS_FILTER_ORDER_1 );
226 1793 : ivas_filters_init_fx( &hTranDet->env_fast, (const Word32 *) filt_coeff_arr_fx[1], filt_coeff_arr_e, IVAS_FILTER_ORDER_1 );
227 1793 : ivas_filters_init_fx( &hTranDet->env_slow, (const Word32 *) filt_coeff_arr_fx[2], filt_coeff_arr_e, IVAS_FILTER_ORDER_1 );
228 :
229 1793 : hTranDet->duck_mult_fac = IVAS_TDET_DUCK_MULT_FAC; /*Q29*/
230 1793 : move32();
231 :
232 1793 : return;
233 : }
234 :
235 : /*-------------------------------------------------------------------------
236 : * ivas_transient_det_open()
237 : *
238 : * Allocate and initialize SPAR TD handle
239 : *------------------------------------------------------------------------*/
240 1793 : 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 1793 : 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 1793 : ivas_transient_det_init( hTranDet, sampling_rate );
253 :
254 1793 : *hTranDet_in = hTranDet;
255 :
256 1793 : return IVAS_ERR_OK;
257 : }
258 :
259 :
260 : /*-------------------------------------------------------------------------
261 : * ivas_transient_det_close()
262 : *
263 : * Deallocate and initialize Transient detector handle
264 : *------------------------------------------------------------------------*/
265 1793 : void ivas_transient_det_close_fx(
266 : ivas_trans_det_state_t **hTranDet /* i/o: Transient detector handle */
267 : )
268 : {
269 1793 : test();
270 1793 : IF( hTranDet == NULL || *hTranDet == NULL )
271 : {
272 0 : return;
273 : }
274 :
275 1793 : free( *hTranDet );
276 1793 : *hTranDet = NULL;
277 :
278 1793 : return;
279 : }
280 :
281 : /*-----------------------------------------------------------------------------------------*
282 : * Function ivas_transient_det_process_fx()
283 : *
284 : * Transient detection process call
285 : *-----------------------------------------------------------------------------------------*/
286 :
287 163820 : 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 163820 : Word32 mem = hTranDet->in_duck_gain; /*Q30*/
297 163820 : move32();
298 :
299 163820 : ivas_td_decorr_get_ducking_gains_fx( hTranDet, pIn_pcm, in_duck_gain, NULL, frame_len, IVAS_TDET_ONLY );
300 163820 : transient_det[0] = 0;
301 163820 : move16();
302 163820 : transient_det[1] = 0;
303 163820 : move16();
304 163820 : if ( GT_32( L_sub( mem, hTranDet->in_duck_gain ), IVAS_TDET_PARM_TRANS_THR ) )
305 : {
306 16750 : transient_det[0] = 1;
307 16750 : move16();
308 : }
309 :
310 163820 : num_sf = 16; /*Q0*/
311 163820 : move16();
312 163820 : sf_samp = idiv1616( frame_len, num_sf ); /*Q0*/
313 2784940 : FOR( sf = 1; sf <= num_sf; sf++ )
314 : {
315 2621120 : idx = sub( imult1616( sf_samp, sf ), 1 );
316 2621120 : if ( GT_32( L_sub( mem, in_duck_gain[idx] ), IVAS_POINT_ONE_ONE_IN_Q30 ) )
317 : {
318 8725 : transient_det[1] = 1;
319 8725 : move16();
320 : }
321 2621120 : mem = in_duck_gain[idx]; /*Q30*/
322 2621120 : move32();
323 : }
324 :
325 163820 : return;
326 : }
327 : /*-----------------------------------------------------------------------------------------*
328 : * Function ivas_calc_duck_gain_fx()
329 : *
330 : * Calculate ducking gain utility
331 : *-----------------------------------------------------------------------------------------*/
332 :
333 264955720 : 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 264955720 : duck_gain_out = L_add( Mpy_32_32( L_sub( duck_gain, ONE_IN_Q30 ), duck_coeff ), ONE_IN_Q29 ); /*Q29*/
346 :
347 264955720 : 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 13691428 : duck_gain_out = 0;
351 13691428 : move32();
352 :
353 13691428 : test();
354 13691428 : IF( ( env_1 != 0 ) && ( env_2 != 0 ) )
355 : {
356 13691428 : L_tmp = BASOP_Util_Divide3232_Scale_newton( env_1, env_2, &tmp_e );
357 13691428 : L_tmp = L_shl( L_tmp, add( sub( env1_e, env2_e ), tmp_e ) );
358 :
359 13691428 : duck_gain_out = Mpy_32_32( duck_mult_fac, L_tmp ); /*Q29*/
360 : }
361 : }
362 :
363 264955720 : duck_gain_out = L_shl( duck_gain_out, Q1 ); /*Q30*/
364 :
365 264955720 : 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 249950 : 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 249950 : Word32 in_duck_gain = hTranDet->in_duck_gain; /*Q30*/
385 249950 : move32();
386 249950 : Word32 out_duck_gain = hTranDet->out_duck_gain; /*Q30*/
387 249950 : move32();
388 249950 : Word32 in_duck_coeff = hTranDet->in_duck_coeff; /*Q30*/
389 249950 : move32();
390 249950 : Word32 out_duck_coeff = hTranDet->out_duck_coeff; /*Q30*/
391 249950 : move32();
392 249950 : Word32 duck_mult_fac = hTranDet->duck_mult_fac; /*Q29*/
393 249950 : move32();
394 :
395 249950 : Copy32( pIn_pcm, e_fast_fx, frame_len ); /*Q11*/
396 :
397 249950 : set16_fx( e_fast_e, 31 - Q11, L_FRAME48k );
398 :
399 : /* env hpf */
400 249950 : ivas_filter_process_exp_fx( &hTranDet->env_hpf, e_fast_fx, frame_len, e_fast_e );
401 :
402 :
403 196241410 : 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 195991460 : 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 195991460 : move32();
408 195991460 : e_slow_fx[i] = e_fast_fx[i];
409 195991460 : move32();
410 195991460 : e_slow_e[i] = e_fast_e[i];
411 195991460 : move16();
412 : }
413 :
414 : /* env fast*/
415 249950 : ivas_filter_process_exp_fx( &hTranDet->env_fast, e_fast_fx, frame_len, e_fast_e );
416 :
417 : /* env slow */
418 249950 : ivas_filter_process_exp_fx( &hTranDet->env_slow, e_slow_fx, frame_len, e_slow_e );
419 :
420 249950 : IF( tdet_flag )
421 : {
422 127191020 : FOR( i = 0; i < frame_len; i++ )
423 : {
424 127027200 : 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 127027200 : pIn_duck_gains[i] = in_duck_gain; /*Q30*/
426 127027200 : move32();
427 : }
428 163820 : hTranDet->in_duck_gain = in_duck_gain; /*Q30*/
429 163820 : 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 249950 : return;
449 : }
|