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 "prot_fx.h"
37 : #include "ivas_prot_rend_fx.h"
38 : #include "ivas_rom_rend.h"
39 : #include "wmc_auto.h"
40 : #include <assert.h>
41 : #include "ivas_prot_fx.h"
42 :
43 :
44 : #define ATTACK_CNST_48k ( 2106670080 ) // Q31
45 : #define ATTACK_CNST_32k ( 2086555136 ) // Q31
46 : #define ATTACK_CNST_16k ( 2027355264 ) // Q31
47 : #define ATTACK_CNST_8k ( 1913946752 ) // Q31
48 :
49 :
50 : /*-------------------------------------------------------------------*
51 : * detect_strong_saturations()
52 : *
53 : * Detection of very strong saturations,
54 : * usually happens as a consequence of a heavy corrupted bitstream
55 : *-------------------------------------------------------------------*/
56 :
57 : /*! r: apply_strong_limiting flag */
58 408891 : static Word16 detect_strong_saturations_fx(
59 : const Word16 BER_detect, /* i : BER detect flag */
60 : Word16 *strong_saturation_cnt, /* i/o: counter of strong saturations */
61 : const Word32 max_val, /* i : maximum absolute value q_factor */
62 : Word32 *frame_gain, /* i/o: frame gain value Q30 */
63 : Word16 q_factor /* i : Q factor of the output samples */
64 : )
65 : {
66 : Word16 apply_strong_limiting;
67 : Word64 compare_max_value_Mul_3, compare_max_value_Mul_10;
68 :
69 408891 : apply_strong_limiting = 0;
70 408891 : move16();
71 408891 : compare_max_value_Mul_3 = W_shl( 98187, q_factor ); // 3 * IVAS_LIMITER_THRESHOLD : Q(q_factor)
72 408891 : compare_max_value_Mul_10 = W_shl( 327290, q_factor ); // 10 * IVAS_LIMITER_THRESHOLD : Q(q_factor)
73 408891 : test();
74 408891 : IF( BER_detect )
75 : {
76 0 : *strong_saturation_cnt = 50;
77 0 : move16();
78 0 : apply_strong_limiting = 1;
79 0 : move16();
80 : }
81 408891 : ELSE IF( GT_64( max_val, compare_max_value_Mul_3 ) && GT_16( *strong_saturation_cnt, 0 ) )
82 : {
83 0 : apply_strong_limiting = 1;
84 0 : move16();
85 : }
86 408891 : ELSE IF( GT_64( max_val, compare_max_value_Mul_10 ) )
87 : {
88 0 : *strong_saturation_cnt = add( *strong_saturation_cnt, 20 );
89 0 : move16();
90 0 : *strong_saturation_cnt = s_min( *strong_saturation_cnt, 50 );
91 0 : move16();
92 0 : apply_strong_limiting = 1;
93 0 : move16();
94 : }
95 : ELSE
96 : {
97 408891 : ( *strong_saturation_cnt )--;
98 408891 : *strong_saturation_cnt = s_max( *strong_saturation_cnt, 0 );
99 408891 : move16();
100 : }
101 :
102 408891 : IF( apply_strong_limiting )
103 : {
104 0 : IF( LT_32( *frame_gain, 322122547 /* 0.3 in Q30 */ ) )
105 : {
106 : /* *frame_gain /= 3.0f; */
107 0 : *frame_gain = Mpy_32_16_1( *frame_gain, 10923 /* 1/3 in Q15 */ ); /* Q30 */
108 0 : move32();
109 : }
110 : ELSE
111 : {
112 0 : apply_strong_limiting = 0;
113 0 : move16();
114 : }
115 : }
116 :
117 408891 : return apply_strong_limiting;
118 : }
119 :
120 :
121 : /*-------------------------------------------------------------------*
122 : * ivas_limiter_open()
123 : *
124 : * Allocate and initialize limiter struct
125 : *-------------------------------------------------------------------*/
126 :
127 : /*! r : limiter struct handle */
128 1291 : ivas_error ivas_limiter_open_fx(
129 : IVAS_LIMITER_HANDLE *hLimiter_out, /* o : limiter struct handle */
130 : const Word16 max_num_channels, /* i : maximum number of I/O channels to be processed */
131 : const Word32 sampling_rate /* i : sampling rate for processing */
132 : )
133 : {
134 : Word16 i;
135 : IVAS_LIMITER_HANDLE hLimiter;
136 1291 : Word32 attack_cnst_fx = 0;
137 1291 : move32();
138 1291 : test();
139 1291 : IF( max_num_channels <= 0 || sampling_rate <= 0 )
140 : {
141 0 : return ( IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Wrong parameters for Limiter\n" ) );
142 : }
143 :
144 1291 : IF( ( hLimiter = malloc( sizeof( IVAS_LIMITER ) ) ) == NULL )
145 : {
146 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) );
147 : }
148 :
149 1291 : hLimiter->max_num_channels = max_num_channels;
150 1291 : move16();
151 1291 : hLimiter->num_channels = max_num_channels;
152 1291 : move16();
153 :
154 1291 : IF( ( hLimiter->channel_ptrs_fx = malloc( max_num_channels * sizeof( Word32 * ) ) ) == NULL )
155 : {
156 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) );
157 : }
158 1291 : hLimiter->sampling_rate = sampling_rate;
159 1291 : move32();
160 1291 : hLimiter->gain_fx = ONE_IN_Q30;
161 1291 : move32();
162 1291 : hLimiter->release_heuristic_fx = 0; /* Q30 */
163 1291 : move32();
164 1291 : SWITCH( sampling_rate )
165 : {
166 1049 : case 48000:
167 1049 : attack_cnst_fx = ATTACK_CNST_48k; /*Q31*/
168 1049 : move32();
169 1049 : BREAK;
170 163 : case 32000:
171 163 : attack_cnst_fx = ATTACK_CNST_32k; /*Q31*/
172 163 : move32();
173 163 : BREAK;
174 79 : case 16000:
175 79 : attack_cnst_fx = ATTACK_CNST_16k; /*Q31*/
176 79 : move32();
177 79 : BREAK;
178 0 : case 8000:
179 0 : attack_cnst_fx = ATTACK_CNST_8k; /*Q31*/
180 0 : move32();
181 0 : BREAK;
182 0 : default:
183 0 : assert( 0 );
184 : }
185 :
186 1291 : hLimiter->attack_constant_fx = attack_cnst_fx; /* Q31 */
187 1291 : move32();
188 1291 : hLimiter->strong_saturation_count = 0;
189 1291 : move16();
190 :
191 7558 : FOR( i = 0; i < max_num_channels; ++i )
192 : {
193 6267 : hLimiter->channel_ptrs_fx[i] = NULL;
194 : }
195 :
196 1291 : *hLimiter_out = hLimiter;
197 :
198 1291 : return IVAS_ERR_OK;
199 : }
200 :
201 :
202 : /*-------------------------------------------------------------------*
203 : * ivas_limiter_close()
204 : *
205 : * Deallocate limiter struct
206 : *-------------------------------------------------------------------*/
207 :
208 1301 : void ivas_limiter_close_fx(
209 : IVAS_LIMITER_HANDLE *phLimiter /* i/o: pointer to limiter handle, can be NULL */
210 : )
211 : {
212 1301 : test();
213 1301 : IF( phLimiter == NULL || *phLimiter == NULL )
214 : {
215 10 : return;
216 : }
217 :
218 1291 : free( ( *phLimiter )->channel_ptrs_fx );
219 1291 : free( *phLimiter );
220 1291 : *phLimiter = NULL;
221 :
222 1291 : return;
223 : }
224 :
225 :
226 : /*-------------------------------------------------------------------*
227 : * ivas_limiter_dec()
228 : *
229 : * In-place saturation control for multichannel buffers with adaptive
230 : * release time and special handling of bit errors
231 : *-------------------------------------------------------------------*/
232 :
233 408970 : void ivas_limiter_dec_fx(
234 : IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */
235 : Word32 *output[MAX_OUTPUT_CHANNELS], /* i/o: input/output buffer Q : q_factor */
236 : const Word16 num_channels, /* i : number of channels to be processed */
237 : const Word16 output_frame, /* i : number of samples per channel in the buffer */
238 : const Word16 BER_detect, /* i : BER detect flag */
239 : Word16 q_factor /* i : Q factor of the output samples */
240 : )
241 : {
242 : Word16 c;
243 : Word32 **channels;
244 :
245 : /* return early if given bad parameters */
246 408970 : test();
247 408970 : test();
248 408970 : IF( hLimiter == NULL || output == NULL || output_frame <= 0 )
249 : {
250 79 : return;
251 : }
252 :
253 : /* Update number of channels and prepare pointers to the beginning of each of them */
254 408891 : assert( num_channels <= hLimiter->max_num_channels && "Number of channels must be lower than the maximum set during limiter initialization!" );
255 408891 : hLimiter->num_channels = s_min( num_channels, hLimiter->max_num_channels );
256 408891 : move16();
257 408891 : channels = hLimiter->channel_ptrs_fx;
258 :
259 1872978 : FOR( c = 0; c < num_channels; ++c )
260 : {
261 1464087 : channels[c] = output[c]; /*q_factor*/
262 : }
263 408891 : Word32 limiter_thresold = L_shl( IVAS_LIMITER_THRESHOLD, q_factor ); /*q_factor*/
264 408891 : limiter_process_fx( hLimiter, output_frame, limiter_thresold, BER_detect, &hLimiter->strong_saturation_count, q_factor );
265 :
266 408891 : return;
267 : }
268 :
269 :
270 : /*-------------------------------------------------------------------*
271 : * limiter_process()
272 : *
273 : * hLimiter->channel_ptrs must be set before calling this function.
274 : * Consider using a wrapper function like ivas_limiter_dec() instead
275 : * of calling this directly.
276 : *-------------------------------------------------------------------*/
277 :
278 1523031 : void limiter_process_fx(
279 : IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */
280 : const Word16 output_frame, /* i : number of samples to be processed per channel in the I/O buffer */
281 : const Word32 threshold, /* i : signal amplitude above which limiting starts to be applied Q : q_factor */
282 : const Word16 BER_detect, /* i : BER detect flag */
283 : Word16 *strong_saturation_cnt, /* i/o: counter of strong saturations (can be NULL) */
284 : Word16 q_factor /* i : Q factor of output samples */
285 : )
286 : {
287 : Word16 i, c;
288 : Word32 tmp, max_val;
289 : Word32 *sample;
290 : Word32 releaseHeuristic, releaseHeuristic_cnst, releaseHeuristic_cnst_2;
291 : Word16 apply_limiting, apply_strong_limiting;
292 : Word32 **output;
293 : Word16 num_channels, scale, result;
294 : Word32 release_constant, compare_value;
295 : Word32 div32, gain, frame_gain, attack_constant;
296 : Word16 idx;
297 :
298 : /* return early if given nonsensical values */
299 1523031 : test();
300 1523031 : IF( hLimiter == NULL || output_frame <= 0 )
301 : {
302 0 : return;
303 : }
304 :
305 1523031 : apply_limiting = 1;
306 1523031 : move16();
307 1523031 : apply_strong_limiting = 0;
308 1523031 : move16();
309 :
310 1523031 : gain = hLimiter->gain_fx; /* Q30 */
311 1523031 : move32();
312 1523031 : output = hLimiter->channel_ptrs_fx;
313 1523031 : num_channels = hLimiter->num_channels;
314 1523031 : move16();
315 : // sampling_rate = hLimiter->sampling_rate;
316 1523031 : attack_constant = hLimiter->attack_constant_fx; /* Q31 */
317 1523031 : move32();
318 : /*-----------------------------------------------------------------*
319 : * Find highest absolute peak sample value
320 : *-----------------------------------------------------------------*/
321 :
322 1523031 : max_val = 0;
323 1523031 : move32();
324 :
325 764248151 : FOR( i = 0; i < output_frame; i++ )
326 : {
327 4600555840 : FOR( c = 0; c < num_channels; c++ )
328 : {
329 3837830720 : tmp = L_abs( output[c][i] );
330 3837830720 : if ( GT_32( tmp, max_val ) )
331 : {
332 34617395 : max_val = tmp; /*q_factor*/
333 34617395 : move32();
334 : }
335 : }
336 : }
337 :
338 : /* Release heuristic
339 : *
340 : * Value ranging from 0.f to 1.f. Increases on each frame that contains
341 : * a sample with a value above threshold and decreases on each frame
342 : * with all sample values below threshold.
343 : *
344 : * Values of 0 and 1 map to the shortest and longest release time, respectively.
345 : *
346 : * The goal of this heuristic is to avoid the "pumping" effect when only
347 : * sharp transients exceed the threshold (use short release time), but also
348 : * keep the gain curve smoother if the threshold is exceeded in many frames
349 : * in a short span of time.
350 : */
351 1523031 : SWITCH( output_frame )
352 : {
353 639364 : case 960:
354 : case 640:
355 : case 320:
356 : case 160:
357 639364 : releaseHeuristic_cnst = 85899345; /*Q30*/
358 639364 : move32();
359 639364 : releaseHeuristic_cnst_2 = 21474836; /*Q30*/
360 639364 : move32();
361 639364 : BREAK;
362 883667 : default:
363 883667 : releaseHeuristic_cnst = 21474836; /*Q30*/
364 883667 : move32();
365 883667 : releaseHeuristic_cnst_2 = 5368709; /*Q30*/
366 883667 : move32();
367 883667 : BREAK;
368 : }
369 1523031 : releaseHeuristic = hLimiter->release_heuristic_fx; /* Q30 */
370 1523031 : move32();
371 :
372 1523031 : IF( GT_32( max_val, threshold ) )
373 : {
374 8671 : frame_gain = L_shl( divide3232( threshold, max_val ), 15 ); // to Q30
375 8671 : releaseHeuristic = L_min( ONE_IN_Q30, L_add( releaseHeuristic, releaseHeuristic_cnst ) ); // releaseHeuristic_cnst is Q30 of ( 4.f * output_frame / sampling_rate )
376 : // release_constant = powf( 0.01f, 1.0f / ( 0.005f * powf( 200.f, .08 ) * sampling_rate ) );
377 : /* Unoptimized code for reference */
378 : /* releaseHeuristic = min( 1.f, releaseHeuristic + ( (float) 2.f * output_frame / sampling_rate / adaptiveReleaseWindowLengthInSeconds ) );
379 : * ^
380 : * React faster when release time should be increased
381 : */
382 : }
383 : ELSE
384 : {
385 1514360 : releaseHeuristic = L_max( 0, L_sub( releaseHeuristic, releaseHeuristic_cnst_2 ) ); // releaseHeuristic_cnst_2 is Q30 of output_frame / sampling_rate )
386 : /* Unoptimized code for reference */
387 : /*releaseHeuristic = max( 0.f, releaseHeuristic - ( (float) 0.5f * output_frame / sampling_rate / adaptiveReleaseWindowLengthInSeconds ) );
388 : * ^
389 : * React slower when release time should be decreased
390 : */
391 : /* No samples above threshold and gain from previous frame is already 1.f,
392 : * therefore gain == 1.f for the entire frame. Skip processing. */
393 1514360 : if ( GE_32( gain, ONE_IN_Q30 ) )
394 : {
395 1331541 : apply_limiting = 0;
396 1331541 : move16();
397 : }
398 : /* No samples above threshold but gain from previous frame is not 1.f,
399 : * transition to gain == 1.f */
400 1514360 : frame_gain = ONE_IN_Q30;
401 1514360 : move32();
402 : }
403 : /* Detection of very strong saturations */
404 1523031 : IF( strong_saturation_cnt != NULL )
405 : {
406 408891 : apply_strong_limiting = detect_strong_saturations_fx( BER_detect, strong_saturation_cnt, max_val, &frame_gain, q_factor );
407 : }
408 1523031 : compare_value = 107374182; // Q30 of 0.1f
409 1523031 : move32();
410 : /* Limit gain reduction to 20dB. Any peaks that require gain reduction
411 : * higher than this are most likely due to bit errors during decoding */
412 1523031 : test();
413 1523031 : if ( LT_32( frame_gain, compare_value ) && !apply_strong_limiting )
414 : {
415 0 : frame_gain = compare_value; /*Q30*/
416 0 : move32();
417 : }
418 :
419 1523031 : IF( apply_limiting )
420 : {
421 : /* 99% time constants of the gain curve
422 : *
423 : * The denominator of the second argument determines after how many
424 : * samples the gain curve will reach 99% of its target value
425 : */
426 191490 : div32 = 5368709; // Q30 of 0.005 which is the lowest values for (output_frame / sampling_rate)
427 191490 : move32();
428 :
429 191490 : result = BASOP_Util_Divide3232_Scale( releaseHeuristic, div32, &scale );
430 191490 : idx = extract_l( Mpy_32_32( hLimiter->sampling_rate, 134218 ) );
431 191490 : result = shr( result, sub( 15, scale ) );
432 191490 : release_constant = release_cnst_table[idx][result]; /* Q31 */
433 191490 : move32();
434 : /* Unoptimized code for reference */
435 : /* releaseTimeInSeconds = 0.005f * powf(200.f, releaseHeuristic); <-- Map heuristic value (0; 1) exponentially to range (0.005; 1)
436 : * release_constant = powf( 0.01f, 1.0f / ( releaseTimeInSeconds * sampling_rate ) );
437 : */
438 :
439 : /*-----------------------------------------------------------------*
440 : * Apply limiting
441 : *-----------------------------------------------------------------*/
442 :
443 91334230 : FOR( i = 0; i < output_frame; i++ )
444 : {
445 : /* Update gain */
446 91142740 : IF( LT_32( frame_gain, gain ) )
447 : {
448 1785600 : gain = Madd_32_32( frame_gain, attack_constant, L_sub( gain, frame_gain ) ); /* Q30 */
449 : }
450 : ELSE
451 : {
452 89357140 : gain = Madd_32_32( frame_gain, release_constant, L_sub( gain, frame_gain ) ); /* Q30 */
453 : }
454 :
455 418615460 : FOR( c = 0; c < num_channels; c++ )
456 : {
457 327472720 : sample = &output[c][i];
458 :
459 : /* Apply gain */
460 327472720 : *sample = Mpy_32_32( L_shl_sat( *sample, 1 ), gain ); /* Q(q_factor) */
461 327472720 : move32();
462 : }
463 : }
464 : }
465 :
466 : /* Save last gain and release heuristic values for next frame */
467 1523031 : hLimiter->gain_fx = gain; /* Q30 */
468 1523031 : move32();
469 1523031 : hLimiter->release_heuristic_fx = releaseHeuristic; /* Q30 */
470 1523031 : move32();
471 :
472 1523031 : return;
473 : }
|