LCOV - code coverage report
Current view: top level - lib_rend - ivas_limiter_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 147 176 83.5 %
Date: 2025-05-03 01:55:50 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 "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             : }

Generated by: LCOV version 1.14