LCOV - code coverage report
Current view: top level - lib_com - ivas_limiter.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 78 93 83.9 %
Date: 2025-05-23 08:37:30 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.h"
      37             : #include "ivas_prot.h"
      38             : #include "wmc_auto.h"
      39             : #include <assert.h>
      40             : 
      41             : 
      42             : /*-------------------------------------------------------------------*
      43             :  * detect_strong_saturations()
      44             :  *
      45             :  * Detection of very strong saturations,
      46             :  * usually happens as a consequence of a heavy corrupted bitstream
      47             :  *-------------------------------------------------------------------*/
      48             : 
      49             : /*! r: apply_strong_limiting flag */
      50     2859836 : static int16_t detect_strong_saturations(
      51             :     const int16_t BER_detect,       /* i  : BER detect flag                 */
      52             :     int16_t *strong_saturation_cnt, /* i/o: counter of strong saturations   */
      53             :     const float max_val,            /* i  : maximum absolute value          */
      54             :     float *frame_gain               /* i/o: frame gain value                */
      55             : )
      56             : {
      57             :     int16_t apply_strong_limiting;
      58             : 
      59     2859836 :     apply_strong_limiting = 0;
      60             : 
      61     2859836 :     if ( BER_detect )
      62             :     {
      63           0 :         *strong_saturation_cnt = 50;
      64           0 :         apply_strong_limiting = 1;
      65             :     }
      66     2859836 :     else if ( max_val > 3 * IVAS_LIMITER_THRESHOLD && *strong_saturation_cnt > 0 )
      67             :     {
      68           0 :         apply_strong_limiting = 1;
      69             :     }
      70     2859836 :     else if ( max_val > 10 * IVAS_LIMITER_THRESHOLD )
      71             :     {
      72           0 :         *strong_saturation_cnt += 20;
      73           0 :         *strong_saturation_cnt = min( *strong_saturation_cnt, 50 );
      74           0 :         apply_strong_limiting = 1;
      75             :     }
      76             :     else
      77             :     {
      78     2859836 :         ( *strong_saturation_cnt )--;
      79     2859836 :         *strong_saturation_cnt = max( *strong_saturation_cnt, 0 );
      80             :     }
      81             : 
      82     2859836 :     if ( apply_strong_limiting )
      83             :     {
      84           0 :         if ( *frame_gain < 0.3f )
      85             :         {
      86           0 :             *frame_gain /= 3.0f;
      87             :         }
      88             :         else
      89             :         {
      90           0 :             apply_strong_limiting = 0;
      91             :         }
      92             :     }
      93             : 
      94     2859836 :     return apply_strong_limiting;
      95             : }
      96             : 
      97             : /*-------------------------------------------------------------------*
      98             :  * ivas_limiter_open()
      99             :  *
     100             :  * Allocate and initialize limiter struct
     101             :  *-------------------------------------------------------------------*/
     102             : 
     103             : /*! r : limiter struct handle */
     104        3275 : ivas_error ivas_limiter_open(
     105             :     IVAS_LIMITER_HANDLE *hLimiter_out, /* o  : limiter struct handle                           */
     106             :     const int16_t max_num_channels,    /* i  : maximum number of I/O channels to be processed  */
     107             :     const int32_t sampling_rate        /* i  : sampling rate for processing                    */
     108             : )
     109             : {
     110             :     int16_t i;
     111             :     IVAS_LIMITER_HANDLE hLimiter;
     112             : 
     113        3275 :     if ( max_num_channels <= 0 || sampling_rate <= 0 )
     114             :     {
     115           0 :         return ( IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Wrong parameters for Limiter\n" ) );
     116             :     }
     117             : 
     118        3275 :     if ( ( hLimiter = malloc( sizeof( IVAS_LIMITER ) ) ) == NULL )
     119             :     {
     120           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) );
     121             :     }
     122             : 
     123        3275 :     hLimiter->max_num_channels = max_num_channels;
     124        3275 :     hLimiter->num_channels = max_num_channels;
     125             : 
     126        3275 :     if ( ( hLimiter->channel_ptrs = malloc( max_num_channels * sizeof( float * ) ) ) == NULL )
     127             :     {
     128           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) );
     129             :     }
     130        3275 :     hLimiter->sampling_rate = sampling_rate;
     131        3275 :     hLimiter->gain = 1.f;
     132        3275 :     hLimiter->release_heuristic = 0.f;
     133        3275 :     hLimiter->attack_constant = powf( 0.01f, 1.0f / ( IVAS_LIMITER_ATTACK_SECONDS * sampling_rate ) );
     134        3275 :     hLimiter->strong_saturation_count = 0;
     135             : #ifdef DEBUGGING
     136             :     hLimiter->cnt_frames_limited = 0;
     137             : #endif
     138             : 
     139       18465 :     for ( i = 0; i < max_num_channels; ++i )
     140             :     {
     141       15190 :         hLimiter->channel_ptrs[i] = NULL;
     142             :     }
     143             : 
     144        3275 :     *hLimiter_out = hLimiter;
     145             : 
     146        3275 :     return IVAS_ERR_OK;
     147             : }
     148             : 
     149             : 
     150             : /*-------------------------------------------------------------------*
     151             :  * ivas_limiter_close()
     152             :  *
     153             :  * Deallocate limiter struct
     154             :  *-------------------------------------------------------------------*/
     155             : 
     156        3275 : void ivas_limiter_close(
     157             :     IVAS_LIMITER_HANDLE *phLimiter /* i/o: pointer to limiter handle, can be NULL  */
     158             : )
     159             : {
     160        3275 :     if ( phLimiter == NULL || *phLimiter == NULL )
     161             :     {
     162           0 :         return;
     163             :     }
     164             : 
     165        3275 :     free( ( *phLimiter )->channel_ptrs );
     166        3275 :     free( *phLimiter );
     167        3275 :     *phLimiter = NULL;
     168             : 
     169        3275 :     return;
     170             : }
     171             : 
     172             : 
     173             : /*-------------------------------------------------------------------*
     174             :  * ivas_limiter_dec()
     175             :  *
     176             :  * In-place saturation control for multichannel buffers with adaptive
     177             :  * release time and special handling of bit errors
     178             :  *-------------------------------------------------------------------*/
     179             : 
     180     2860112 : void ivas_limiter_dec(
     181             :     IVAS_LIMITER_HANDLE hLimiter,       /* i/o: limiter struct handle                                           */
     182             :     float *output[MAX_OUTPUT_CHANNELS], /* i/o: input/output buffer                                             */
     183             :     const int16_t num_channels,         /* i  : number of channels to be processed                              */
     184             :     const int16_t output_frame,         /* i  : number of samples per channel in the buffer                     */
     185             :     const int16_t BER_detect            /* i  : BER detect flag                                                 */
     186             : )
     187             : {
     188             :     int16_t c;
     189             :     float **channels;
     190             : 
     191             :     /* return early if given bad parameters */
     192     2860112 :     if ( hLimiter == NULL || output == NULL || output_frame <= 0 )
     193             :     {
     194         276 :         return;
     195             :     }
     196             : 
     197             :     /* Update number of channels and prepare pointers to the beginning of each of them */
     198     2859836 :     assert( num_channels <= hLimiter->max_num_channels && "Number of channels must be lower than the maximum set during limiter initialization!" );
     199     2859836 :     hLimiter->num_channels = min( num_channels, hLimiter->max_num_channels );
     200     2859836 :     channels = hLimiter->channel_ptrs;
     201             : 
     202    12969398 :     for ( c = 0; c < num_channels; ++c )
     203             :     {
     204    10109562 :         channels[c] = output[c];
     205             :     }
     206             : 
     207     2859836 :     limiter_process( hLimiter, output_frame, IVAS_LIMITER_THRESHOLD, BER_detect, &hLimiter->strong_saturation_count );
     208             : 
     209     2859836 :     return;
     210             : }
     211             : 
     212             : 
     213             : /*-------------------------------------------------------------------*
     214             :  * limiter_process()
     215             :  *
     216             :  * hLimiter->channel_ptrs must be set before calling this function.
     217             :  * Consider using a wrapper function like ivas_limiter_dec() instead
     218             :  * of calling this directly.
     219             :  *-------------------------------------------------------------------*/
     220             : 
     221     5088116 : void limiter_process(
     222             :     IVAS_LIMITER_HANDLE hLimiter,  /* i/o: limiter struct handle                                              */
     223             :     const int16_t output_frame,    /* i  : number of samples to be processed per channel in the I/O buffer    */
     224             :     const float threshold,         /* i  : signal amplitude above which limiting starts to be applied         */
     225             :     const int16_t BER_detect,      /* i  : BER detect flag                                                    */
     226             :     int16_t *strong_saturation_cnt /* i/o: counter of strong saturations (can be NULL)                        */
     227             : )
     228             : {
     229             :     int16_t i, c;
     230             :     float tmp, max_val;
     231             :     float *sample;
     232             :     float gain, frame_gain, attack_constant, release_constant;
     233             :     float releaseHeuristic;
     234             :     int16_t apply_limiting, apply_strong_limiting;
     235             :     float **output;
     236             :     int16_t num_channels;
     237             :     int32_t sampling_rate;
     238             : 
     239             :     /* return early if given nonsensical values */
     240     5088116 :     if ( hLimiter == NULL || output_frame <= 0 )
     241             :     {
     242           0 :         return;
     243             :     }
     244             : 
     245     5088116 :     apply_limiting = 1;
     246     5088116 :     apply_strong_limiting = 0;
     247             : 
     248     5088116 :     gain = hLimiter->gain;
     249     5088116 :     output = hLimiter->channel_ptrs;
     250     5088116 :     num_channels = hLimiter->num_channels;
     251     5088116 :     sampling_rate = hLimiter->sampling_rate;
     252     5088116 :     attack_constant = hLimiter->attack_constant;
     253             : 
     254             :     /*-----------------------------------------------------------------*
     255             :      * Find highest absolute peak sample value
     256             :      *-----------------------------------------------------------------*/
     257             : 
     258     5088116 :     max_val = 0.f;
     259             : 
     260  1913816036 :     for ( i = 0; i < output_frame; i++ )
     261             :     {
     262 11012803020 :         for ( c = 0; c < num_channels; c++ )
     263             :         {
     264  9104075100 :             tmp = fabsf( output[c][i] );
     265  9104075100 :             if ( tmp > max_val )
     266             :             {
     267   107926335 :                 max_val = tmp;
     268             :             }
     269             :         }
     270             :     }
     271             : 
     272             :     /* Release heuristic
     273             :      *
     274             :      * Value ranging from 0.f to 1.f. Increases on each frame that contains
     275             :      * a sample with a value above threshold and decreases on each frame
     276             :      * with all sample values below threshold.
     277             :      *
     278             :      * Values of 0 and 1 map to the shortest and longest release time, respectively.
     279             :      *
     280             :      * The goal of this heuristic is to avoid the "pumping" effect when only
     281             :      * sharp transients exceed the threshold (use short release time), but also
     282             :      * keep the gain curve smoother if the threshold is exceeded in many frames
     283             :      * in a short span of time.
     284             :      */
     285     5088116 :     releaseHeuristic = hLimiter->release_heuristic;
     286             : 
     287     5088116 :     if ( max_val > threshold )
     288             :     {
     289       33335 :         frame_gain = threshold / max_val;
     290             : 
     291       33335 :         releaseHeuristic = min( 1.f, releaseHeuristic + ( 4.f * output_frame / sampling_rate ) );
     292             :         /* Unoptimized code for reference */
     293             :         /* releaseHeuristic = min( 1.f, releaseHeuristic + ( (float) 2.f * output_frame / sampling_rate / adaptiveReleaseWindowLengthInSeconds ) );
     294             :          *                                                            ^
     295             :          *                                                          React faster when release time should be increased
     296             :          */
     297             : #ifdef DEBUGGING
     298             :         if ( max_val > threshold )
     299             :         {
     300             :             hLimiter->cnt_frames_limited++;
     301             :         }
     302             : #endif
     303             :     }
     304             :     else
     305             :     {
     306     5054781 :         releaseHeuristic = max( 0.f, releaseHeuristic - ( (float) output_frame / sampling_rate ) );
     307             :         /* Unoptimized code for reference */
     308             :         /* releaseHeuristic = max( 0.f, releaseHeuristic - ( (float) 0.5f * output_frame / sampling_rate / adaptiveReleaseWindowLengthInSeconds ) );
     309             :          *                                                            ^
     310             :          *                                                          React slower when release time should be decreased
     311             :          */
     312             : 
     313             :         /* No samples above threshold and gain from previous frame is already 1.f,
     314             :          * therefore gain == 1.f for the entire frame. Skip processing. */
     315     5054781 :         if ( gain >= 1.f - EPSILON )
     316             :         {
     317     4434262 :             apply_limiting = 0;
     318             :         }
     319             : 
     320             :         /* No samples above threshold but gain from previous frame is not 1.f,
     321             :          * transition to gain == 1.f */
     322     5054781 :         frame_gain = 1.f;
     323             :     }
     324             : 
     325             :     /* Detection of very strong saturations */
     326     5088116 :     if ( strong_saturation_cnt != NULL )
     327             :     {
     328     2859836 :         apply_strong_limiting = detect_strong_saturations( BER_detect, strong_saturation_cnt, max_val, &frame_gain );
     329             :     }
     330             : 
     331             :     /* Limit gain reduction to 20dB. Any peaks that require gain reduction
     332             :      * higher than this are most likely due to bit errors during decoding */
     333     5088116 :     if ( frame_gain < 0.1f && !apply_strong_limiting )
     334             :     {
     335           0 :         frame_gain = 0.1f;
     336             :     }
     337             : 
     338     5088116 :     if ( apply_limiting )
     339             :     {
     340             : 
     341             :         /* 99% time constants of the gain curve
     342             :          *
     343             :          * The denominator of the second argument determines after how many
     344             :          * samples the gain curve will reach 99% of its target value
     345             :          */
     346      653854 :         release_constant = powf( 0.01f, 1.0f / ( 0.005f * powf( 200.f, releaseHeuristic ) * sampling_rate ) );
     347             : 
     348             :         /* Unoptimized code for reference */
     349             :         /* releaseTimeInSeconds = 0.005f * powf(200.f, releaseHeuristic); <-- Map heuristic value (0; 1) exponentially to range (0.005; 1)
     350             :          * release_constant = powf( 0.01f, 1.0f / ( releaseTimeInSeconds * sampling_rate ) );
     351             :          */
     352             : 
     353             :         /*-----------------------------------------------------------------*
     354             :          * Apply limiting
     355             :          *-----------------------------------------------------------------*/
     356             : 
     357   242378974 :         for ( i = 0; i < output_frame; i++ )
     358             :         {
     359             :             /* Update gain */
     360   241725120 :             if ( frame_gain < gain )
     361             :             {
     362     4579520 :                 gain = attack_constant * ( gain - frame_gain ) + frame_gain;
     363             :             }
     364             :             else
     365             :             {
     366   237145600 :                 gain = release_constant * ( gain - frame_gain ) + frame_gain;
     367             :             }
     368             : 
     369  1074511000 :             for ( c = 0; c < num_channels; c++ )
     370             :             {
     371   832785880 :                 sample = &output[c][i];
     372             : 
     373             :                 /* Apply gain */
     374   832785880 :                 *sample = gain * ( *sample );
     375             :             }
     376             :         }
     377             :     }
     378             : 
     379             :     /* Save last gain and release heuristic values for next frame */
     380     5088116 :     hLimiter->gain = gain;
     381     5088116 :     hLimiter->release_heuristic = releaseHeuristic;
     382             : 
     383     5088116 :     return;
     384             : }

Generated by: LCOV version 1.14