From de3dba049b1244379b2cb9a2f7f9660bed3e209c Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Wed, 6 Mar 2024 13:53:06 +0530 Subject: [PATCH] renderInputMC functions converted to fixed point. [x]Converted renderMcToBinaural, renderMcToBinauralRoom, renderMcToBinaural,renderMcToMc, renderMcToSba functions and its associated functions. --- lib_com/ivas_cnst.h | 1 + lib_rend/ivas_objectRenderer.c | 110 +- lib_rend/ivas_prot_rend.h | 14 + lib_rend/ivas_rom_rend.c | 8 +- lib_rend/ivas_stat_rend.h | 2 +- lib_rend/lib_rend.c | 1794 +++++++++++++++++++++++++------- lib_rend/lib_rend.h | 4 + 7 files changed, 1567 insertions(+), 366 deletions(-) diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index 3aa2073c5..6e0f00159 100644 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -1544,6 +1544,7 @@ typedef enum #define HRTF_NUM_BINS 60 #define REVERB_PREDELAY_MAX 20 /* Max input delay for reverb module */ #define GAIN_LFE 1.88364911f /* Gain applied to LFE during renderering */ +#define GAIN_LFE_WORD32 2022552831 /* Gain applied to LFE during renderering */ #ifdef IVAS_FLOAT_FIXED #define GAIN_LFE_FX 30862 /* Gain applied to LFE during renderering */ #endif // IVAS_FLOAT_FIXED diff --git a/lib_rend/ivas_objectRenderer.c b/lib_rend/ivas_objectRenderer.c index 29e012b18..44c58a9e8 100644 --- a/lib_rend/ivas_objectRenderer.c +++ b/lib_rend/ivas_objectRenderer.c @@ -943,7 +943,114 @@ ivas_error ivas_td_binaural_open_ext( return ivas_td_binaural_open_unwrap( &pTDRend->hHrtfTD, outFs, nchan_transport, ivas_format, transport_config, directivity, hTransSetup, &pTDRend->hBinRendererTd, &pTDRend->binaural_latency_ns ); } +#ifdef IVAS_FLOAT_FIXED +/*---------------------------------------------------------------------* + * ivas_td_binaural_renderer_ext() + * + * Receives the current frames for the object streams, updates metadata + * and renders the current frame. + *---------------------------------------------------------------------*/ + +ivas_error ivas_td_binaural_renderer_ext_fx( + const TDREND_WRAPPER *pTDRend, /* i : TD Renderer wrapper structure */ + const AUDIO_CONFIG inConfig, /* i : Input audio configuration */ + const LSSETUP_CUSTOM_STRUCT *customLsInput, /* i : Input custom loudspeaker layout */ + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */ + const IVAS_ISM_METADATA *currentPos, /* i : Object position */ + const REVERB_HANDLE hReverb, /* i : Reverberator handle */ + const Word16 ism_md_subframe_update_ext, /* i : Metadata Delay in subframes to sync with audio delay */ + const Word32 output_Fs, /* i : output sampling rate */ + const Word16 output_frame, /* i : output frame length */ + Word32 output[][L_FRAME48k], /* i/o: SCE channels / Binaural synthesis */ + Word16 exp +) +{ + ISM_METADATA_FRAME hIsmMetaDataFrame; + ISM_METADATA_HANDLE hIsmMetaData[1]; + Word16 lfe_idx; + Word16 num_src; + IVAS_FORMAT ivas_format; + IVAS_REND_AudioConfigType inConfigType; + AUDIO_CONFIG transport_config; + ivas_error error; + float *p_output[MAX_OUTPUT_CHANNELS]; + float output_fl[MAX_OUTPUT_CHANNELS][L_FRAME48k]; + Word16 ch,j; + /*This intermediate conversion will be removed once the subfunctions are also converted to fixed*/ + for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ ) + { + for ( j = 0; j < L_FRAME48k ;j++) + { + output_fl[ch][j] = (float)output[ch][j]/(1<num_lfe > 0 ) ? customLsInput->lfe_idx[0] : -1; + num_src = add(customLsInput->num_spk , customLsInput->num_lfe); + } + } + ELSE + { + ivas_format = ISM_FORMAT; + num_src = 1; + transport_config = IVAS_AUDIO_CONFIG_ISM1; + hIsmMetaData[0] = &hIsmMetaDataFrame; + hIsmMetaData[0]->azimuth = currentPos->azimuth; + hIsmMetaData[0]->elevation = currentPos->elevation; + hIsmMetaData[0]->yaw = currentPos->yaw; + hIsmMetaData[0]->pitch = currentPos->pitch; + hIsmMetaData[0]->radius = currentPos->radius; + hIsmMetaData[0]->non_diegetic_flag = currentPos->non_diegetic_flag; + } + + IF ( ( error = ivas_td_binaural_renderer_unwrap( hReverb, transport_config, pTDRend->hBinRendererTd, num_src, lfe_idx, ivas_format, hIsmMetaData, *hCombinedOrientationData, + ism_md_subframe_update_ext, p_output, output_frame, (int16_t) ( ( output_frame * FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) / output_Fs ) ) ) != IVAS_ERR_OK ) + { + return error; + } + IF ( hReverb != NULL) + { + exp = sub(exp , 2); + } + /*This intermediate conversion will be removed once the subfunctions are also converted to fixed*/ + for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ ) + { + for ( j = 0; j < L_FRAME48k; j++ ) + { + output[ch][j] = (Word32) output_fl[ch][j] *( 1 << (exp)) ; + } + } + pop_wmops(); + + return IVAS_ERR_OK; +} + +#endif /*---------------------------------------------------------------------* * ivas_td_binaural_renderer_ext() * @@ -974,7 +1081,6 @@ ivas_error ivas_td_binaural_renderer_ext( ivas_error error; float *p_output[MAX_OUTPUT_CHANNELS]; int16_t ch; - for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ ) { p_output[ch] = output[ch]; @@ -1030,8 +1136,6 @@ ivas_error ivas_td_binaural_renderer_ext( } - - /*---------------------------------------------------------------------* * angles_to_vec() * diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index 12ebdcf25..022c3279f 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -867,6 +867,20 @@ ivas_error ivas_td_binaural_renderer_ext( float output[][L_FRAME48k] /* i/o: SCE channels / Binaural synthesis */ ); #ifdef IVAS_FLOAT_FIXED +ivas_error ivas_td_binaural_renderer_ext_fx( + const TDREND_WRAPPER *pTDRend, /* i : TD Renderer wrapper structure */ + const AUDIO_CONFIG inConfig, /* i : Input audio configuration */ + const LSSETUP_CUSTOM_STRUCT *customLsInput, /* i : Input custom loudspeaker layout */ + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData,/* i : Combined head and external orientations */ + const IVAS_ISM_METADATA *currentPos, /* i : Object position */ + const REVERB_HANDLE hReverb, /* i : Reverberator handle */ + const Word16 ism_md_subframe_update_ext, /* i : Metadata Delay in subframes to sync with audio delay */ + const Word32 output_Fs, /* i : output sampling rate */ + const Word16 output_frame, /* i : output frame length */ + Word32 output[][L_FRAME48k], /* i/o: SCE channels / Binaural synthesis */ + Word16 exp +); + ivas_error ivas_td_binaural_open_unwrap_fx( TDREND_HRFILT_FiltSet_t **hHrtfTD, /* i/o: HR filter model (from file or NULL) */ const Word32 output_Fs, /* i : Output sampling rate */ diff --git a/lib_rend/ivas_rom_rend.c b/lib_rend/ivas_rom_rend.c index 2efffa270..a5272c3aa 100644 --- a/lib_rend/ivas_rom_rend.c +++ b/lib_rend/ivas_rom_rend.c @@ -893,10 +893,10 @@ const Word32 ls_conversion_cicpX_stereo_fx[12][2] = // Q30 {0, 858993408}, {858993408, 0}, {0, 858993408}, - {858993408, 0}, - {0, 858993408}, - {858993408, 0}, - {0, 858993408} + {912680512, 0}, + {0, 912680512}, + {912680512, 0}, + {0, 912680512} }; const LS_CONVERSION_MATRIX_FX ls_conversion_cicp12_cicp6_fx[] = // Q30 diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index a623f93b2..09c3fa45b 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -1936,7 +1936,7 @@ typedef struct ivas_LS_setupconversion_struct #ifdef IVAS_FLOAT_FIXED typedef struct ivas_LS_setupconversion_matrix_fx { - int16_t index; + Word16 index; Word32 value; } LS_CONVERSION_MATRIX_FX; diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 18af1b3c0..f0ab84417 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -79,6 +79,7 @@ typedef float pan_vector[MAX_OUTPUT_CHANNELS]; typedef float pan_matrix[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS]; typedef float rotation_gains[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS]; #ifdef IVAS_FLOAT_FIXED +typedef Word32 pan_vector_fx[MAX_OUTPUT_CHANNELS]; typedef Word32 pan_matrix_fx[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS]; typedef Word16 rotation_gains_fx[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS]; typedef Word32 rotation_gains_Word32[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS]; @@ -145,6 +146,26 @@ typedef struct int32_t numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */ } input_base; #endif +#ifdef IVAS_FLOAT_FIXED +typedef struct +{ + input_base base; + IVAS_ISM_METADATA currentPos; + IVAS_ISM_METADATA previousPos; + TDREND_WRAPPER tdRendWrapper; + CREND_WRAPPER_HANDLE crendWrapper; + REVERB_HANDLE hReverb; + rotation_matrix rot_mat_prev; + pan_vector prev_pan_gains; + int8_t firstFrameRendered; + float *bufferData; + Word16 nonDiegeticPan; + float nonDiegeticPanGain; + OMASA_ANA_HANDLE hOMasa; + uint16_t total_num_objects; + float ism_metadata_delay_ms; +} input_ism; +#else typedef struct { input_base base; @@ -163,7 +184,22 @@ typedef struct uint16_t total_num_objects; float ism_metadata_delay_ms; } input_ism; - +#endif +#ifdef IVAS_FLOAT_FIXED +typedef struct +{ + Word16 numLfeChannels; + bool pan_lfe; + float lfeInputGain; + Word32 lfeInputGain_fx; + float lfeOutputAzimuth; + Word16 lfeOutputAzimuth_fx; + float lfeOutputElevation; + Word16 lfeOutputElevation_fx; + IVAS_REND_LfePanMtx lfePanMtx; + IVAS_REND_LfePanMtx_fx lfePanMtx_fx; +} lfe_routing; +#else typedef struct { int16_t numLfeChannels; @@ -173,6 +209,7 @@ typedef struct float lfeOutputElevation; IVAS_REND_LfePanMtx lfePanMtx; } lfe_routing; +#endif #ifdef IVAS_FLOAT_FIXED typedef struct { @@ -181,6 +218,7 @@ typedef struct /* Full panning matrix. 1st index is input channel, 2nd index is output channel. All LFE channels should be included, both for inputs and outputs */ pan_matrix panGains; + pan_matrix_fx panGains_fx; LSSETUP_CUSTOM_STRUCT customLsInput; EFAP_WRAPPER efapInWrapper; @@ -189,13 +227,15 @@ typedef struct REVERB_HANDLE hReverb; rotation_gains rot_gains_prev; rotation_gains_Word32 rot_gains_prev_fx; - int16_t nonDiegeticPan; + Word16 nonDiegeticPan; float nonDiegeticPanGain; + Word32 nonDiegeticPanGain_fx; lfe_routing lfeRouting; float *bufferData; Word32 *bufferData_fx; int16_t binauralDelaySmp; float *lfeDelayBuffer; + Word32 *lfeDelayBuffer_fx; MCMASA_ANA_HANDLE hMcMasa; } input_mc; #else @@ -372,7 +412,20 @@ static void freeInputBaseBufferData( return; } +#ifdef IVAS_FLOAT_FIXED +static ivas_error allocateMcLfeDelayBuffer_fx( + Word32 **lfeDelayBuffer, + const Word16 data_size ) +{ + *lfeDelayBuffer = (Word32 *) malloc( data_size * sizeof( Word32 ) ); + if ( *lfeDelayBuffer == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for LFE delay buffer" ); + } + return IVAS_ERR_OK; +} +#endif static ivas_error allocateMcLfeDelayBuffer( float **lfeDelayBuffer, const int16_t data_size ) @@ -385,7 +438,20 @@ static ivas_error allocateMcLfeDelayBuffer( return IVAS_ERR_OK; } +#ifdef IVAS_FLOAT_FIXED +static void freeMcLfeDelayBuffer_fx( + Word32 **lfeDelayBuffer ) +{ + IF( *lfeDelayBuffer != NULL ) + { + free( *lfeDelayBuffer ); + *lfeDelayBuffer = NULL; + } + + return; +} +#endif static void freeMcLfeDelayBuffer( float **lfeDelayBuffer ) { @@ -997,7 +1063,7 @@ static ivas_error initLimiter( return IVAS_ERR_OK; } #endif - +#ifdef IVAS_FLOAT_FIXED static LSSETUP_CUSTOM_STRUCT defaultCustomLs( void ) { @@ -1008,7 +1074,9 @@ static LSSETUP_CUSTOM_STRUCT defaultCustomLs( ls.is_planar_setup = 1; ls.num_spk = 1; set_zero( ls.ls_azimuth, MAX_OUTPUT_CHANNELS ); + set_val_Word32( ls.ls_azimuth_fx, 0, MAX_OUTPUT_CHANNELS ); set_zero( ls.ls_elevation, MAX_OUTPUT_CHANNELS ); + set_val_Word32( ls.ls_elevation_fx, 0, MAX_OUTPUT_CHANNELS ); ls.num_lfe = 0; set_s( ls.lfe_idx, 0, MAX_OUTPUT_CHANNELS ); ls.separate_ch_found = 0; @@ -1016,7 +1084,26 @@ static LSSETUP_CUSTOM_STRUCT defaultCustomLs( return ls; } +#else +static LSSETUP_CUSTOM_STRUCT defaultCustomLs( + void ) +{ + LSSETUP_CUSTOM_STRUCT ls; + + /* Set mono by default. This simplifies initialization, + since output config is never in an undefined state. */ + ls.is_planar_setup = 1; + ls.num_spk = 1; + set_zero( ls.ls_azimuth, MAX_OUTPUT_CHANNELS ); + set_zero( ls.ls_elevation, MAX_OUTPUT_CHANNELS ); + ls.num_lfe = 0; + set_s( ls.lfe_idx, 0, MAX_OUTPUT_CHANNELS ); + ls.separate_ch_found = 0; + set_f( ls.separate_ch_gains, 0, MAX_OUTPUT_CHANNELS ); + return ls; +} +#endif #ifdef IVAS_FLOAT_FIXED static ivas_error getSpeakerAzimuths_fx( AUDIO_CONFIG config, @@ -1200,7 +1287,27 @@ static ivas_error getAmbisonicsOrder( return IVAS_ERR_OK; } +#ifdef IVAS_FLOAT_FIXED +static Word16 getNumLfeChannels( + input_mc *inputMc ) +{ + SWITCH( inputMc->base.inConfig ) + { + case IVAS_AUDIO_CONFIG_5_1: + case IVAS_AUDIO_CONFIG_7_1: + case IVAS_AUDIO_CONFIG_5_1_2: + case IVAS_AUDIO_CONFIG_5_1_4: + case IVAS_AUDIO_CONFIG_7_1_4: + return 1; + case IVAS_AUDIO_CONFIG_LS_CUSTOM: + return inputMc->customLsInput.num_lfe; + default: + BREAK; + } + return 0; +} +#else static int16_t getNumLfeChannels( input_mc *inputMc ) { @@ -1220,7 +1327,46 @@ static int16_t getNumLfeChannels( return 0; } +#endif +#ifdef IVAS_FLOAT_FIXED +static ivas_error getNumNonLfeChannelsInSpeakerLayout( + AUDIO_CONFIG config, + Word16 *numNonLfeChannels ) +{ + SWITCH( config ) + { + case IVAS_AUDIO_CONFIG_MONO: + *numNonLfeChannels = 1; + move16(); + BREAK; + case IVAS_AUDIO_CONFIG_STEREO: + *numNonLfeChannels = 2; + move16(); + BREAK; + case IVAS_AUDIO_CONFIG_5_1: + *numNonLfeChannels = 5; + move16(); + BREAK; + case IVAS_AUDIO_CONFIG_5_1_2: + case IVAS_AUDIO_CONFIG_7_1: + *numNonLfeChannels = 7; + move16(); + BREAK; + case IVAS_AUDIO_CONFIG_5_1_4: + *numNonLfeChannels = 9; + move16(); + BREAK; + case IVAS_AUDIO_CONFIG_7_1_4: + *numNonLfeChannels = 11; + move16(); + BREAK; + default: + return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" ); + } + return IVAS_ERR_OK; +} +#else static ivas_error getNumNonLfeChannelsInSpeakerLayout( AUDIO_CONFIG config, int16_t *numNonLfeChannels ) @@ -1252,6 +1398,7 @@ static ivas_error getNumNonLfeChannelsInSpeakerLayout( return IVAS_ERR_OK; } +#endif #ifdef IVAS_FLOAT_FIXED static ivas_error getMcConfigValues_fx( AUDIO_CONFIG inConfig, @@ -1452,7 +1599,76 @@ static ivas_error initEfap( return IVAS_ERR_OK; } +#ifdef IVAS_FLOAT_FIXED +static ivas_error getEfapGains_fx( + EFAP_WRAPPER efapWrapper, + const Word32 azi, + const Word32 ele, + pan_vector_fx panGains ) +{ + pan_vector_fx tmpPanGains; /* tmp pan gain buffer without LFE channels */ + Word32 *readPtr; + Word16 i; + Word16 lfeCount; + Word16 numChannels; + ivas_error error; + + /* EFAP returns an array of gains only for non-LFE speakers */ + efap_determine_gains_fixed( efapWrapper.hEfap, tmpPanGains, azi, ele, EFAP_MODE_EFAP ); + + /* Now copy to buffer that includes LFE channels */ + IF( EQ_32( efapWrapper.speakerConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) + { + numChannels = add( efapWrapper.pCustomLsSetup->num_spk, efapWrapper.pCustomLsSetup->num_lfe ); + move16(); + readPtr = tmpPanGains; + move16(); + lfeCount = 0; + FOR( i = 0; i < numChannels; ++i ) + { + IF( LT_16( lfeCount, efapWrapper.pCustomLsSetup->num_lfe ) && EQ_16( i, efapWrapper.pCustomLsSetup->lfe_idx[lfeCount] ) ) + { + panGains[i] = 0; + move32(); + ++lfeCount; + } + ELSE + { + panGains[i] = EQ_32( *readPtr, ONE_IN_Q30 ) ? ONE_IN_Q31 : L_shl( *readPtr, 1 ); // Q31 + move32(); + ++readPtr; + } + } + } + ELSE + { + IF( ( error = getAudioConfigNumChannels( efapWrapper.speakerConfig, &numChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + + readPtr = tmpPanGains; + move32(); + + FOR( i = 0; i < numChannels; ++i ) + { + IF( EQ_16( i, LFE_CHANNEL ) ) + { + panGains[i] = 0; + move32(); + } + ELSE + { + panGains[i] = GE_32( *readPtr, ONE_IN_Q30 ) ? ONE_IN_Q31 : L_shl( *readPtr, 1 ); // Q31 + move32(); + ++readPtr; + } + } + } + return IVAS_ERR_OK; +} +#endif static ivas_error getEfapGains( EFAP_WRAPPER efapWrapper, const float azi, @@ -1940,6 +2156,40 @@ static void clearInputIsm( return; } +#ifdef IVAS_FLOAT_FIXED +static void copyLsConversionMatrixToPanMatrix_fx( + const LS_CONVERSION_MATRIX_FX *lsConvMatrix, + pan_matrix_fx panMatrix ) +{ + Word16 i; + Word16 inCh, outCh; + Word16 numNonZeroGains; + Word16 numColumns; + Word16 tmp_e, tmp; + /* Index 0 is special and describes the following values */ + numNonZeroGains = lsConvMatrix[0].index; + move16(); + numColumns = (Word16) lsConvMatrix[0].value; + move16(); + + FOR( i = 1; i < numNonZeroGains + 1; ++i ) + { + tmp = BASOP_Util_Divide1616_Scale( lsConvMatrix[i].index, numColumns, &tmp_e ); + move16(); + tmp = shr( tmp, add( 15, negate( tmp_e ) ) ); + move16(); + inCh = tmp; + move16(); + // inCh = lsConvMatrix[i].index / numColumns; + outCh = lsConvMatrix[i].index % numColumns; + move16(); + panMatrix[inCh][outCh] = EQ_32( lsConvMatrix[i].value, ONE_IN_Q30 ) ? ONE_IN_Q31 : L_shl( lsConvMatrix[i].value, 1 ); // Q31 + move32(); + } + + return; +} +#endif static void copyLsConversionMatrixToPanMatrix( const LS_CONVERSION_MATRIX *lsConvMatrix, @@ -2020,7 +2270,15 @@ static void fillIdentityPanMatrix( return; } +#ifdef IVAS_FLOAT_FIXED +static ivas_error initMcPanGainsWithIdentMatrix( + input_mc *inputMc ) +{ + fillIdentityPanMatrix_fx( inputMc->panGains_fx ); + return IVAS_ERR_OK; +} +#else static ivas_error initMcPanGainsWithIdentMatrix( input_mc *inputMc ) { @@ -2029,6 +2287,42 @@ static ivas_error initMcPanGainsWithIdentMatrix( return IVAS_ERR_OK; } +#endif +#ifdef IVAS_FLOAT_FIXED +static ivas_error initMcPanGainsWithConversionMapping_fx( + input_mc *inputMc, + const AUDIO_CONFIG outConfig ) +{ + AUDIO_CONFIG ivasConfigIn, ivasConfigOut; + Word16 i; + + ivasConfigIn = inputMc->base.inConfig; + ivasConfigOut = outConfig; + + /* Find conversion mapping for current I/O config pair. + * Stay with default panning matrix if conversion_matrix is NULL */ + FOR( i = 0; i < LS_SETUP_CONVERSION_NUM_MAPPINGS; ++i ) + { + IF( EQ_32( ls_conversion_mapping_fx[i].input_config, ivasConfigIn ) && EQ_32( ls_conversion_mapping_fx[i].output_config, ivasConfigOut ) ) + { + /* Mapping found with valid matrix - copy */ + IF( ls_conversion_mapping_fx[i].conversion_matrix_fx != NULL ) + { + copyLsConversionMatrixToPanMatrix_fx( ls_conversion_mapping_fx[i].conversion_matrix_fx, inputMc->panGains_fx ); + } + /* Mapping found with NULL matrix - use identity matrix */ + ELSE + { + fillIdentityPanMatrix_fx( inputMc->panGains_fx ); + } + + return IVAS_ERR_OK; + } + } + + return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Missing multichannel conversion mapping" ); +} +#endif static ivas_error initMcPanGainsWithConversionMapping( input_mc *inputMc, @@ -2063,76 +2357,177 @@ static ivas_error initMcPanGainsWithConversionMapping( return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Missing multichannel conversion mapping" ); } - - -static ivas_error initMcPanGainsWithEfap( +#ifdef IVAS_FLOAT_FIXED +static ivas_error initMcPanGainsWithEfap_fx( input_mc *inputMc, const AUDIO_CONFIG outConfig ) { - int16_t i; - int16_t numNonLfeInChannels; - int16_t inLfeChIdx, outChIdx; - const float *spkAzi, *spkEle; + Word16 i; + Word16 numNonLfeInChannels; + Word16 inLfeChIdx, outChIdx; + const Word32 *spkAzi, *spkEle; ivas_error error; - if ( inputMc->base.inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM ) + IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) { - if ( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ) != IVAS_ERR_OK ) + IF( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ) != IVAS_ERR_OK ) { return error; } - if ( ( error = getSpeakerAzimuths( inputMc->base.inConfig, &spkAzi ) ) != IVAS_ERR_OK ) + IF( ( error = getSpeakerAzimuths_fx( inputMc->base.inConfig, &spkAzi ) ) != IVAS_ERR_OK ) { return error; } - if ( ( error = getSpeakerElevations( inputMc->base.inConfig, &spkEle ) ) != IVAS_ERR_OK ) + IF( ( error = getSpeakerElevations_fx( inputMc->base.inConfig, &spkEle ) ) != IVAS_ERR_OK ) { return error; } inLfeChIdx = LFE_CHANNEL; } - else + ELSE { numNonLfeInChannels = inputMc->customLsInput.num_spk; - spkAzi = inputMc->customLsInput.ls_azimuth; - spkEle = inputMc->customLsInput.ls_elevation; + move16(); + spkAzi = inputMc->customLsInput.ls_azimuth_fx; + move32(); + spkEle = inputMc->customLsInput.ls_elevation_fx; + move32(); inLfeChIdx = -1; - if ( inputMc->customLsInput.num_lfe > 0 ) + move16(); + IF( GT_16( inputMc->customLsInput.num_lfe, 0 ) ) { inLfeChIdx = inputMc->customLsInput.lfe_idx[0]; + move16(); } } - - for ( i = 0, outChIdx = 0; i < numNonLfeInChannels; ++i, ++outChIdx ) + outChIdx = 0; + FOR( i = 0; i < numNonLfeInChannels; ++i ) { - if ( i == inLfeChIdx ) + IF( EQ_16( i, inLfeChIdx ) ) { ++outChIdx; } - if ( ( error = getEfapGains( *inputMc->base.ctx.pEfapOutWrapper, spkAzi[i], spkEle[i], inputMc->panGains[outChIdx] ) ) != IVAS_ERR_OK ) + IF( ( error = getEfapGains_fx( *inputMc->base.ctx.pEfapOutWrapper, spkAzi[i], spkEle[i], inputMc->panGains_fx[outChIdx] ) ) != IVAS_ERR_OK ) { return error; } + ++outChIdx; } - if ( outConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inLfeChIdx >= 0 ) + IF( NE_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && GE_16( inLfeChIdx, 0 ) ) { - inputMc->panGains[inLfeChIdx][LFE_CHANNEL] = 1; + inputMc->panGains_fx[inLfeChIdx][LFE_CHANNEL] = ONE_IN_Q31; + move32(); } - else if ( inputMc->base.ctx.pCustomLsOut->num_lfe > 0 && inLfeChIdx >= 0 ) + ELSE IF( GT_16( inputMc->base.ctx.pCustomLsOut->num_lfe, 0 ) && GE_16( inLfeChIdx, 0 ) ) { - inputMc->panGains[inLfeChIdx][inputMc->base.ctx.pCustomLsOut->lfe_idx[0]] = 1; + inputMc->panGains_fx[inLfeChIdx][inputMc->base.ctx.pCustomLsOut->lfe_idx[0]] = ONE_IN_Q31; + move32(); } - return IVAS_ERR_OK; } - - -static ivas_error getRendInputNumChannels( +#endif +static ivas_error initMcPanGainsWithEfap( + input_mc *inputMc, + const AUDIO_CONFIG outConfig ) +{ + int16_t i; + int16_t numNonLfeInChannels; + int16_t inLfeChIdx, outChIdx; + const float *spkAzi, *spkEle; + ivas_error error; + + if ( inputMc->base.inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM ) + { + if ( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( ( error = getSpeakerAzimuths( inputMc->base.inConfig, &spkAzi ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( ( error = getSpeakerElevations( inputMc->base.inConfig, &spkEle ) ) != IVAS_ERR_OK ) + { + return error; + } + + inLfeChIdx = LFE_CHANNEL; + } + else + { + numNonLfeInChannels = inputMc->customLsInput.num_spk; + spkAzi = inputMc->customLsInput.ls_azimuth; + spkEle = inputMc->customLsInput.ls_elevation; + inLfeChIdx = -1; + if ( inputMc->customLsInput.num_lfe > 0 ) + { + inLfeChIdx = inputMc->customLsInput.lfe_idx[0]; + } + } + + for ( i = 0, outChIdx = 0; i < numNonLfeInChannels; ++i, ++outChIdx ) + { + if ( i == inLfeChIdx ) + { + ++outChIdx; + } + + if ( ( error = getEfapGains( *inputMc->base.ctx.pEfapOutWrapper, spkAzi[i], spkEle[i], inputMc->panGains[outChIdx] ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + if ( outConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inLfeChIdx >= 0 ) + { + inputMc->panGains[inLfeChIdx][LFE_CHANNEL] = 1; + } + else if ( inputMc->base.ctx.pCustomLsOut->num_lfe > 0 && inLfeChIdx >= 0 ) + { + inputMc->panGains[inLfeChIdx][inputMc->base.ctx.pCustomLsOut->lfe_idx[0]] = 1; + } + + return IVAS_ERR_OK; +} + +#ifdef IVAS_FLOAT_FIXED +static ivas_error getRendInputNumChannels( + const void *rendInput, + Word16 *numInChannels ) +{ + /* Using a void pointer for this function to be reusable for any input type (input_ism, input_mc, input_sba). + Assumptions: - input_base is always the first member in the input struct */ + + ivas_error error; + const input_base *pInputBase; + const input_mc *pInputMc; + + pInputBase = (const input_base *) rendInput; + + IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) + { + pInputMc = (const input_mc *) rendInput; + *numInChannels = add( pInputMc->customLsInput.num_spk, pInputMc->customLsInput.num_lfe ); + } + ELSE + { + IF( ( error = getAudioConfigNumChannels( pInputBase->inConfig, numInChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + return IVAS_ERR_OK; +} +#else +static ivas_error getRendInputNumChannels( const void *rendInput, int16_t *numInChannels ) { @@ -2160,7 +2555,70 @@ static ivas_error getRendInputNumChannels( return IVAS_ERR_OK; } +#endif +#ifdef IVAS_FLOAT_FIXED +static ivas_error initMcPanGainsWithMonoOut_fx( + input_mc *inputMc ) +{ + Word16 i; + Word16 numInChannels; + Word16 readIdx; + Word16 writeIdx; + bool skipSideSpeakers; + ivas_error error; + + IF( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + + IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) + { + FOR( i = 0; i < numInChannels; ++i ) + { + /* It's OK to also set gain 1 for LFE input channels here. + * Correct LFE handling will be applied within updateMcPanGains() */ + inputMc->panGains_fx[i][0] = ONE_IN_Q31; + move32(); + } + } + ELSE IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_STEREO ) ) + { + /* Special case for STEREO to MONO: Passive downmix (L+R)/2 */ + inputMc->panGains_fx[0][0] = ONE_IN_Q30; // Q31(of 0.5) + move32(); + inputMc->panGains_fx[1][0] = ONE_IN_Q30; // Q31(of 0.5) + move32(); + } + ELSE + { + /* ls_conversion_cicpX_stereo contains gains for side speakers. + * These should be skipped with 5.1+X inputs. */ + skipSideSpeakers = false; + IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_4 ) ) + { + skipSideSpeakers = true; + } + readIdx = 0; + move16(); + FOR( writeIdx = 0; writeIdx < numInChannels; ++writeIdx ) + { + IF( ( skipSideSpeakers ) && EQ_16( readIdx, 4 ) ) + { + /* Skip gains for side speakers in lookup table */ + readIdx = add( readIdx, 2 ); + move16(); + } + inputMc->panGains_fx[writeIdx][0] = ( EQ_32( ls_conversion_cicpX_mono_fx[readIdx][0], ONE_IN_Q30 ) ) ? ONE_IN_Q31 : L_shl( ls_conversion_cicpX_mono_fx[readIdx][0], 1 ); // Q31 + move32(); + ++readIdx; + } + } + + return IVAS_ERR_OK; +} +#endif static ivas_error initMcPanGainsWithMonoOut( input_mc *inputMc ) @@ -2215,7 +2673,60 @@ static ivas_error initMcPanGainsWithMonoOut( return IVAS_ERR_OK; } +#ifdef IVAS_FLOAT_FIXED +static ivas_error initMcPanGainsWithStereoLookup_fx( + input_mc *inputMc ) +{ + Word16 readIdx; + Word16 writeIdx; + bool skipSideSpeakers; + Word16 numInChannels; + ivas_error error; + /* Special case - MONO input. + * Use gains for center CICP speaker and return early. */ + IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) ) + { + inputMc->panGains_fx[0][0] = L_shl( ls_conversion_cicpX_stereo_fx[2][0], 1 ); // Q31 + move32(); + inputMc->panGains_fx[0][1] = L_shl( ls_conversion_cicpX_stereo_fx[2][1], 1 ); // Q31 + move32(); + return IVAS_ERR_OK; + } + + /* ls_conversion_cicpX_stereo contains gains for side speakers. + * These should be skipped with 5.1+X inputs. */ + skipSideSpeakers = false; + IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_4 ) ) + { + skipSideSpeakers = true; + } + + IF( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + readIdx = 0; + move16(); + FOR( writeIdx = 0; writeIdx < numInChannels; ++writeIdx ) + { + IF( skipSideSpeakers && EQ_16( readIdx, 4 ) ) + { + /* Skip gains for side speakers in lookup table */ + readIdx = add( readIdx, 2 ); + move16(); + } + + inputMc->panGains_fx[writeIdx][0] = EQ_32( ls_conversion_cicpX_stereo_fx[readIdx][0], ONE_IN_Q30 ) ? ONE_IN_Q31 : L_shl( ls_conversion_cicpX_stereo_fx[readIdx][0], 1 ); // Q31 + move32(); + inputMc->panGains_fx[writeIdx][1] = EQ_32( ls_conversion_cicpX_stereo_fx[readIdx][1], ONE_IN_Q30 ) ? ONE_IN_Q31 : L_shl( ls_conversion_cicpX_stereo_fx[readIdx][1], 1 ); // Q31 + move32(); + ++readIdx; + } + + return IVAS_ERR_OK; +} +#endif static ivas_error initMcPanGainsWithStereoLookup( input_mc *inputMc ) @@ -2263,9 +2774,59 @@ static ivas_error initMcPanGainsWithStereoLookup( return IVAS_ERR_OK; } - /* Returns 1 (true) if configs A and B are equal, otherwise returns 0 (false). * If both configs are custom LS layouts, layout details are compared to determine equality. */ +#ifdef IVAS_FLOAT_FIXED +static bool configsAreEqual( + const AUDIO_CONFIG configA, + const LSSETUP_CUSTOM_STRUCT customLsA, + const AUDIO_CONFIG configB, + const LSSETUP_CUSTOM_STRUCT customLsB ) +{ + Word16 i; + + /* Both input and output are custom LS - compare structs */ + IF ( EQ_16(configA , IVAS_AUDIO_CONFIG_LS_CUSTOM) && EQ_16(configB , IVAS_AUDIO_CONFIG_LS_CUSTOM) ) + { + IF ( NE_16(customLsA.num_spk , customLsB.num_spk) ) + { + return false; + } + + IF ( NE_16(customLsA.num_lfe , customLsB.num_lfe )) + { + return false; + } + + IF ( NE_16(customLsA.is_planar_setup , customLsB.is_planar_setup) ) + { + return false; + } + + FOR ( i = 0; i < customLsA.num_spk; ++i ) + { + /* Compare to nearest degree (hence the int16_t cast) */ + IF ( NE_32(customLsA.ls_azimuth_fx[i] , customLsB.ls_azimuth_fx[i]) || + NE_32(customLsA.ls_elevation_fx[i] , customLsB.ls_elevation_fx[i] )) + { + return false; + } + } + FOR ( i = 0; i < customLsA.num_lfe; ++i ) + { + IF ( NE_16(customLsA.lfe_idx[i] , customLsB.lfe_idx[i]) ) + { + return false; + } + } + + return true; + } + + /* Otherwise it's enough to compare config enums */ + return configA == configB; +} +#else static bool configsAreEqual( const AUDIO_CONFIG configA, const LSSETUP_CUSTOM_STRUCT customLsA, @@ -2315,8 +2876,53 @@ static bool configsAreEqual( /* Otherwise it's enough to compare config enums */ return configA == configB; } +#endif +#ifdef IVAS_FLOAT_FIXED +static ivas_error updateLfePanGainsForMcOut( + input_mc *inputMc, + const AUDIO_CONFIG outConfig ) +{ + Word16 i, numLfeIn, numOutChannels; + ivas_error error; + error = IVAS_ERR_OK; + + /* If panning is not required, simply return */ + IF ( !inputMc->lfeRouting.pan_lfe ) + { + return error; + } + numLfeIn = getNumLfeChannels( inputMc ); + move16(); + IF ( EQ_16(outConfig , IVAS_AUDIO_CONFIG_LS_CUSTOM) ) + { + numOutChannels = add( inputMc->base.ctx.pCustomLsOut->num_spk, inputMc->base.ctx.pCustomLsOut->num_lfe ); + move16(); + } + ELSE + { + IF ( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + FOR ( i = 0; i < numLfeIn; i++ ) + { + /* panning gains */ + IF ( ( error = getEfapGains_fx( *inputMc->base.ctx.pEfapOutWrapper, inputMc->lfeRouting.lfeOutputAzimuth_fx, inputMc->lfeRouting.lfeOutputElevation_fx, inputMc->lfeRouting.lfePanMtx_fx[i] ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* linear input gain */ + v_multc_fixed( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->lfeRouting.lfeInputGain_fx, inputMc->lfeRouting.lfePanMtx_fx[i], numOutChannels ); + } + + return error; +} +#else static ivas_error updateLfePanGainsForMcOut( input_mc *inputMc, const AUDIO_CONFIG outConfig ) @@ -2339,28 +2945,62 @@ static ivas_error updateLfePanGainsForMcOut( } else { - if ( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ) != IVAS_ERR_OK ) - { - return error; - } + if ( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + for ( i = 0; i < numLfeIn; i++ ) + { + /* panning gains */ + if ( ( error = getEfapGains( *inputMc->base.ctx.pEfapOutWrapper, inputMc->lfeRouting.lfeOutputAzimuth, inputMc->lfeRouting.lfeOutputElevation, inputMc->lfeRouting.lfePanMtx[i] ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* linear input gain */ + v_multc( inputMc->lfeRouting.lfePanMtx[i], inputMc->lfeRouting.lfeInputGain, inputMc->lfeRouting.lfePanMtx[i], numOutChannels ); + } + + return error; +} +#endif +#ifdef IVAS_FLOAT_FIXED +static ivas_error updateLfePanGainsForAmbiOut( + input_mc *inputMc, + const AUDIO_CONFIG outConfig ) +{ + Word16 i; + Word16 numLfeIn, outAmbiOrder; + ivas_error error; + error = IVAS_ERR_OK; + + /* If panning is not required, simply return */ + IF ( !inputMc->lfeRouting.pan_lfe ) + { + return error; + } + + IF ( ( error = getAmbisonicsOrder_fx( outConfig, &outAmbiOrder ) ) != IVAS_ERR_OK ) + { + return error; } - for ( i = 0; i < numLfeIn; i++ ) + numLfeIn = getNumLfeChannels( inputMc ); + move16(); + FOR ( i = 0; i < numLfeIn; i++ ) { /* panning gains */ - if ( ( error = getEfapGains( *inputMc->base.ctx.pEfapOutWrapper, inputMc->lfeRouting.lfeOutputAzimuth, inputMc->lfeRouting.lfeOutputElevation, inputMc->lfeRouting.lfePanMtx[i] ) ) != IVAS_ERR_OK ) - { - return error; - } + ivas_dirac_dec_get_response_fixed( inputMc->lfeRouting.lfeOutputAzimuth_fx, inputMc->lfeRouting.lfeOutputElevation_fx, inputMc->lfeRouting.lfePanMtx_fx[i], outAmbiOrder ); /* linear input gain */ - v_multc( inputMc->lfeRouting.lfePanMtx[i], inputMc->lfeRouting.lfeInputGain, inputMc->lfeRouting.lfePanMtx[i], numOutChannels ); + v_multc_fixed( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->lfeRouting.lfeInputGain_fx, inputMc->lfeRouting.lfePanMtx_fx[i], IVAS_MAX_OUTPUT_CHANNELS ); } return error; } - - +#else static ivas_error updateLfePanGainsForAmbiOut( input_mc *inputMc, const AUDIO_CONFIG outConfig ) @@ -2394,8 +3034,72 @@ static ivas_error updateLfePanGainsForAmbiOut( return error; } +#endif +#ifdef IVAS_FLOAT_FIXED +static ivas_error updateMcPanGainsForMcOut( + input_mc *inputMc, + const AUDIO_CONFIG outConfig ) +{ + ivas_error error; + + /* "if" conditions below realize the following mapping: + + If in == out, use identity matrix, otherwise follow the table: + +-----------+-------------+---------------+-----------+--------------------+ + | in\out | MONO | STEREO | custom LS | other | + +-----------+-------------+---------------+-----------+--------------------+ + | MONO | mono out | EFAP | EFAP | EFAP | + | custom LS | mono out | EFAP | EFAP | EFAP | + | other | mono lookup | stereo lookup | EFAP | conversion mapping | + +-----------+-------------+---------------+-----------+--------------------+ + */ + + IF ( configsAreEqual( inputMc->base.inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut ) ) + { + error = initMcPanGainsWithIdentMatrix( inputMc ); + } + ELSE IF ( EQ_16(outConfig , IVAS_AUDIO_CONFIG_LS_CUSTOM) || + EQ_16(inputMc->base.inConfig , IVAS_AUDIO_CONFIG_MONO) || + EQ_16(inputMc->base.inConfig , IVAS_AUDIO_CONFIG_LS_CUSTOM )) + { + IF ( EQ_16(inputMc->base.inConfig , IVAS_AUDIO_CONFIG_MONO ) && ( inputMc->nonDiegeticPan ) ) + { + inputMc->panGains_fx[0][0] = EQ_32(inputMc->nonDiegeticPanGain_fx , ONE_IN_Q31 ) ? ONE_IN_Q31 : L_add( L_shr( inputMc->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 ); + move32(); + inputMc->panGains_fx[0][1] = L_sub( ONE_IN_Q31, inputMc->panGains_fx[0][0] ); + move32(); + error = IVAS_ERR_OK; + } + ELSE + { + error = initMcPanGainsWithEfap_fx( inputMc, outConfig ); + } + } + ELSE IF ( EQ_16(outConfig , IVAS_AUDIO_CONFIG_MONO) ) + { + error = initMcPanGainsWithMonoOut_fx( inputMc ); + } + ELSE IF( EQ_16(outConfig , IVAS_AUDIO_CONFIG_STEREO) ) + { + error = initMcPanGainsWithStereoLookup_fx( inputMc ); + } + ELSE /* default */ + { + error = initMcPanGainsWithConversionMapping_fx( inputMc, outConfig ); + } + + /* check for errors from above block */ + IF ( error != IVAS_ERR_OK ) + { + return error; + } + /* update LFE panning */ + error = updateLfePanGainsForMcOut( inputMc, outConfig ); + return error; +} +#else static ivas_error updateMcPanGainsForMcOut( input_mc *inputMc, const AUDIO_CONFIG outConfig ) @@ -2457,8 +3161,101 @@ static ivas_error updateMcPanGainsForMcOut( return error; } +#endif +#ifdef IVAS_FLOAT_FIXED +static ivas_error updateMcPanGainsForAmbiOut( + input_mc *inputMc, + const AUDIO_CONFIG outConfig ) +{ + Word16 ch_in, ch_out, lfeIdx, i; + Word16 numNonLfeInChannels, outAmbiOrder; + const Word32 *spkAzi_fx, *spkEle_fx; + ivas_error error; + + IF( ( error = getAmbisonicsOrder_fx( outConfig, &outAmbiOrder ) ) != IVAS_ERR_OK ) + { + return error; + } + + IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) + { + IF( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + + IF( ( error = getSpeakerAzimuths_fx( inputMc->base.inConfig, &spkAzi_fx ) ) != IVAS_ERR_OK ) + { + return error; + } + + IF( ( error = getSpeakerElevations_fx( inputMc->base.inConfig, &spkEle_fx ) ) != IVAS_ERR_OK ) + { + return error; + } + ch_in = 0; + move16(); + FOR ( ch_out = 0; ch_in < numNonLfeInChannels; ++ch_out ) + { + IF ( EQ_16(ch_in , LFE_CHANNEL )) + { + ++ch_out; + } + ivas_dirac_dec_get_response_fixed( (Word16) L_shr( spkAzi_fx[ch_in], 22 ), (Word16) L_shr( spkEle_fx[ch_in], 22 ), inputMc->panGains_fx[ch_out], outAmbiOrder ); + FOR ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + { + Word32 temp = inputMc->panGains_fx[ch_out][i]; + move32(); + inputMc->panGains_fx[ch_out][i] = GE_32( abs( temp ), ONE_IN_Q29 ) ? ( GT_32( temp, 0 ) ? ONE_IN_Q31 : L_negate( ONE_IN_Q31 ) ) + : L_shl( temp, 2 ); // Q31 + move32(); + } + ++ch_in; + } + } + ELSE + { + numNonLfeInChannels = inputMc->customLsInput.num_spk; + move16(); + spkAzi_fx = inputMc->customLsInput.ls_azimuth_fx; + move32(); + spkEle_fx = inputMc->customLsInput.ls_elevation_fx; + move32(); + ch_in = 0; + move16(); + FOR ( ch_out = 0; ch_in < numNonLfeInChannels; ++ch_out ) + { + FOR ( lfeIdx = 0; lfeIdx < inputMc->customLsInput.num_lfe; ++lfeIdx ) + { + IF ( EQ_16(inputMc->customLsInput.lfe_idx[lfeIdx] , ch_in )) + { + ++ch_out; + BREAK; + } + } + ivas_dirac_dec_get_response_fixed( (Word16) L_shr( spkAzi_fx[ch_in], 22 ), (Word16) L_shr( spkEle_fx[ch_in], 22 ), inputMc->panGains_fx[ch_out], outAmbiOrder ); + FOR ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + { + Word32 temp = inputMc->panGains_fx[ch_out][i]; + move32(); + inputMc->panGains_fx[ch_out][i] = GE_32( abs( temp ), ONE_IN_Q29 ) ? ( GT_32( temp, 0 ) ? ONE_IN_Q31 : L_negate( ONE_IN_Q31 ) ) + : L_shl( temp, 2 ); // Q31 + move32(); + } + ++ch_in; + } + } + + /* update LFE panning */ + IF ( ( error = updateLfePanGainsForAmbiOut( inputMc, outConfig ) ) != IVAS_ERR_OK ) + { + return error; + } + return IVAS_ERR_OK; +} +#else static ivas_error updateMcPanGainsForAmbiOut( input_mc *inputMc, const AUDIO_CONFIG outConfig ) @@ -2528,8 +3325,69 @@ static ivas_error updateMcPanGainsForAmbiOut( return IVAS_ERR_OK; } +#endif +#ifdef IVAS_FLOAT_FIXED +static ivas_error updateMcPanGains( + input_mc *inputMc, + const AUDIO_CONFIG outConfig ) +{ + Word16 i; + ivas_error error; + + /* Reset to all zeros - some functions below only write non-zero elements. */ + setZeroPanMatrix_fx( inputMc->panGains_fx ); + + error = IVAS_ERR_OK; + SWITCH ( getAudioConfigType( outConfig ) ) + { + case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED: + error = updateMcPanGainsForMcOut( inputMc, outConfig ); + BREAK; + case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS: + error = updateMcPanGainsForAmbiOut( inputMc, outConfig ); + BREAK; + case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL: + SWITCH( outConfig ) + { + case IVAS_AUDIO_CONFIG_BINAURAL: + BREAK; /* Do nothing */ + case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR: + case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB: + /* Prepare rendering to intermediate format */ + error = updateMcPanGainsForMcOut( inputMc, IVAS_AUDIO_CONFIG_7_1_4 ); + BREAK; + default: + return IVAS_ERR_INVALID_OUTPUT_FORMAT; + } + BREAK; + case IVAS_REND_AUDIO_CONFIG_TYPE_MASA: + BREAK; /* Do nothing */ + default: + return IVAS_ERR_INVALID_OUTPUT_FORMAT; + } + /* Check error here to keep switch statement more compact */ + IF ( error != IVAS_ERR_OK ) + { + return error; + } + /* Copy LFE routing to pan gains array */ + IF (EQ_16( inputMc->base.inConfig , IVAS_AUDIO_CONFIG_LS_CUSTOM )) + { + FOR ( i = 0; i < inputMc->customLsInput.num_lfe; ++i ) + { + mvr2r_Word32( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->panGains_fx[inputMc->customLsInput.lfe_idx[i]], IVAS_MAX_OUTPUT_CHANNELS ); + } + } + ELSE + { + /* For code simplicity, always copy LFE gains. If config has no LFE, gains will be zero anyway. */ + mvr2r_Word32( inputMc->lfeRouting.lfePanMtx_fx[0], inputMc->panGains_fx[LFE_CHANNEL], IVAS_MAX_OUTPUT_CHANNELS ); + } + return IVAS_ERR_OK; +} +#else static ivas_error updateMcPanGains( input_mc *inputMc, const AUDIO_CONFIG outConfig ) @@ -2590,7 +3448,7 @@ static ivas_error updateMcPanGains( return IVAS_ERR_OK; } - +#endif static ivas_error initMcBinauralRendering( input_mc *inputMc, @@ -2724,8 +3582,69 @@ static ivas_error initMcMasaRendering( return IVAS_ERR_OK; } +#ifdef IVAS_FLOAT_FIXED +static lfe_routing defaultLfeRouting( + const AUDIO_CONFIG inConfig, + const LSSETUP_CUSTOM_STRUCT customLsIn, + const AUDIO_CONFIG outConfig, + const LSSETUP_CUSTOM_STRUCT customLsOut ) +{ + Word16 i; + lfe_routing routing; + + /* Set all output gains to zero, then route each input LFE consecutively to the next available output LFE. */ + + FOR ( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; ++i ) + { + set_val_Word32( routing.lfePanMtx_fx[i], 0, IVAS_MAX_OUTPUT_CHANNELS ); + } + routing.pan_lfe = false; + routing.lfeInputGain_fx = ONE_IN_Q31; + + SWITCH ( inConfig ) + { + case IVAS_AUDIO_CONFIG_5_1: + case IVAS_AUDIO_CONFIG_5_1_2: + case IVAS_AUDIO_CONFIG_5_1_4: + case IVAS_AUDIO_CONFIG_7_1: + case IVAS_AUDIO_CONFIG_7_1_4: + routing.numLfeChannels = 1; + move16(); + BREAK; + case IVAS_AUDIO_CONFIG_LS_CUSTOM: + routing.numLfeChannels = customLsIn.num_lfe; + move16(); + BREAK; + default: + routing.numLfeChannels = 0; + move16(); + } + SWITCH ( outConfig ) + { + case IVAS_AUDIO_CONFIG_5_1: + case IVAS_AUDIO_CONFIG_5_1_2: + case IVAS_AUDIO_CONFIG_5_1_4: + case IVAS_AUDIO_CONFIG_7_1: + case IVAS_AUDIO_CONFIG_7_1_4: + routing.lfePanMtx_fx[0][LFE_CHANNEL] = ONE_IN_Q31; + move32(); + BREAK; + case IVAS_AUDIO_CONFIG_LS_CUSTOM: + FOR ( i = 0; i < routing.numLfeChannels && i < customLsOut.num_lfe; ++i ) + { + routing.lfePanMtx_fx[i][customLsOut.lfe_idx[i]] = ONE_IN_Q31; + move32(); + } + BREAK; + default: + /* Do nothing */ + BREAK; + } + return routing; +} +#else static lfe_routing defaultLfeRouting( const AUDIO_CONFIG inConfig, const LSSETUP_CUSTOM_STRUCT customLsIn, @@ -2783,7 +3702,7 @@ static lfe_routing defaultLfeRouting( return routing; } - +#endif #ifdef IVAS_FLOAT_FIXED static ivas_error setRendInputActiveMc( void *input, @@ -2809,7 +3728,10 @@ static ivas_error setRendInputActiveMc( { return error; } - + if ( ( error = allocateMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx, MAX_BIN_DELAY_SAMPLES ) ) != IVAS_ERR_OK ) + { + return error; + } if ( ( error = allocateInputBaseBufferData( &inputMc->bufferData, MAX_BUFFER_LENGTH ) ) != IVAS_ERR_OK ) { return error; @@ -2822,6 +3744,7 @@ static ivas_error setRendInputActiveMc( initRendInputBase_fx( &inputMc->base, inConfig, id, rendCtx, inputMc->bufferData_fx, MAX_BUFFER_LENGTH ); setZeroPanMatrix( inputMc->panGains ); + setZeroPanMatrix_fx( inputMc->panGains_fx ); inputMc->customLsInput = defaultCustomLs(); inputMc->tdRendWrapper = defaultTdRendWrapper(); @@ -2833,6 +3756,7 @@ static ivas_error setRendInputActiveMc( initRotGainsWord32_fx( inputMc->rot_gains_prev_fx ); inputMc->lfeRouting = defaultLfeRouting( inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut ); set_zero( inputMc->lfeDelayBuffer, MAX_BIN_DELAY_SAMPLES ); + set_val_Word32( inputMc->lfeDelayBuffer_fx, 0, MAX_BIN_DELAY_SAMPLES ); inputMc->binauralDelaySmp = 0; if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) @@ -2935,6 +3859,7 @@ static void clearInputMc( rendCtx = inputMc->base.ctx; freeMcLfeDelayBuffer( &inputMc->lfeDelayBuffer ); + freeMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx ); freeInputBaseBufferData( &inputMc->bufferData ); freeInputBaseBufferData_fx( &inputMc->bufferData_fx ); initRendInputBase( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); @@ -3082,7 +4007,7 @@ static ivas_error initSbaPanGainsForSbaOut( ivas_error error; error = IVAS_ERR_OK; - if ( getAudioConfigType( outConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) + IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ) { assert( !"Invalid configuration" ); return IVAS_ERR_WRONG_PARAMS; @@ -3594,8 +4519,11 @@ ivas_error IVAS_REND_Open( hIvasRend->inputsMc[i].bufferData = NULL; hIvasRend->inputsMc[i].bufferData_fx = NULL; hIvasRend->inputsMc[i].lfeDelayBuffer = NULL; + hIvasRend->inputsMc[i].lfeDelayBuffer_fx = NULL; hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan; hIvasRend->inputsMc[i].nonDiegeticPanGain = nonDiegeticPanGain; + Word32 temp = ( abs( (Word32) nonDiegeticPanGain ) ); + hIvasRend->inputsMc[i].nonDiegeticPanGain_fx = ( temp == 1 ) ? ( ( nonDiegeticPanGain < 0 ) ? L_negate( ONE_IN_Q31 ) : ONE_IN_Q31 ) :(Word32) (nonDiegeticPanGain * ( ONE_IN_Q31 )); hIvasRend->inputsMc[i].hMcMasa = NULL; } @@ -3749,19 +4677,51 @@ ivas_error IVAS_REND_Open( for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i ) { - initRendInputBase( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 ); - - hIvasRend->inputsMasa[i].metadataHasBeenFed = false; - hIvasRend->inputsMasa[i].bufferData = NULL; - hIvasRend->inputsMasa[i].hMasaPrerend = NULL; - hIvasRend->inputsMasa[i].hMasaExtRend = NULL; + initRendInputBase( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 ); + + hIvasRend->inputsMasa[i].metadataHasBeenFed = false; + hIvasRend->inputsMasa[i].bufferData = NULL; + hIvasRend->inputsMasa[i].hMasaPrerend = NULL; + hIvasRend->inputsMasa[i].hMasaExtRend = NULL; + } + + + return IVAS_ERR_OK; +} +#endif +#ifdef IVAS_FLOAT_FIXED +static LSSETUP_CUSTOM_STRUCT makeCustomLsSetup( + const IVAS_CUSTOM_LS_DATA rendCustomLsLayout ) +{ + int16_t i; + LSSETUP_CUSTOM_STRUCT customLs; + + /* Copy layout description */ + customLs.num_spk = rendCustomLsLayout.num_spk; + for ( i = 0; i < rendCustomLsLayout.num_spk; i++ ) + { + customLs.ls_azimuth_fx[i] = (Word32) ( rendCustomLsLayout.azimuth[i] * ONE_IN_Q22 ); + customLs.ls_elevation_fx[i] = (Word32) ( rendCustomLsLayout.elevation[i] * ONE_IN_Q22 ); + } + mvr2r( rendCustomLsLayout.azimuth, customLs.ls_azimuth, rendCustomLsLayout.num_spk ); + mvr2r( rendCustomLsLayout.elevation, customLs.ls_elevation, rendCustomLsLayout.num_spk ); + + customLs.is_planar_setup = 1; + for ( i = 0; i < rendCustomLsLayout.num_spk; ++i ) + { + if ( fabsf( rendCustomLsLayout.elevation[i] ) > EPSILON ) + { + customLs.is_planar_setup = 0; + break; + } } + customLs.num_lfe = rendCustomLsLayout.num_lfe; + mvs2s( rendCustomLsLayout.lfe_idx, customLs.lfe_idx, rendCustomLsLayout.num_lfe ); - return IVAS_ERR_OK; + return customLs; } -#endif - +#else static LSSETUP_CUSTOM_STRUCT makeCustomLsSetup( const IVAS_CUSTOM_LS_DATA rendCustomLsLayout ) { @@ -3788,7 +4748,7 @@ static LSSETUP_CUSTOM_STRUCT makeCustomLsSetup( return customLs; } - +#endif static ivas_error validateCustomLsLayout( const IVAS_CUSTOM_LS_DATA layout ) @@ -4387,7 +5347,7 @@ ivas_error IVAS_REND_SetInputLfeMtx( return IVAS_ERR_OK; } - +#ifdef IVAS_FLOAT_FIXED /*-------------------------------------------------------------------* * IVAS_REND_SetInputLfePos() * @@ -4426,8 +5386,11 @@ ivas_error IVAS_REND_SetInputLfePos( pInputMc->lfeRouting.pan_lfe = true; pInputMc->lfeRouting.lfeInputGain = inputGain; + pInputMc->lfeRouting.lfeInputGain_fx = ( inputGain == 1.0f ) ? ONE_IN_Q31 : (Word32) (inputGain * ( ONE_IN_Q31 )); pInputMc->lfeRouting.lfeOutputAzimuth = outputAzimuth; + pInputMc->lfeRouting.lfeOutputAzimuth_fx = (Word16) ( outputAzimuth ); // Q0 pInputMc->lfeRouting.lfeOutputElevation = outputElevation; + pInputMc->lfeRouting.lfeOutputElevation_fx = (Word16) ( outputElevation ); // Q0 if ( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ) != IVAS_ERR_OK ) { @@ -4436,7 +5399,50 @@ ivas_error IVAS_REND_SetInputLfePos( return IVAS_ERR_OK; } +#else +ivas_error IVAS_REND_SetInputLfePos( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + const IVAS_REND_InputId inputId, /* i : ID of the input */ + const float inputGain, /* i : Input gain to be applied to the LFE channel(s) */ + const float outputAzimuth, /* i : Output azimuth position */ + const float outputElevation /* i : Output elevation position */ +) +{ + input_base *pInputBase; + input_mc *pInputMc; + ivas_error error; + + /* Validate function arguments */ + if ( hIvasRend == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + if ( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( getAudioConfigType( pInputBase->inConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) + { + /* Custom LFE routing only makes sense with channel-based input */ + return IVAS_ERR_INVALID_INPUT_FORMAT; + } + pInputMc = (input_mc *) pInputBase; + + pInputMc->lfeRouting.pan_lfe = true; + pInputMc->lfeRouting.lfeInputGain = inputGain; + pInputMc->lfeRouting.lfeOutputAzimuth = outputAzimuth; + pInputMc->lfeRouting.lfeOutputElevation = outputElevation; + + if ( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ) != IVAS_ERR_OK ) + { + return error; + } + return IVAS_ERR_OK; +} +#endif /*-------------------------------------------------------------------* * IVAS_REND_RemoveInput() @@ -5636,8 +6642,9 @@ static ivas_error rotateFrameMc_fx( return error; } num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES; + move16(); - IF( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM ) + IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) { IF( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ) != IVAS_ERR_OK ) { @@ -5646,7 +6653,7 @@ static ivas_error rotateFrameMc_fx( } ELSE { - nchan = pInCustomLs->num_spk + pInCustomLs->num_lfe; + nchan = add( pInCustomLs->num_spk, pInCustomLs->num_lfe ); } IF( ( error = getMcConfigValues_fx( inConfig, pInCustomLs, &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ) != IVAS_ERR_OK ) @@ -5659,11 +6666,15 @@ static ivas_error rotateFrameMc_fx( { set_val_Word32( gains[ch_in], 0, nchan ); gains[ch_in][ch_in] = ONE_IN_Q30; + move32(); } /* subframe loop */ + Word16 tmp_e; + Word16 tmp = BASOP_Util_Divide3216_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &tmp_e ); + tmp = shr( tmp, negate( add( 1, tmp_e ) ) ); + subframe_len = tmp; - subframe_len = inAudio.config.numSamplesPerChannel / num_subframes; FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ ) { FOR( i = 0; i < 3; i++ ) @@ -5673,6 +6684,7 @@ static ivas_error rotateFrameMc_fx( FOR( j = 0; j < 3; j++ ) { Rmat_fx[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j]; + move32(); } } ELSE @@ -5680,19 +6692,21 @@ static ivas_error rotateFrameMc_fx( /* Set to identity */ set_val_Word32( Rmat_fx[i], 0, 3 ); Rmat_fx[i][i] = ONE_IN_Q30; + move32(); } } FOR( ch_in = 0; ch_in < nchan; ch_in++ ) { /* skip LFE */ - if ( EQ_16( ch_in, lfe_idx ) ) + IF( EQ_16( ch_in, lfe_idx ) ) { CONTINUE; } /* input channel index without LFE */ - ch_in_woLFE = ( ( lfe_idx > 0 ) && ( ch_in >= lfe_idx ) ) ? ch_in - 1 : ch_in; + ch_in_woLFE = ( ( GT_16( lfe_idx, 0 ) ) && ( GE_16( ch_in, lfe_idx ) ) ) ? sub( ch_in, 1 ) : ch_in; + move16(); /* gains for current subframe rotation */ rotateAziEle_fixed( (Word16) L_shr( ls_azimuth[ch_in_woLFE], 22 ), (Word16) L_shr( ls_elevation[ch_in_woLFE], 22 ), &azimuth_fx, &elevation_fx, Rmat_fx, is_planar_setup ); @@ -5711,8 +6725,9 @@ static ivas_error rotateFrameMc_fx( /* output channel index without LFE */ ch_out_woLFE = ( ( lfe_idx > 0 ) && ( ch_out >= lfe_idx ) ) ? ch_out - 1 : ch_out; - + move16(); gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; // Q30 + move32(); } } } @@ -5723,13 +6738,17 @@ static ivas_error rotateFrameMc_fx( FOR( ch_in = 0; ch_in < nchan; ch_in++ ) { writePtr = getSmplPtr_fx( outAudio, ch_out, subframe_idx * subframe_len ); + move32(); readPtr = getSmplPtr_fx( inAudio, ch_in, subframe_idx * subframe_len ); + move32(); /* crossfade with previous rotation gains */ FOR( i = 0; i < subframe_len; i++ ) { *writePtr++ = L_add( *writePtr, L_add( Mpy_32_32( ( *readPtr ), Mpy_32_32( ( ONE_IN_Q31 - crossfade[i] ), gains_prev[ch_in][ch_out] ) ), Mpy_32_32( ( *readPtr ), Mpy_32_32( crossfade[i], gains[ch_in][ch_out] ) ) ) ); // Qinp -1 + + move32(); readPtr++; } } @@ -6805,7 +7824,7 @@ static ivas_error renderActiveInputsIsm( int16_t i; input_ism *pCurrentInput; ivas_error error; - + Word16 input_q = *outAudio.pq_fact; for ( i = 0, pCurrentInput = hIvasRend->inputsIsm; i < RENDERER_MAX_ISM_INPUTS; ++i, ++pCurrentInput ) { if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID ) @@ -6821,7 +7840,7 @@ static ivas_error renderActiveInputsIsm( } for ( i = 0; i < outAudio.config.numSamplesPerChannel * outAudio.config.numChannels; ++i ) { - outAudio.data_fx[i] = (Word32) ( outAudio.data[i] * ( 1 << ( *outAudio.pq_fact - 1 ) ) ); + outAudio.data_fx[i] = (Word32) ( outAudio.data[i] * ( 1 << ( input_q - 1 ) ) ); } return IVAS_ERR_OK; } @@ -6851,7 +7870,88 @@ static ivas_error renderActiveInputsIsm( return IVAS_ERR_OK; } #endif +#ifdef IVAS_FLOAT_FIXED +static ivas_error renderLfeToBinaural_fx( + const input_mc *mcInput, + IVAS_REND_AudioBuffer outAudio, + Word16 in_q, + Word16 out_q ) +{ + Word16 lfe_idx; + Word32 gain_fx; + Word16 ear_idx, i, r_shift; + Word32 tmpLfeBuffer[MAX_BUFFER_LENGTH_PER_CHANNEL]; + Word16 frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame; + const Word32 *lfeInput; + Word32 *writePtr; + + assert( ( outAudio.config.numChannels == 2 ) && "Must be binaural output" ); + + push_wmops( "renderLfeToBinaural" ); + gain_fx = GAIN_LFE_WORD32; + move32(); + + IF( NE_32( mcInput->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) + { + lfe_idx = LFE_CHANNEL; + move16(); + } + ELSE IF( GT_16( mcInput->customLsInput.num_lfe, 0 ) ) + { + lfe_idx = mcInput->customLsInput.lfe_idx[0]; + move16(); + } + ELSE + { + /* no LFE to render */ + return IVAS_ERR_OK; + } + + /* --- Prepare LFE signal to be added to binaural output --- */ + lfeInput = getSmplPtr_fx( mcInput->base.inputBuffer, lfe_idx, 0 ); + move32(); + frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel; + move16(); + num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp; + move16(); + num_cpy_smpl_cur_frame = frame_size - num_cpy_smpl_prev_frame; + move16(); + + /* Assuming LFE should be delayed by less that the duration of one frame */ + assert( mcInput->binauralDelaySmp < frame_size ); + + /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */ + v_multc_fixed( mcInput->lfeDelayBuffer_fx, gain_fx, tmpLfeBuffer, num_cpy_smpl_prev_frame ); // Qinp-1 + + /* Continue filling tmp buffer, now with LFE signal from current frame */ + v_multc_fixed( lfeInput, gain_fx, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); // Qinp-1 + + /* Save remaining LFE samples of current frame for next frame */ + mvr2r_Word32( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer_fx, num_cpy_smpl_prev_frame ); + r_shift = sub( sub( in_q, 1 ), out_q ); + move16(); + IF( NE_16( r_shift, 0 ) ) + { + FOR( i = 0; i < add( num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); i++ ) + { + tmpLfeBuffer[i] = L_shr( tmpLfeBuffer[i], r_shift ); // out_q + move32(); + } + } + /* Copy LFE to left and right ears */ + FOR( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx ) + { + writePtr = getSmplPtr_fx( outAudio, ear_idx, 0 ); + move32(); + v_add_fixed( writePtr, tmpLfeBuffer, writePtr, frame_size, 0 ); // out_q + } + + pop_wmops(); + + return IVAS_ERR_OK; +} +#endif static ivas_error renderLfeToBinaural( const input_mc *mcInput, IVAS_REND_AudioBuffer outAudio ) @@ -6920,158 +8020,106 @@ static ivas_error renderMcToBinaural( const AUDIO_CONFIG outConfig, IVAS_REND_AudioBuffer outAudio ) { - float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; + Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k]; AUDIO_CONFIG inConfig; ivas_error error; IVAS_REND_AudioBuffer tmpRotBuffer; const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; - int8_t combinedOrientationEnabled; - int16_t subframe_idx; - float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS]; - int16_t i, j; + Word8 combinedOrientationEnabled; + Word16 subframe_idx; + Word32 *p_tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS]; + Word16 i; + Word16 exp = *outAudio.pq_fact; - for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) { - p_tmpRendBuffer[i] = tmpRendBuffer[i]; + p_tmpRendBuffer_fx[i] = tmpRendBuffer_fx[i]; + move32(); } - push_wmops( "renderMcToBinaural" ); inConfig = mcInput->base.inConfig; - + move32(); hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData; combinedOrientationEnabled = 0; - if ( hCombinedOrientationData != NULL ) + IF( hCombinedOrientationData != NULL ) { - for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ ) + FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ ) { - if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + IF( NE_16( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx], 0 ) ) { combinedOrientationEnabled = 1; - break; + BREAK; } } } - if ( ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ) ) + IF( ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) || ( combinedOrientationEnabled && ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) ) ) ) { - copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer ); + copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx ); - if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb, - 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK ) + IF( ( error = ivas_td_binaural_renderer_ext_fx( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb, + 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer_fx, *outAudio.pq_fact ) ) != IVAS_ERR_OK ) { return error; } + + IF( mcInput->hReverb != NULL ) + { + exp = sub( *outAudio.pq_fact, 2 ); + move16(); + } } - else + ELSE { /* apply rotation */ - if ( combinedOrientationEnabled ) + IF( combinedOrientationEnabled ) { tmpRotBuffer = mcInput->base.inputBuffer; - tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) ); - set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); set_val_Word32( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); - if ( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev_fx, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) + IF( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev_fx, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) { return error; } - for ( i = 0; i < tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels; i++ ) - { + exp = sub( *outAudio.pq_fact, 1 ); + move16(); + copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer_fx ); - tmpRotBuffer.data[i] = (float) tmpRotBuffer.data_fx[i] / ( 1 << ( *outAudio.pq_fact - 2 ) ); - } - copyBufferTo2dArray( tmpRotBuffer, tmpRendBuffer ); - free( tmpRotBuffer.data ); free( tmpRotBuffer.data_fx ); } - else + ELSE { - copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer ); + copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx ); } // Porting Crend_process function - Word16 nchan_out = 2, nchan_in = 12, subframe_len; CREND_HANDLE hCrend; - Word32 output_buffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k]; - Word32 *output_fx[MAX_OUTPUT_CHANNELS]; hCrend = mcInput->crendWrapper->hCrend; - IVAS_REND_AudioConfigType inConfigType; - subframe_len = (Word16) ( *mcInput->base.ctx.pOutSampleRate / ( FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) ); - Word16 gd_bits = find_guarded_bits_fx( subframe_len ); - Word16 exp = 15; - exp -= gd_bits; - Word16 nchan = nchan_in; - inConfigType = getAudioConfigType( mcInput->base.inConfig ); - - if ( ( error = getAudioConfigNumChannels( outConfig, &nchan_out ) ) != IVAS_ERR_OK ) - { - return error; - } - // TODO:will remove later for temporary conversion; not there in the float code code - if ( ( error = getAudioConfigNumChannels( inConfig, &nchan_in ) ) != IVAS_ERR_OK ) - { - return error; - } - for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) - { - output_fx[i] = output_buffer_fx[i]; - } - if ( hCrend->reflections != NULL ) - { - if ( hCrend->reflections->use_er == 1 && hCrend->reflections->is_ready == 1 ) - { - nchan = hCrend->reflections->shoebox_data.n_sources + 1; - for ( i = 0; i < 150; i++ ) - { - hCrend->reflections->shoebox_data.gains.data_fx[i] = (Word32) ( hCrend->reflections->shoebox_data.gains.data[i] * ONE_IN_Q31 ); - } - } - } - - if ( inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED || inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) - { - nchan = nchan_in; - } - for ( i = 0; i < nchan; i++ ) - { - for ( j = 0; j < L_FRAME48k; j++ ) - { - output_fx[i][j] = (Word32) float_to_fix( p_tmpRendBuffer[i][j], exp ); - } - } /* call CREND */ - if ( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, output_fx, *mcInput->base.ctx.pOutSampleRate, - getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ) != IVAS_ERR_OK ) + IF( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, p_tmpRendBuffer_fx, *mcInput->base.ctx.pOutSampleRate, + getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ) != IVAS_ERR_OK ) { return error; } - if ( hCrend->hReverb != NULL ) - { - exp -= 2; - } - for ( i = 0; i < nchan_out; i++ ) + IF( hCrend->hReverb != NULL ) { - - for ( j = 0; j < L_FRAME48k; j++ ) - { - - p_tmpRendBuffer[i][j] = fix_to_float( output_fx[i][j], exp ); - } + exp = sub( exp, 2 ); + move16(); } } - accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio ); + accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio ); - if ( ( error = renderLfeToBinaural( mcInput, outAudio ) ) != IVAS_ERR_OK ) + IF( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ) != IVAS_ERR_OK ) { return error; } - + *outAudio.pq_fact = exp; + move16(); pop_wmops(); return IVAS_ERR_OK; } @@ -7171,150 +8219,108 @@ static ivas_error renderMcToBinauralRoom( const AUDIO_CONFIG outConfig, IVAS_REND_AudioBuffer outAudio ) { - float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; + Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; AUDIO_CONFIG inConfig; ivas_error error; IVAS_REND_AudioBuffer tmpRotBuffer; - float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS]; - int16_t i; + Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS]; + Word16 i; const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; - int8_t combinedOrientationEnabled; - int16_t subframe_idx; - - for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + Word8 combinedOrientationEnabled; + Word16 subframe_idx; + Word16 exp = *outAudio.pq_fact; + move16(); + FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) { p_tmpRendBuffer[i] = tmpRendBuffer[i]; + move32(); } push_wmops( "renderMcToBinauralRoom" ); inConfig = mcInput->base.inConfig; - + move32(); hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData; + move32(); combinedOrientationEnabled = 0; - if ( hCombinedOrientationData != NULL ) + move32(); + IF( hCombinedOrientationData != NULL ) { - for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ ) + FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ ) { - if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + IF( NE_16( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx], 0 ) ) { combinedOrientationEnabled = 1; - break; + BREAK; } } } - if ( ( mcInput->hReverb != NULL && outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && ( ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ) ) ) - { - copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer ); - - if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb, - 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK ) - { - return error; - } - } - else - { - /* apply rotation */ - if ( combinedOrientationEnabled ) - { - tmpRotBuffer = mcInput->base.inputBuffer; - tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); - set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); - - if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, - mcInput->rot_gains_prev, - mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) - { - return error; - } - - copyBufferTo2dArray( tmpRotBuffer, tmpRendBuffer ); - free( tmpRotBuffer.data ); - } - else - { - copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer ); - } - // Porting Crend_process function - Word16 j, nchan_out = 2, nchan_in = 12, subframe_len; - CREND_HANDLE hCrend; - Word32 output_buffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k]; - Word32 *output_fx[MAX_OUTPUT_CHANNELS]; - hCrend = mcInput->crendWrapper->hCrend; - IVAS_REND_AudioConfigType inConfigType; - subframe_len = (Word16) ( *mcInput->base.ctx.pOutSampleRate / ( FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) ); - Word16 gd_bits = find_guarded_bits_fx( subframe_len ); - Word16 exp = 15; - exp -= gd_bits; - Word16 nchan = nchan_in; - inConfigType = getAudioConfigType( mcInput->base.inConfig ); - - if ( ( error = getAudioConfigNumChannels( outConfig, &nchan_out ) ) != IVAS_ERR_OK ) - { - return error; - } - // TODO:will remove later for temporary conversion; not there in the float code code - if ( ( error = getAudioConfigNumChannels( inConfig, &nchan_in ) ) != IVAS_ERR_OK ) + if ( ( mcInput->hReverb != NULL && EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) && ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) ) ) ) ) + { + copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer ); + + IF( ( error = ivas_td_binaural_renderer_ext_fx( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb, + 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer, *outAudio.pq_fact ) ) != IVAS_ERR_OK ) { return error; } - for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + IF( mcInput->hReverb != NULL ) { - output_fx[i] = output_buffer_fx[i]; + exp = sub( *outAudio.pq_fact, 2 ); + move16(); } - if ( hCrend->reflections != NULL ) + } + ELSE + { + /* apply rotation */ + IF( combinedOrientationEnabled ) { - if ( hCrend->reflections->use_er == 1 && hCrend->reflections->is_ready == 1 ) + tmpRotBuffer = mcInput->base.inputBuffer; + tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) ); + set_val_Word32( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); + + IF( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, + mcInput->rot_gains_prev_fx, + mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) { - nchan = hCrend->reflections->shoebox_data.n_sources + 1; - for ( i = 0; i < 150; i++ ) - { - hCrend->reflections->shoebox_data.gains.data_fx[i] = (Word32) ( hCrend->reflections->shoebox_data.gains.data[i] * ONE_IN_Q31 ); - } + return error; } - } - if ( inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED || inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) - { - nchan = nchan_in; + exp = sub( *outAudio.pq_fact, 1 ); + move16(); + + copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer ); + free( tmpRotBuffer.data_fx ); } - for ( i = 0; i < nchan; i++ ) + ELSE { - for ( j = 0; j < L_FRAME48k; j++ ) - { - - output_fx[i][j] = (Word32) float_to_fix( p_tmpRendBuffer[i][j], exp ); - } + copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer ); } + // Porting Crend_process function + CREND_HANDLE hCrend; + hCrend = mcInput->crendWrapper->hCrend; + /* call CREND */ - if ( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, output_fx, *mcInput->base.ctx.pOutSampleRate, - getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ) != IVAS_ERR_OK ) + IF( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, p_tmpRendBuffer, *mcInput->base.ctx.pOutSampleRate, + getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ) != IVAS_ERR_OK ) { return error; } - if ( hCrend->hReverb != NULL ) - { - exp -= 2; - } - for ( i = 0; i < nchan_out; i++ ) + IF( hCrend->hReverb != NULL ) { - - for ( j = 0; j < L_FRAME48k; j++ ) - { - - p_tmpRendBuffer[i][j] = fix_to_float( output_fx[i][j], exp ); - } + exp = sub( exp, 2 ); + move16(); } } - accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio ); + accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio ); - if ( ( error = renderLfeToBinaural( mcInput, outAudio ) ) != IVAS_ERR_OK ) + IF( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ) != IVAS_ERR_OK ) { return error; } - + *outAudio.pq_fact = exp; + move16(); pop_wmops(); return IVAS_ERR_OK; } @@ -7415,151 +8421,108 @@ static ivas_error renderMcCustomLsToBinauralRoom( const AUDIO_CONFIG outConfig, IVAS_REND_AudioBuffer outAudio ) { - int16_t i; - int16_t tmp; - float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; + Word16 i; + Word16 tmp; + Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; ivas_error error; IVAS_REND_AudioBuffer tmpRotBuffer; IVAS_REND_AudioBuffer tmpMcBuffer; IVAS_REND_AudioBuffer *tmpBufPtr; - float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS]; + Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS]; const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; - int8_t combinedOrientationEnabled; - int16_t subframe_idx; - + Word8 combinedOrientationEnabled; + Word16 subframe_idx; + Word16 exp = *outAudio.pq_fact; + move16(); push_wmops( "renderMcCustomLsToBinauralRoom" ); tmpRotBuffer = outAudio; /* avoid compilation warning */ - for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) + FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) { p_tmpCrendBuffer[i] = tmpCrendBuffer[i]; + move32(); } hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData; combinedOrientationEnabled = 0; - if ( hCombinedOrientationData != NULL ) + move16(); + IF( hCombinedOrientationData != NULL ) { - for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ ) + FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ ) { - if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + IF( NE_16( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx], 0 ) ) { combinedOrientationEnabled = 1; - break; + move16(); + BREAK; } } } /* apply rotation */ - if ( combinedOrientationEnabled ) + IF( combinedOrientationEnabled ) { tmpRotBuffer = mcInput->base.inputBuffer; - tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); - set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); + tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) ); + set_val_Word32( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); - if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, - mcInput->rot_gains_prev, - mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) + IF( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, + mcInput->rot_gains_prev_fx, + mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) { return error; } + exp = sub( *outAudio.pq_fact, 1 ); + move16(); } /* intermediate conversion to 7_1_4 */ tmpMcBuffer = mcInput->base.inputBuffer; - if ( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ) != IVAS_ERR_OK ) + IF( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ) != IVAS_ERR_OK ) { return error; } tmpMcBuffer.config.numChannels = tmp; - tmpMcBuffer.data = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( float ) ); - set_zero( tmpMcBuffer.data, tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels ); + move16(); + tmpMcBuffer.data_fx = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( Word32 ) ); + set_val_Word32( tmpMcBuffer.data_fx, 0, tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels ); tmpBufPtr = ( combinedOrientationEnabled ) ? &tmpRotBuffer : &mcInput->base.inputBuffer; - for ( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ ) + FOR( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ ) { - renderBufferChannel( *tmpBufPtr, i, mcInput->panGains[i], tmpMcBuffer ); + renderBufferChannel_fx( *tmpBufPtr, i, mcInput->panGains_fx[i], tmpMcBuffer ); } - copyBufferTo2dArray( tmpMcBuffer, tmpCrendBuffer ); - // Porting Crend_process function - Word16 j, nchan_out = 2, nchan_in = 12, subframe_len; + copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer ); + CREND_HANDLE hCrend; - Word32 output_buffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k]; - Word32 *output_fx[MAX_OUTPUT_CHANNELS]; hCrend = mcInput->crendWrapper->hCrend; - IVAS_REND_AudioConfigType inConfigType; - subframe_len = (Word16) ( *mcInput->base.ctx.pOutSampleRate / ( FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) ); - Word16 gd_bits = find_guarded_bits_fx( subframe_len ); - Word16 exp = 15; - exp -= gd_bits; - Word16 nchan = nchan_in; - inConfigType = getAudioConfigType( mcInput->base.inConfig ); - - if ( ( error = getAudioConfigNumChannels( outConfig, &nchan_out ) ) != IVAS_ERR_OK ) - { - return error; - } - nchan_in = 12; - for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) - { - output_fx[i] = output_buffer_fx[i]; - } - if ( hCrend->reflections != NULL ) - { - if ( hCrend->reflections->use_er == 1 && hCrend->reflections->is_ready == 1 ) - { - nchan = hCrend->reflections->shoebox_data.n_sources + 1; - for ( i = 0; i < 150; i++ ) - { - hCrend->reflections->shoebox_data.gains.data_fx[i] = (Word32) ( hCrend->reflections->shoebox_data.gains.data[i] * ONE_IN_Q31 ); - } - } - } - - if ( inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED || inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) - { - nchan = nchan_in; - } - for ( i = 0; i < nchan; i++ ) - { - for ( j = 0; j < L_FRAME48k; j++ ) - { - - output_fx[i][j] = (Word32) float_to_fix( p_tmpCrendBuffer[i][j], exp ); - } - } /* call CREND */ - if ( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL, NULL, NULL, - output_fx, *mcInput->base.ctx.pOutSampleRate, getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ) != IVAS_ERR_OK ) + IF( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL, NULL, NULL, + p_tmpCrendBuffer, *mcInput->base.ctx.pOutSampleRate, getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ) != IVAS_ERR_OK ) { return error; } - if ( hCrend->hReverb != NULL ) + IF( hCrend->hReverb != NULL ) { - exp -= 2; + exp = sub( exp, 2 ); + move16(); } - for ( i = 0; i < nchan_out; i++ ) - { - - for ( j = 0; j < L_FRAME48k; j++ ) - { - p_tmpCrendBuffer[i][j] = fix_to_float( output_fx[i][j], exp ); - } - } - accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio ); + accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio ); - if ( ( error = renderLfeToBinaural( mcInput, outAudio ) ) != IVAS_ERR_OK ) + IF( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ) != IVAS_ERR_OK ) { return error; } - - if ( combinedOrientationEnabled ) + *outAudio.pq_fact = exp; + move16(); + IF( combinedOrientationEnabled ) { - free( tmpRotBuffer.data ); + free( tmpRotBuffer.data_fx ); } - free( tmpMcBuffer.data ); + free( tmpMcBuffer.data_fx ); pop_wmops(); return IVAS_ERR_OK; @@ -7662,7 +8625,26 @@ static ivas_error renderMcCustomLsToBinauralRoom( return IVAS_ERR_OK; } #endif +#ifdef IVAS_FLOAT_FIXED +static void renderMcToMc( + const input_mc *mcInput, + IVAS_REND_AudioBuffer outAudio ) +{ + Word16 i; + IVAS_REND_AudioBuffer inAudio; + + push_wmops( "renderMcToMc" ); + inAudio = mcInput->base.inputBuffer; + + FOR( i = 0; i < inAudio.config.numChannels; ++i ) + { + renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio ); + } + pop_wmops(); + return; +} +#else static void renderMcToMc( const input_mc *mcInput, IVAS_REND_AudioBuffer outAudio ) @@ -7681,8 +8663,26 @@ static void renderMcToMc( pop_wmops(); return; } +#endif +#ifdef IVAS_FLOAT_FIXED +static void renderMcToSba( + const input_mc *mcInput, + IVAS_REND_AudioBuffer outAudio ) +{ + Word16 i; + IVAS_REND_AudioBuffer inAudio; + push_wmops( "renderMcToSba" ); + inAudio = mcInput->base.inputBuffer; + FOR( i = 0; i < inAudio.config.numChannels; ++i ) + { + renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio ); + } + pop_wmops(); + return; +} +#else static void renderMcToSba( const input_mc *mcInput, IVAS_REND_AudioBuffer outAudio ) @@ -7701,7 +8701,7 @@ static void renderMcToSba( pop_wmops(); return; } - +#endif static void renderMcToMasa( input_mc *mcInput, @@ -7720,7 +8720,7 @@ static void renderMcToMasa( return; } - +#ifdef IVAS_FLOAT_FIXED static ivas_error renderInputMc( input_mc *mcInput, const AUDIO_CONFIG outConfig, @@ -7728,7 +8728,7 @@ static ivas_error renderInputMc( { ivas_error error; IVAS_REND_AudioBuffer inAudio; - + Word16 i; error = IVAS_ERR_OK; inAudio = mcInput->base.inputBuffer; @@ -7741,9 +8741,9 @@ static ivas_error renderInputMc( /* Apply input gain to new audio */ v_multc( inAudio.data, mcInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels ); -#ifdef IVAS_FLOAT_FIXED + v_multc_fixed( inAudio.data_fx, mcInput->base.gain_fx, inAudio.data_fx, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels ); -#endif + *outAudio.pq_fact -= 1; // reducing the Q by 1 compensating for the v_mult_fixed done /* set combined orientation subframe info to start info */ ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) ); @@ -7751,25 +8751,45 @@ static ivas_error renderInputMc( { case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED: renderMcToMc( mcInput, outAudio ); + for ( i = 0; i < outAudio.config.numChannels * outAudio.config.numSamplesPerChannel; i++ ) + { + outAudio.data[i] = fix_to_float( outAudio.data_fx[i], *outAudio.pq_fact ); + } break; case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS: renderMcToSba( mcInput, outAudio ); + for ( i = 0; i < outAudio.config.numChannels * outAudio.config.numSamplesPerChannel; i++ ) + { + outAudio.data[i] = fix_to_float( outAudio.data_fx[i], *outAudio.pq_fact ); + } break; case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL: switch ( outConfig ) { case IVAS_AUDIO_CONFIG_BINAURAL: error = renderMcToBinaural( mcInput, outConfig, outAudio ); + for ( i = 0; i < outAudio.config.numChannels * outAudio.config.numSamplesPerChannel; i++ ) + { + outAudio.data[i] = fix_to_float( outAudio.data_fx[i], *outAudio.pq_fact ); + } break; case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR: case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB: if ( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) { error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio ); + for ( i = 0; i < outAudio.config.numChannels * outAudio.config.numSamplesPerChannel; i++ ) + { + outAudio.data[i] = fix_to_float( outAudio.data_fx[i], *outAudio.pq_fact ); + } } else { error = renderMcToBinauralRoom( mcInput, outConfig, outAudio ); + for ( i = 0; i < outAudio.config.numChannels * outAudio.config.numSamplesPerChannel; i++ ) + { + outAudio.data[i] = fix_to_float( outAudio.data_fx[i], *outAudio.pq_fact ); + } } break; default: @@ -7782,10 +8802,69 @@ static ivas_error renderInputMc( default: return IVAS_ERR_INVALID_OUTPUT_FORMAT; } - return error; } +#else +static ivas_error renderInputMc( + input_mc *mcInput, + const AUDIO_CONFIG outConfig, + IVAS_REND_AudioBuffer outAudio ) +{ + ivas_error error; + IVAS_REND_AudioBuffer inAudio; + error = IVAS_ERR_OK; + + inAudio = mcInput->base.inputBuffer; + + if ( mcInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel ) + { + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" ); + } + mcInput->base.numNewSamplesPerChannel = 0; + /* Apply input gain to new audio */ + v_multc( inAudio.data, mcInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels ); + /* set combined orientation subframe info to start info */ + ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) ); + + switch ( getAudioConfigType( outConfig ) ) + { + case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED: + renderMcToMc( mcInput, outAudio ); + break; + case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS: + renderMcToSba( mcInput, outAudio ); + break; + case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL: + switch ( outConfig ) + { + case IVAS_AUDIO_CONFIG_BINAURAL: + error = renderMcToBinaural( mcInput, outConfig, outAudio ); + break; + case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR: + case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB: + if ( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) + { + error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio ); + } + else + { + error = renderMcToBinauralRoom( mcInput, outConfig, outAudio ); + } + break; + default: + return IVAS_ERR_INVALID_OUTPUT_FORMAT; + } + break; + case IVAS_REND_AUDIO_CONFIG_TYPE_MASA: + renderMcToMasa( mcInput, outAudio ); + break; + default: + return IVAS_ERR_INVALID_OUTPUT_FORMAT; + } + return error; +} +#endif #ifdef IVAS_FLOAT_FIXED static ivas_error renderActiveInputsMc( IVAS_REND_HANDLE hIvasRend, @@ -7794,7 +8873,7 @@ static ivas_error renderActiveInputsMc( int16_t i; input_mc *pCurrentInput; ivas_error error; - + Word16 input_q = *outAudio.pq_fact; for ( i = 0, pCurrentInput = hIvasRend->inputsMc; i < RENDERER_MAX_MC_INPUTS; ++i, ++pCurrentInput ) { if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID ) @@ -7808,9 +8887,10 @@ static ivas_error renderActiveInputsMc( return error; } } + for ( i = 0; i < outAudio.config.numSamplesPerChannel * outAudio.config.numChannels; ++i ) { - outAudio.data_fx[i] = (Word32) ( outAudio.data[i] * ( 1 << ( *outAudio.pq_fact - 1 ) ) ); // to make the output buffer Q same as input when it reaches renderActiveInputsSba + outAudio.data_fx[i] = (Word32) ( outAudio.data[i] * ( 1 << ( input_q - 1 ) ) ); // to make the output buffer Q same as input when it reaches renderActiveInputsSba } return IVAS_ERR_OK; } @@ -7980,10 +9060,8 @@ static ivas_error renderSbaToBinaural( } // Porting Crend_process function CREND_HANDLE hCrend; - hCrend = sbaInput->crendWrapper->hCrend; - IVAS_REND_AudioConfigType inConfigType; - inConfigType = getAudioConfigType( sbaInput->base.inConfig ); + /* call CREND */ IF( ( error = ivas_rend_crendProcess( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, output_fx, *sbaInput->base.ctx.pOutSampleRate, getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) ) ) != IVAS_ERR_OK ) @@ -8329,7 +9407,7 @@ static ivas_error renderInputSba( return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" ); } sbaInput->base.numNewSamplesPerChannel = 0; - + *outAudio.pq_fact = outAudio.q_factor; /* Apply input gain to new audio */ v_multc_fixed( inAudio.data_fx, sbaInput->base.gain_fx, inAudio.data_fx, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels ); *outAudio.pq_fact -= 1; // to compensate for the qfactor reduction in gain multiplication. diff --git a/lib_rend/lib_rend.h b/lib_rend/lib_rend.h index f9083d086..a5fb7b313 100644 --- a/lib_rend/lib_rend.h +++ b/lib_rend/lib_rend.h @@ -55,6 +55,10 @@ *---------------------------------------------------------------------*/ typedef float IVAS_REND_LfePanMtx[RENDERER_MAX_INPUT_LFE_CHANNELS][IVAS_MAX_OUTPUT_CHANNELS]; +#ifdef IVAS_FLOAT_FIXED +typedef Word32 IVAS_REND_LfePanMtx_fx[RENDERER_MAX_INPUT_LFE_CHANNELS][IVAS_MAX_OUTPUT_CHANNELS]; + +#endif #ifndef IVAS_FLOAT_FIXED typedef struct { -- GitLab