LCOV - code coverage report
Current view: top level - lib_com - ivas_limiter_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 146 176 83.0 %
Date: 2025-08-23 01:22:27 Functions: 5 5 100.0 %

          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             : }

Generated by: LCOV version 1.14