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 -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 118 121 97.5 %
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 "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 alpha */
      49             : #define DOWNMIX_ONE_MINUS_ALPHA_FX 1638  /* Smoothing coefficient (1 - alpha) */
      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        2455 : void ivas_mono_dmx_renderer_close(
      89             :     MONO_DOWNMIX_RENDERER_HANDLE *hMonoDmxRenderer /* i/ i/o: Mono downmix structure */
      90             : )
      91             : {
      92        2455 :     test();
      93        2455 :     IF( hMonoDmxRenderer == NULL || *hMonoDmxRenderer == NULL )
      94             :     {
      95        2408 :         return;
      96             :     }
      97             : 
      98          47 :     free( *hMonoDmxRenderer );
      99          47 :     *hMonoDmxRenderer = NULL;
     100             : 
     101          47 :     return;
     102             : }
     103             : 
     104             : /*-------------------------------------------------------------------------
     105             :  * ivas_ism_mono_dmx()
     106             :  *
     107             :  * Downmix process
     108             :  *------------------------------------------------------------------------*/
     109        5945 : void ivas_ism_mono_dmx_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             : 
     124        5945 :     numInputChannels = st_ivas->nSCE;
     125        5945 :     move16();
     126        5945 :     if ( EQ_32( st_ivas->ivas_format, SBA_ISM_FORMAT ) )
     127             :     {
     128        1000 :         numInputChannels = st_ivas->nchan_ism;
     129        1000 :         move16();
     130             :     }
     131             : 
     132        5945 :     IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) )
     133             :     {
     134         975 :         test();
     135         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 ) )
     136             :         {
     137         595 :             numInputChannels = add( st_ivas->nchan_transport, 1 );
     138             :         }
     139             :         ELSE
     140             :         {
     141         380 :             numInputChannels = add( st_ivas->nchan_transport, st_ivas->nchan_ism );
     142             :         }
     143             :     }
     144             : 
     145        5945 :     hDownmix = st_ivas->hMonoDmxRenderer;
     146        5945 :     set32_fx( proto_signal_fx, 0, output_frame );
     147             : 
     148        5945 :     Word16 Output_norm = 32;
     149        5945 :     move16();
     150       18100 :     FOR( Word16 lp = 0; lp < numInputChannels; lp++ )
     151             :     {
     152       12155 :         Word16 norm = L_norm_arr( output_f_fx[lp], output_frame );
     153       12155 :         Output_norm = s_min( Output_norm, norm );
     154             :     }
     155        5945 :     Q_shift = sub( Output_norm, find_guarded_bits_fx( numInputChannels ) );
     156             : 
     157             :     /* Compute the Proto Signal */
     158       18100 :     FOR( i = 0; i < numInputChannels; i++ )
     159             :     {
     160       12155 :         v_shr_32( output_f_fx[i], output_shr, output_frame, -Q_shift );
     161       12155 :         v_add_32( output_shr, proto_signal_fx, proto_signal_fx, output_frame );
     162             :     }
     163             : 
     164             : 
     165        5945 :     proto_norm = L_norm_arr( proto_signal_fx, output_frame );
     166             : 
     167        5945 :     proto_shift = sub( proto_norm, shr( ( add( find_guarded_bits_fx( output_frame ), 1 ) ), 1 ) );
     168        5945 :     input_shift = sub( Output_norm, shr( ( add( find_guarded_bits_fx( i_mult( output_frame, numInputChannels ) ), 1 ) ), 1 ) );
     169        5945 :     protoEner_pre = 0;
     170        5945 :     move32();
     171        5945 :     inputEner_pre = 0;
     172        5945 :     move32();
     173     4762745 :     FOR( i = 0; i < output_frame; i++ )
     174             :     {
     175     4756800 :         Word32 proto_sh = L_shl( proto_signal_fx[i], proto_shift );
     176     4756800 :         protoEner_pre = L_add( protoEner_pre, Mpy_32_32( proto_sh, proto_sh ) );
     177    14195200 :         FOR( j = 0; j < numInputChannels; j++ )
     178             :         {
     179     9438400 :             Word32 output_f_shift = L_shl( output_f_fx[j][i], input_shift );
     180     9438400 :             inputEner_pre = L_add( inputEner_pre, Mpy_32_32( output_f_shift, output_f_shift ) );
     181             :         }
     182             :     }
     183             : 
     184        5945 :     hDownmix->inputEnergy_fx = Mpy_32_16_1( hDownmix->inputEnergy_fx, DOWNMIX_ALPHA_FX );
     185        5945 :     move32();
     186        5945 :     hDownmix->protoEnergy_fx = Mpy_32_16_1( hDownmix->protoEnergy_fx, DOWNMIX_ALPHA_FX );
     187        5945 :     move32();
     188             : 
     189        5945 :     protoEner_pre = Mpy_32_16_1( protoEner_pre, DOWNMIX_ONE_MINUS_ALPHA_FX );
     190        5945 :     inputEner_pre = Mpy_32_16_1( inputEner_pre, DOWNMIX_ONE_MINUS_ALPHA_FX );
     191             : 
     192             :     /* compute the eq factor */
     193             : 
     194        5945 :     IF( hDownmix->protoEnergy_fx == 0 )
     195             :     {
     196          47 :         norm_protoEner = add( 31, hDownmix->Q_protoEner );
     197             :     }
     198             :     ELSE
     199             :     {
     200        5898 :         norm_protoEner = add( norm_l( hDownmix->protoEnergy_fx ), hDownmix->Q_protoEner );
     201             :     }
     202        5945 :     IF( hDownmix->inputEnergy_fx == 0 )
     203             :     {
     204          47 :         norm_inputEner = add( 31, hDownmix->Q_inputEner );
     205             :     }
     206             :     ELSE
     207             :     {
     208        5898 :         norm_inputEner = add( norm_l( hDownmix->inputEnergy_fx ), hDownmix->Q_inputEner );
     209             :     }
     210             : 
     211        5945 :     norm_protoEner = sub( s_min( norm_protoEner, sub( shl( add( add( 11, Q_shift ), proto_shift ), 1 ), 31 ) ), 1 );
     212        5945 :     norm_inputEner = sub( s_min( norm_inputEner, sub( shl( add( 11, input_shift ), 1 ), 31 ) ), 1 );
     213             : 
     214        5945 :     hDownmix->protoEnergy_fx = L_shl( hDownmix->protoEnergy_fx, sub( norm_protoEner, hDownmix->Q_protoEner ) );
     215        5945 :     move32();
     216        5945 :     hDownmix->inputEnergy_fx = L_shl( hDownmix->inputEnergy_fx, sub( norm_inputEner, hDownmix->Q_inputEner ) );
     217        5945 :     move32();
     218             : 
     219        5945 :     hDownmix->Q_protoEner = norm_protoEner;
     220        5945 :     move16();
     221        5945 :     hDownmix->Q_inputEner = norm_inputEner;
     222        5945 :     move16();
     223             : 
     224        5945 :     protoEner_pre = L_shl( protoEner_pre, sub( norm_protoEner, sub( shl( add( add( 11, Q_shift ), proto_shift ), 1 ), 31 ) ) );
     225        5945 :     inputEner_pre = L_shl( inputEner_pre, sub( norm_inputEner, sub( shl( add( 11, input_shift ), 1 ), 31 ) ) );
     226             : 
     227        5945 :     hDownmix->protoEnergy_fx = L_add( hDownmix->protoEnergy_fx, protoEner_pre );
     228        5945 :     move32();
     229        5945 :     hDownmix->inputEnergy_fx = L_add( hDownmix->inputEnergy_fx, inputEner_pre );
     230        5945 :     move32();
     231             : 
     232        5945 :     diff_shift = sub( hDownmix->Q_inputEner, hDownmix->Q_protoEner );
     233        5945 :     IF( diff_shift > 0 )
     234             :     {
     235         298 :         hDownmix->inputEnergy_fx = L_shr( hDownmix->inputEnergy_fx, diff_shift );
     236         298 :         move32();
     237         298 :         hDownmix->Q_inputEner = sub( hDownmix->Q_inputEner, diff_shift );
     238         298 :         move16();
     239             :     }
     240             :     ELSE
     241             :     {
     242        5647 :         hDownmix->protoEnergy_fx = L_shr( hDownmix->protoEnergy_fx, -diff_shift );
     243        5647 :         move32();
     244        5647 :         hDownmix->Q_protoEner = add( hDownmix->Q_protoEner, diff_shift );
     245        5647 :         move16();
     246             :     }
     247        5945 :     IF( GE_32( hDownmix->protoEnergy_fx, L_shr( hDownmix->inputEnergy_fx, 2 ) ) )
     248             :     {
     249        5945 :         div = BASOP_Util_Divide3232_Scale( hDownmix->inputEnergy_fx, hDownmix->protoEnergy_fx, &diff_shift );
     250        5945 :         div_sqrt = Sqrt16( div, &diff_shift );
     251        5945 :         eq_fx = shr( div_sqrt, sub( 3, diff_shift ) );
     252             :     }
     253             :     ELSE
     254             :     {
     255           0 :         eq_fx = 16384; // 0.5.Q15
     256           0 :         move16();
     257             :     }
     258             : 
     259             : 
     260             :     /* equalize the downmix */
     261        5945 :     v_multc_fixed_16( proto_signal_fx, eq_fx, output_f_fx[0], output_frame );
     262        5945 :     v_shr_32( output_f_fx[0], output_f_fx[0], output_frame, Q_shift );
     263             : 
     264        5945 :     return;
     265             : }
     266             : 
     267             : /*-------------------------------------------------------------------------
     268             :  * ivas_mono_stereo_downmix_mcmasa()
     269             :  *
     270             :  * Downmix process in McMASA
     271             :  *------------------------------------------------------------------------*/
     272             : 
     273         500 : void ivas_mono_stereo_downmix_mcmasa_fx(
     274             :     Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure                                          */
     275             :     Word32 *output_f_fx[],   /* i/o: synthesized core-coder transport channels/mono or stereo output Q11*/
     276             :     Word16 output_frame      /* i  : output frame length per channel                                 */
     277             : )
     278             : {
     279             :     Word16 i;
     280             : 
     281             :     Word32 dmx_tmp_fx[L_FRAME48k];
     282             : 
     283         500 :     set32_fx( dmx_tmp_fx, 0, output_frame );
     284             : 
     285             :     /* Dowmix center channel to L and R */
     286         500 :     test();
     287         500 :     IF( EQ_16( st_ivas->hDecoderConfig->nchan_out, 2 ) && st_ivas->hOutSetup.separateChannelEnabled )
     288             :     {
     289         200 :         v_multc_acc_32_16( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], INV_SQRT2_FX_Q15, output_f_fx[0], output_frame ); // Q11
     290         200 :         v_multc_acc_32_16( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], INV_SQRT2_FX_Q15, output_f_fx[1], output_frame ); // Q11
     291             :     }
     292             :     /* Mono downmix */
     293         300 :     ELSE IF( EQ_16( st_ivas->hDecoderConfig->nchan_out, 1 ) )
     294             :     {
     295             :         /* Downmix L and R to dmx_tmp */
     296         900 :         FOR( i = 0; i < st_ivas->nchan_transport; i++ )
     297             :         {
     298         600 :             v_multc_acc_32_16( output_f_fx[i], INV_SQRT2_FX_Q15, dmx_tmp_fx, output_frame ); // Q11
     299             :         }
     300             :         /* Add center channel */
     301         300 :         IF( st_ivas->hOutSetup.separateChannelEnabled )
     302             :         {
     303         150 :             v_add_32( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], dmx_tmp_fx, dmx_tmp_fx, output_frame );
     304             :         }
     305             : 
     306             :         /* Move to output */
     307         300 :         Copy32( dmx_tmp_fx, output_f_fx[0], output_frame ); // Q11
     308             :     }
     309             : 
     310         500 :     return;
     311             : }
     312             : 
     313             : 
     314             : /*-------------------------------------------------------------------------
     315             :  * ivas_apply_non_diegetic_panning()
     316             :  *
     317             :  * Apply non-diegetic panning
     318             :  *------------------------------------------------------------------------*/
     319             : 
     320        1500 : void ivas_apply_non_diegetic_panning_fx(
     321             :     Word32 *input_f_fx,                    /* i  : non-diegetic object                                 */
     322             :     Word32 *output_f_fx[],                 /* o: core-coder transport mono channel/stereo output       */
     323             :     const Word16 non_diegetic_pan_gain_fx, /* i  : non-diegetic panning gain                        Q15*/
     324             :     const Word16 output_frame              /* i  : output frame length per channel                  Q11*/
     325             : )
     326             : {
     327             :     Word16 pan_left_fx, pan_right_fx;
     328             : 
     329        1500 :     pan_left_fx = add( mult( non_diegetic_pan_gain_fx, 16384 ), 16384 ); // 0.5.Q15 = 16384
     330        1500 :     pan_right_fx = sub( 32767, pan_left_fx );
     331             : 
     332        1500 :     v_multc_fixed( input_f_fx, L_shl( L_deposit_l( pan_right_fx ), 16 ), output_f_fx[1], output_frame );
     333        1500 :     v_multc_fixed( input_f_fx, L_shl( L_deposit_l( pan_left_fx ), 16 ), output_f_fx[0], output_frame );
     334             : 
     335        1500 :     return;
     336             : }

Generated by: LCOV version 1.14