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