LCOV - code coverage report
Current view: top level - lib_dec - ivas_mono_dmx_renderer_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 116 119 97.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 "cnst.h"
      37             : #include "prot_fx.h"
      38             : #include "ivas_prot_fx.h"
      39             : #include "ivas_cnst.h"
      40             : #include "ivas_rom_com.h"
      41             : #include "ivas_rom_dec.h"
      42             : #include "wmc_auto.h"
      43             : 
      44             : 
      45             : /*-------------------------------------------------------------------------
      46             :  * Local constants
      47             :  *------------------------------------------------------------------------*/
      48             : #define DOWNMIX_ALPHA_FX                      31130 /* Smoothing coefficient */
      49             : #define MONO_DOWNMIX_RENDERER_MAX_INPUT_CHANS 4
      50             : 
      51             : /*-------------------------------------------------------------------------
      52             :  * ivas_mono_dmx_renderer_open()
      53             :  *
      54             :  * Open decoder downmix handle
      55             :  *-------------------------------------------------------------------------*/
      56             : 
      57          47 : ivas_error ivas_mono_dmx_renderer_open(
      58             :     Decoder_Struct *st_ivas /* i/o: IVAS decoder structure  */
      59             : )
      60             : {
      61             :     MONO_DOWNMIX_RENDERER_HANDLE hDownmix;
      62             : 
      63          47 :     IF( ( hDownmix = (MONO_DOWNMIX_RENDERER_HANDLE) malloc( sizeof( MONO_DOWNMIX_RENDERER_STRUCT ) ) ) == NULL )
      64             :     {
      65           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for downmixing\n" ) );
      66             :     }
      67             : 
      68          47 :     hDownmix->inputEnergy_fx = 0;
      69          47 :     move16();
      70          47 :     hDownmix->protoEnergy_fx = 0;
      71          47 :     move16();
      72          47 :     hDownmix->Q_inputEner = 0;
      73          47 :     move16();
      74          47 :     hDownmix->Q_protoEner = 0;
      75          47 :     move16();
      76             : 
      77          47 :     st_ivas->hMonoDmxRenderer = hDownmix;
      78             : 
      79          47 :     return IVAS_ERR_OK;
      80             : }
      81             : 
      82             : /*-------------------------------------------------------------------------
      83             :  * ivas_mono_dmx_renderer_close()
      84             :  *
      85             :  * Close decoder downmix handle
      86             :  *-------------------------------------------------------------------------*/
      87             : 
      88        2209 : void ivas_mono_dmx_renderer_close(
      89             :     MONO_DOWNMIX_RENDERER_HANDLE *hMonoDmxRenderer /* i/ i/o: Mono downmix structure */
      90             : )
      91             : {
      92        2209 :     test();
      93        2209 :     IF( hMonoDmxRenderer == NULL || *hMonoDmxRenderer == NULL )
      94             :     {
      95        2162 :         return;
      96             :     }
      97             : 
      98          47 :     free( *hMonoDmxRenderer );
      99          47 :     *hMonoDmxRenderer = NULL;
     100             : 
     101          47 :     return;
     102             : }
     103             : 
     104             : /*-------------------------------------------------------------------------
     105             :  * ivas_mono_downmix_render_passive()
     106             :  *
     107             :  * Downmix process
     108             :  *------------------------------------------------------------------------*/
     109        5945 : void ivas_mono_downmix_render_passive_fx(
     110             :     Decoder_Struct *st_ivas,  /* i/o: IVAS decoder structure                                */
     111             :     Word32 *output_f_fx[],    /* i/o: synthesized core-coder transport channels/mono output Qin = 11/ Qout = 8*/
     112             :     const Word16 output_frame /* i  : output frame length                                   */
     113             : )
     114             : {
     115             :     Word16 i, j, numInputChannels;
     116             :     Word32 proto_signal_fx[L_FRAME48k];
     117             :     Word16 eq_fx;
     118             :     Word32 output_shr[L_FRAME48k];
     119             :     MONO_DOWNMIX_RENDERER_HANDLE hDownmix;
     120             :     Word16 Q_shift, proto_shift, input_shift, norm_protoEner, norm_inputEner, proto_norm;
     121             :     Word16 diff_shift, div, div_sqrt;
     122             :     Word32 protoEner_pre, inputEner_pre;
     123        5945 :     numInputChannels = st_ivas->nSCE;
     124        5945 :     move16();
     125        5945 :     if ( EQ_32( st_ivas->ivas_format, SBA_ISM_FORMAT ) )
     126             :     {
     127        1000 :         numInputChannels = st_ivas->nchan_ism;
     128        1000 :         move16();
     129             :     }
     130             : 
     131        5945 :     IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) )
     132             :     {
     133         975 :         test();
     134         975 :         IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) )
     135             :         {
     136         595 :             numInputChannels = add( st_ivas->nchan_transport, 1 );
     137             :         }
     138             :         ELSE
     139             :         {
     140         380 :             numInputChannels = add( st_ivas->nchan_transport, st_ivas->nchan_ism );
     141             :         }
     142             :     }
     143             : 
     144        5945 :     hDownmix = st_ivas->hMonoDmxRenderer;
     145        5945 :     set32_fx( proto_signal_fx, 0, output_frame );
     146             : 
     147        5945 :     Word16 Output_norm = 32;
     148        5945 :     move16();
     149       18100 :     FOR( Word16 lp = 0; lp < numInputChannels; lp++ )
     150             :     {
     151       12155 :         Word16 norm = L_norm_arr( output_f_fx[lp], output_frame );
     152       12155 :         Output_norm = s_min( Output_norm, norm );
     153             :     }
     154        5945 :     Q_shift = sub( Output_norm, find_guarded_bits_fx( numInputChannels ) );
     155             : 
     156             :     /* Compute the Proto Signal */
     157       18100 :     FOR( i = 0; i < numInputChannels; i++ )
     158             :     {
     159       12155 :         v_shr_32( output_f_fx[i], output_shr, output_frame, -Q_shift );
     160       12155 :         v_add_32( output_shr, proto_signal_fx, proto_signal_fx, output_frame );
     161             :     }
     162             : 
     163             :     /* compute the input energy, proto energy after smoothing */
     164        5945 :     hDownmix->inputEnergy_fx = Mpy_32_16_1( hDownmix->inputEnergy_fx, DOWNMIX_ALPHA_FX );
     165        5945 :     move32();
     166        5945 :     hDownmix->protoEnergy_fx = Mpy_32_16_1( hDownmix->protoEnergy_fx, DOWNMIX_ALPHA_FX );
     167        5945 :     move32();
     168             : 
     169        5945 :     proto_norm = L_norm_arr( proto_signal_fx, output_frame );
     170             : 
     171        5945 :     proto_shift = sub( proto_norm, shr( ( add( find_guarded_bits_fx( output_frame ), 1 ) ), 1 ) );
     172        5945 :     input_shift = sub( Output_norm, shr( ( add( find_guarded_bits_fx( i_mult( output_frame, numInputChannels ) ), 1 ) ), 1 ) );
     173        5945 :     protoEner_pre = 0;
     174        5945 :     move32();
     175        5945 :     inputEner_pre = 0;
     176        5945 :     move32();
     177     4762745 :     FOR( i = 0; i < output_frame; i++ )
     178             :     {
     179     4756800 :         Word32 proto_sh = L_shl( proto_signal_fx[i], proto_shift );
     180     4756800 :         protoEner_pre = L_add( protoEner_pre, Mpy_32_32( proto_sh, proto_sh ) );
     181    14195200 :         FOR( j = 0; j < numInputChannels; j++ )
     182             :         {
     183     9438400 :             Word32 output_f_shift = L_shl( output_f_fx[j][i], input_shift );
     184     9438400 :             inputEner_pre = L_add( inputEner_pre, Mpy_32_32( output_f_shift, output_f_shift ) );
     185             :         }
     186             :     }
     187             : 
     188             :     /* compute the eq factor */
     189             : 
     190        5945 :     IF( hDownmix->protoEnergy_fx == 0 )
     191             :     {
     192          47 :         norm_protoEner = add( 31, hDownmix->Q_protoEner );
     193             :     }
     194             :     ELSE
     195             :     {
     196        5898 :         norm_protoEner = add( norm_l( hDownmix->protoEnergy_fx ), hDownmix->Q_protoEner );
     197             :     }
     198        5945 :     IF( hDownmix->inputEnergy_fx == 0 )
     199             :     {
     200          47 :         norm_inputEner = add( 31, hDownmix->Q_inputEner );
     201             :     }
     202             :     ELSE
     203             :     {
     204        5898 :         norm_inputEner = add( norm_l( hDownmix->inputEnergy_fx ), hDownmix->Q_inputEner );
     205             :     }
     206             : 
     207        5945 :     norm_protoEner = sub( s_min( norm_protoEner, sub( shl( add( add( 11, Q_shift ), proto_shift ), 1 ), 31 ) ), 1 );
     208        5945 :     norm_inputEner = sub( s_min( norm_inputEner, sub( shl( add( 11, input_shift ), 1 ), 31 ) ), 1 );
     209             : 
     210        5945 :     hDownmix->protoEnergy_fx = L_shl( hDownmix->protoEnergy_fx, sub( norm_protoEner, hDownmix->Q_protoEner ) );
     211        5945 :     move32();
     212        5945 :     hDownmix->inputEnergy_fx = L_shl( hDownmix->inputEnergy_fx, sub( norm_inputEner, hDownmix->Q_inputEner ) );
     213        5945 :     move32();
     214             : 
     215        5945 :     hDownmix->Q_protoEner = norm_protoEner;
     216        5945 :     move16();
     217        5945 :     hDownmix->Q_inputEner = norm_inputEner;
     218        5945 :     move16();
     219             : 
     220        5945 :     protoEner_pre = L_shl( protoEner_pre, sub( norm_protoEner, sub( shl( add( add( 11, Q_shift ), proto_shift ), 1 ), 31 ) ) );
     221        5945 :     inputEner_pre = L_shl( inputEner_pre, sub( norm_inputEner, sub( shl( add( 11, input_shift ), 1 ), 31 ) ) );
     222             : 
     223        5945 :     hDownmix->protoEnergy_fx = L_add( hDownmix->protoEnergy_fx, protoEner_pre );
     224        5945 :     move32();
     225        5945 :     hDownmix->inputEnergy_fx = L_add( hDownmix->inputEnergy_fx, inputEner_pre );
     226        5945 :     move32();
     227             : 
     228        5945 :     diff_shift = sub( hDownmix->Q_inputEner, hDownmix->Q_protoEner );
     229        5945 :     IF( diff_shift > 0 )
     230             :     {
     231         730 :         hDownmix->inputEnergy_fx = L_shr( hDownmix->inputEnergy_fx, diff_shift );
     232         730 :         move32();
     233         730 :         hDownmix->Q_inputEner = sub( hDownmix->Q_inputEner, diff_shift );
     234         730 :         move16();
     235             :     }
     236             :     ELSE
     237             :     {
     238        5215 :         hDownmix->protoEnergy_fx = L_shr( hDownmix->protoEnergy_fx, -diff_shift );
     239        5215 :         move32();
     240        5215 :         hDownmix->Q_protoEner = add( hDownmix->Q_protoEner, diff_shift );
     241        5215 :         move16();
     242             :     }
     243        5945 :     IF( GE_32( hDownmix->protoEnergy_fx, L_shr( hDownmix->inputEnergy_fx, 2 ) ) )
     244             :     {
     245        5945 :         div = BASOP_Util_Divide3232_Scale( hDownmix->inputEnergy_fx, hDownmix->protoEnergy_fx, &diff_shift );
     246        5945 :         div_sqrt = Sqrt16( div, &diff_shift );
     247        5945 :         eq_fx = shr( div_sqrt, sub( 3, diff_shift ) );
     248             :     }
     249             :     ELSE
     250             :     {
     251           0 :         eq_fx = 16384; // 0.5.Q15
     252           0 :         move16();
     253             :     }
     254             : 
     255             : 
     256             :     /* equalize the downmix */
     257        5945 :     v_multc_fixed_16( proto_signal_fx, eq_fx, output_f_fx[0], output_frame );
     258        5945 :     v_shr_32( output_f_fx[0], output_f_fx[0], output_frame, Q_shift );
     259             : 
     260        5945 :     return;
     261             : }
     262             : 
     263             : /*-------------------------------------------------------------------------
     264             :  * ivas_mono_stereo_downmix_mcmasa()
     265             :  *
     266             :  * Downmix process in McMASA
     267             :  *------------------------------------------------------------------------*/
     268             : 
     269         500 : void ivas_mono_stereo_downmix_mcmasa_fx(
     270             :     Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure                                          */
     271             :     Word32 *output_f_fx[],   /* i/o: synthesized core-coder transport channels/mono or stereo output Q11*/
     272             :     Word16 output_frame      /* i  : output frame length per channel                                 */
     273             : )
     274             : {
     275             :     Word16 i;
     276             : 
     277             :     Word32 dmx_tmp_fx[L_FRAME48k];
     278             : 
     279         500 :     set32_fx( dmx_tmp_fx, 0, output_frame );
     280             : 
     281             :     /* Dowmix center channel to L and R */
     282         500 :     test();
     283         500 :     IF( EQ_16( st_ivas->hDecoderConfig->nchan_out, 2 ) && st_ivas->hOutSetup.separateChannelEnabled )
     284             :     {
     285         200 :         v_multc_acc_32_16( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], INV_SQRT2_FX_Q15, output_f_fx[0], output_frame ); // Q11
     286         200 :         v_multc_acc_32_16( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], INV_SQRT2_FX_Q15, output_f_fx[1], output_frame ); // Q11
     287             :     }
     288             :     /* Mono downmix */
     289         300 :     ELSE IF( EQ_16( st_ivas->hDecoderConfig->nchan_out, 1 ) )
     290             :     {
     291             :         /* Downmix L and R to dmx_tmp */
     292         900 :         FOR( i = 0; i < st_ivas->nchan_transport; i++ )
     293             :         {
     294         600 :             v_multc_acc_32_16( output_f_fx[i], INV_SQRT2_FX_Q15, dmx_tmp_fx, output_frame ); // Q11
     295             :         }
     296             :         /* Add center channel */
     297         300 :         IF( st_ivas->hOutSetup.separateChannelEnabled )
     298             :         {
     299         150 :             v_add_32( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], dmx_tmp_fx, dmx_tmp_fx, output_frame );
     300             :         }
     301             : 
     302             :         /* Move to output */
     303         300 :         Copy32( dmx_tmp_fx, output_f_fx[0], output_frame ); // Q11
     304             :     }
     305             : 
     306         500 :     return;
     307             : }
     308             : 
     309             : 
     310             : /*-------------------------------------------------------------------------
     311             :  * ivas_apply_non_diegetic_panning()
     312             :  *
     313             :  * Apply non-diegetic panning
     314             :  *------------------------------------------------------------------------*/
     315             : 
     316        1500 : void ivas_apply_non_diegetic_panning_fx(
     317             :     Word32 *output_f_fx[],                 /* i/o: core-coder transport mono channel/stereo output  */
     318             :     const Word16 non_diegetic_pan_gain_fx, /* i  : non-diegetic panning gain                        Q15*/
     319             :     const Word16 output_frame              /* i  : output frame length per channel                  Q11*/
     320             : )
     321             : {
     322             :     Word16 pan_left_fx, pan_right_fx;
     323             : 
     324        1500 :     pan_left_fx = add( mult( non_diegetic_pan_gain_fx, 16384 ), 16384 ); // 0.5.Q15 = 16384
     325        1500 :     pan_right_fx = sub( 32767, pan_left_fx );
     326             : 
     327        1500 :     v_multc_fixed( output_f_fx[0], L_shl( L_deposit_l( pan_right_fx ), 16 ), output_f_fx[1], output_frame );
     328        1500 :     v_multc_fixed( output_f_fx[0], L_shl( L_deposit_l( pan_left_fx ), 16 ), output_f_fx[0], output_frame );
     329             : 
     330        1500 :     return;
     331             : }

Generated by: LCOV version 1.14