diff --git a/apps/renderer.c b/apps/renderer.c index 92430a35351ee6fad1083eb48676c9940f1767c7..1536613953582027d2c0ce08a85a8618eefacc5b 100644 --- a/apps/renderer.c +++ b/apps/renderer.c @@ -31,6 +31,7 @@ *******************************************************************************************************/ #include "lib_rend.h" +#include "typedef.h" #include #include #include @@ -195,7 +196,7 @@ typedef struct float lfeConfigElevation; bool lfeCustomRoutingEnabled; char inLfePanningMatrixFile[RENDERER_MAX_CLI_ARG_LENGTH]; - float syncMdDelay; + int16_t syncMdDelay; IVAS_RENDER_FRAMESIZE render_framesize; uint16_t directivityPatternId[RENDERER_MAX_ISM_INPUTS]; AcousticEnvironmentSequence aeSequence; @@ -802,6 +803,7 @@ int main( SplitFileReadWrite *hSplitRendFileReadWrite; int16_t delayNumSamples_temp; int32_t delayTimeScale_temp; + bool flushRendererLastFrame = false; int16_t numSamplesRead; int16_t delayNumSamples = -1; int16_t delayNumSamples_orig = 0; @@ -847,8 +849,11 @@ int main( CmdlnArgs args = parseCmdlnArgs( argc, argv ); - if ( args.nonDiegeticPan && !( ( args.inConfig.numAudioObjects == 0 && args.inConfig.multiChannelBuses[0].audioConfig == IVAS_AUDIO_CONFIG_MONO ) || - ( args.inConfig.numAudioObjects > 0 && args.inConfig.audioObjects[0].audioConfig == IVAS_AUDIO_CONFIG_OBA && args.inConfig.numAudioObjects == 1 ) ) ) + if ( args.nonDiegeticPan && + !( ( args.inConfig.numAudioObjects == 0 && + args.inConfig.multiChannelBuses[0].audioConfig == IVAS_AUDIO_CONFIG_MONO ) || + ( args.inConfig.numAudioObjects > 0 && + args.inConfig.audioObjects[0].audioConfig == IVAS_AUDIO_CONFIG_OBA && args.inConfig.numAudioObjects == 1 ) ) ) { fprintf( stderr, "\ninvalid configuration - non-diegetic panning requires mono or ISM1 input\n" ); goto cleanup; @@ -1178,7 +1183,10 @@ int main( #endif /* sanity check */ - if ( ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL ) && ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) && ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && !is_split_pre_rend_mode( &args ) ) + if ( ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL ) && + ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) && + ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && + !is_split_pre_rend_mode( &args ) ) { fprintf( stderr, "\nExternal Renderer Config is supported only when binaural output configurations is used as output OR when Split pre-rendering mode is enabled. Exiting. \n" ); goto cleanup; @@ -1284,8 +1292,7 @@ int main( #ifdef NONBE_1359_FIX_IVASREND_OMASA_BINAURAL_LOUDNESS /* Set the metadata delay for objects */ #endif - Word32 var1 = (Word32) ( args.syncMdDelay ); - IF( ( error = IVAS_REND_SetIsmMetadataDelay( hIvasRend, var1 ) ) != IVAS_ERR_OK ) + IF( ( error = IVAS_REND_SetIsmMetadataDelay( hIvasRend, args.syncMdDelay ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_SetIsmMetadataDelay(): %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1516,7 +1523,7 @@ int main( } Word16 numOutChannels; - if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_NumOutChannels(): %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1531,8 +1538,16 @@ int main( } } - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { + char *outFile = args.outMetadataFilePath; + + if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + { + outFile = args.outputFilePath; + audioWriter = NULL; + } + if ( ( error = IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms, &bitsBuffer.config.isar_frame_size_ms ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_GetSplitRendBitstreamHeader(): %s!\n", ivas_error_to_string( error ) ); @@ -1545,36 +1560,15 @@ int main( goto cleanup; } - if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outputFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) + if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, outFile, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nCould not open split rend metadata file %s\n", args.outputFilePath ); + fprintf( stderr, "\nCould not open split rend metadata file %s\n", outFile ); goto cleanup; } - audioWriter = NULL; } - else - { - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) - { - if ( ( error = IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms, &bitsBuffer.config.isar_frame_size_ms ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError in IVAS_REND_GetSplitRendBitstreamHeader(): %s!\n", ivas_error_to_string( error ) ); - goto cleanup; - } - - if ( IVAS_REND_GetDelay_fx( hIvasRend, &delayNumSamples_temp, &delayTimeScale_temp ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nUnable to get delay of renderer!\n" ); - goto cleanup; - } - - if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outMetadataFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nCould not open split rend metadata file %s\n", args.outMetadataFilePath ); - goto cleanup; - } - } + if ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + { if ( AudioFileWriter_open( &audioWriter, args.outputFilePath, args.sampleRate, numOutChannels ) != IVAS_ERR_OK ) { fprintf( stderr, "\nFailed to open file: %s\n", args.outputFilePath ); @@ -1667,6 +1661,7 @@ int main( outBuffer.pq_fact = &outBuffer.q_factor; Word16 subframe_len = (Word16) ( args.sampleRate / ( 200 ) ); // sample rate /FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES Word16 gd_bits = find_guard_bits( subframe_len ); + Word16 prev_q_fact = Q11; while ( 1 ) { int16_t num_in_channels; @@ -1719,19 +1714,28 @@ int main( if ( numSamplesRead == 0 ) { /* end of input data */ - break; + flushRendererLastFrame = true; } /* Convert from int to float and from interleaved to packed */ - Word16 Q_out; - *outBuffer.pq_fact = 16 - ( gd_bits ); - convertInputBuffer_fx( inpInt16Buffer, numSamplesRead, inBuffer.config.numSamplesPerChannel, num_in_channels, inInt32Buffer, *outBuffer.pq_fact, inBuffer.config.is_cldfb, cldfbAna, &Q_out ); - *outBuffer.pq_fact = Q_out; + if ( !flushRendererLastFrame ) + { + Word16 Q_out; + *outBuffer.pq_fact = 16 - ( gd_bits ); + convertInputBuffer_fx( inpInt16Buffer, numSamplesRead, inBuffer.config.numSamplesPerChannel, num_in_channels, inInt32Buffer, *outBuffer.pq_fact, inBuffer.config.is_cldfb, cldfbAna, &Q_out ); + *outBuffer.pq_fact = Q_out; + prev_q_fact = Q_out; + } + else + { + memset( inBuffer.data_fx, 0, inBuffer.config.numChannels * inBuffer.config.numSamplesPerChannel * sizeof( Word32 ) ); + *outBuffer.pq_fact = prev_q_fact; + } int16_t num_subframes, sf_idx; num_subframes = (int16_t) args.render_framesize; - if ( isCurrentFrameMultipleOf20ms ) + if ( isCurrentFrameMultipleOf20ms && !flushRendererLastFrame ) { IsmPositionProvider_getNextFrame( positionProvider, &mtdBuffer ); @@ -1843,7 +1847,7 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.multiChannelBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, mcIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, mcIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1857,7 +1861,7 @@ int main( if ( i == 0 ) { IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.audioObjects[i].inputChannelIndex, args.inConfig.numAudioObjects ); - if ( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, ismIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, ismIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1873,7 +1877,7 @@ int main( else { IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.audioObjects[i].inputChannelIndex, 1 ); - if ( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, ismIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, ismIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1896,7 +1900,7 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.ambisonicsBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, sbaIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, sbaIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1913,13 +1917,13 @@ int main( IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.masaBuses[i].inputChannelIndex, numChannels ); - IF( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, masaIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + IF( ( error = IVAS_REND_FeedInputAudio_fx( hIvasRend, masaIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; } - if ( isCurrentFrameMultipleOf20ms ) + if ( isCurrentFrameMultipleOf20ms && !flushRendererLastFrame ) { if ( masaReaders[i] != NULL ) { @@ -1982,7 +1986,7 @@ int main( zeroPad = delayNumSamples; } - if ( is_split_pre_rend_mode( &args ) ) + if ( is_split_pre_rend_mode( &args ) && !flushRendererLastFrame ) { if ( split_rend_write_bitstream_to_file( hSplitRendFileReadWrite, bitsBuffer.bits, &bitsBuffer.config.bitsRead, &bitsBuffer.config.bitsWritten ) != IVAS_ERR_OK ) @@ -1992,7 +1996,7 @@ int main( } } - if ( audioWriter != NULL ) + if ( audioWriter != NULL && !flushRendererLastFrame ) { if ( delayNumSamples * num_out_channels < outBufferSize ) { @@ -2013,7 +2017,7 @@ int main( bitsBuffer.config.bitsWritten = 0; /* Write MASA metadata for MASA outputs */ - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA1 || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA2 ) + if ( !flushRendererLastFrame && ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA1 || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA2 ) ) { IVAS_REND_AudioConfigType inputType1; IVAS_REND_AudioConfigType inputType2; @@ -2085,7 +2089,8 @@ int main( } } - if ( ( args.inConfig.numAmbisonicsBuses > 0 || args.inConfig.numMultiChannelBuses > 0 || args.inConfig.numMasaBuses > 0 ) && args.inConfig.numAudioObjects > 0 ) + if ( ( args.inConfig.numAmbisonicsBuses > 0 || args.inConfig.numMultiChannelBuses > 0 || args.inConfig.numMasaBuses > 0 ) && + args.inConfig.numAudioObjects > 0 ) { inputType2 = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED; if ( ( error = IVAS_REND_MergeMasaMetadata( hIvasRend, &hMetaOutput, inputType1, inputType2 ) ) != IVAS_ERR_OK ) @@ -2101,6 +2106,13 @@ int main( } } + /* no new input was actually read, only delay buffers were flushed + * therefore this is not a real frame */ + if ( flushRendererLastFrame ) + { + break; + } + frame++; if ( !args.quietModeEnabled ) { @@ -2113,12 +2125,13 @@ int main( #endif } - /* add zeros at the end to have equal length of synthesized signals */ + /* add zeros at the end to have equal length of synthesized signals + * the output buffer will contain either leftover input samples from delay aligned inputs + * or zeros for padding */ if ( audioWriter != NULL ) { for ( zeroPadToWrite = zeroPad; zeroPadToWrite > frameSize_smpls; zeroPadToWrite -= frameSize_smpls ) { - memset( outInt16Buffer, 0, outBufferSize * sizeof( int16_t ) ); if ( ( error = AudioFileWriter_write( audioWriter, outInt16Buffer, outBufferSize ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nOutput audio file writer error\n" ); @@ -2126,7 +2139,6 @@ int main( } } - memset( outInt16Buffer, 0, zeroPadToWrite * outBuffer.config.numChannels * sizeof( int16_t ) ); if ( ( error = AudioFileWriter_write( audioWriter, outInt16Buffer, zeroPadToWrite * outBuffer.config.numChannels ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nOutput audio file writer error\n" ); @@ -2136,9 +2148,10 @@ int main( } - if ( args.inConfig.numAudioObjects != 0 && ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) + if ( args.inConfig.numAudioObjects != 0 && + ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) { - fprintf( stdout, "\n\nMetadata delayed %d subframes\n\n", (int16_t) round( args.syncMdDelay / ( 1000 / IVAS_NUM_FRAMES_PER_SEC / IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ) ) ); + fprintf( stdout, "\n\nMetadata delayed %d subframes\n\n", (int16_t) round( args.syncMdDelay / ( (float) BINAURAL_RENDERING_FRAME_SIZE_MS ) ) ); } if ( !args.quietModeEnabled && args.delayCompensationEnabled ) @@ -3038,7 +3051,7 @@ static void parseOption( case CmdLnOptionId_syncMdDelay: assert( numOptionValues == 1 ); /* Metadata Delay to sync with audio delay in ms */ - args->syncMdDelay = strtof( optionValues[0], NULL ); + args->syncMdDelay = (int16_t) strtol( optionValues[0], NULL, 10 ); break; default: assert( 0 && "This should be unreachable - all command line options should be explicitly handled." ); @@ -3574,7 +3587,8 @@ static void parseObjectPosition( *positionDuration = (uint16_t) strtol( line, &endptr, 10 ); readNextMetadataChunk( line, "\n" ); - read_values = (int16_t) sscanf( line, "%f,%f,%f,%f,%f,%f,%f,%f", &meta_prm[0], &meta_prm[1], &meta_prm[2], &meta_prm[3], &meta_prm[4], &meta_prm[5], &meta_prm[6], &meta_prm[7] ); + read_values = (int16_t) sscanf( line, "%f,%f,%f,%f,%f,%f,%f,%f", + &meta_prm[0], &meta_prm[1], &meta_prm[2], &meta_prm[3], &meta_prm[4], &meta_prm[5], &meta_prm[6], &meta_prm[7] ); if ( read_values < 2 ) { diff --git a/lib_isar/lib_isar_post_rend.c b/lib_isar/lib_isar_post_rend.c index 6b63882613943ce2fb75ac37d6d124ccd90652f3..2dcf72622e89ac12d0a4649654e56d8c1a7425d4 100644 --- a/lib_isar/lib_isar_post_rend.c +++ b/lib_isar/lib_isar_post_rend.c @@ -1741,12 +1741,12 @@ ivas_error ISAR_POST_REND_getSamples( } #ifndef DISABLE_LIMITER - Word32 limiter_thresold; + Word32 limiter_threshold; #ifdef DEBUGGING hIvasRend->numClipping += #endif - limiter_thresold = L_shl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact ); - limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_thresold, *outAudio.pq_fact ); + limiter_threshold = L_shl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact ); + limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_threshold, *outAudio.pq_fact ); #endif return IVAS_ERR_OK; diff --git a/lib_isar/lib_isar_pre_rend.c b/lib_isar/lib_isar_pre_rend.c index 2075bc0af1c7e6bb38fd6f463d2c4540a1066309..ae32791dd8fba0c9b1fd5e492ef564bfd5e66a74 100644 --- a/lib_isar/lib_isar_pre_rend.c +++ b/lib_isar/lib_isar_pre_rend.c @@ -96,9 +96,8 @@ ivas_error ISAR_PRE_REND_open( isCldfbNeeded = 1; } - hSplitRendWrapper->hCldfbHandles = NULL; - - IF( isCldfbNeeded ) + test(); + IF( isCldfbNeeded && hSplitRendWrapper->hCldfbHandles == NULL ) { IF( ( hSplitRendWrapper->hCldfbHandles = (CLDFB_HANDLES_WRAPPER_HANDLE) malloc( sizeof( CLDFB_HANDLES_WRAPPER ) ) ) == NULL ) { diff --git a/lib_rend/ivas_mcmasa_ana_fx.c b/lib_rend/ivas_mcmasa_ana_fx.c index dbaf5b7d90079e783bb42ca5e2f5c9d995630a96..ab41810b84403df5e460a5117aa7c44afa546c3f 100644 --- a/lib_rend/ivas_mcmasa_ana_fx.c +++ b/lib_rend/ivas_mcmasa_ana_fx.c @@ -1051,7 +1051,7 @@ void ivas_mcmasa_param_est_ana_fx( cohPanCoh_e = tempCoh2_e; move16(); } - cohPanCoh_fx = L_shl( cohPanCoh_fx, cohPanCoh_e ); /*Q31*/ + cohPanCoh_fx = L_shl_sat( cohPanCoh_fx, cohPanCoh_e ); /*Q31*/ cohPanCoh_e = 0; move16(); lsEnergyRelation_fx = BASOP_Util_Divide3232_Scale( lsEnergy_fx[i2], L_add( lsEnergy_fx[i1], EPSILON_FX ), &lsEnergyRelation_e ); diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index 7fe2f3af753e6ac21489b0b06fe11c595b46199a..3f6ac811b28dd7b1344d7fb2397a353b2d772596 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -33,6 +33,7 @@ #ifndef IVAS_STAT_REND_H #define IVAS_STAT_REND_H +#include "stl.h" #include #include "options.h" #include "ivas_cnst.h" diff --git a/lib_rend/lib_rend.h b/lib_rend/lib_rend.h index c06d6f3cfc3d6b7d85d5482467e905a79cee96fc..f5f1d86cb1b094ec3825b8a4aee70ab36e224987 100644 --- a/lib_rend/lib_rend.h +++ b/lib_rend/lib_rend.h @@ -134,7 +134,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( /* Functions to be called before/during rendering */ -ivas_error IVAS_REND_NumOutChannels( +ivas_error IVAS_REND_GetNumOutChannels( IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */ Word16 *numOutChannels /* o : number of output channels */ ); @@ -218,7 +218,7 @@ ivas_error IVAS_REND_GetHrtfParamBinHandle( ); ivas_error IVAS_REND_GetHrtfStatisticsHandle( - IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ + IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ IVAS_DEC_HRTF_STATISTICS_HANDLE **hHrtfStatistics /* o : HRTF statistics handle */ ); @@ -227,7 +227,8 @@ ivas_error IVAS_REND_GetHrtfStatisticsHandle( ivas_error IVAS_REND_FeedInputAudio_fx( IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ const IVAS_REND_InputId inputId, /* i : ID of the input */ - const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */ + const IVAS_REND_ReadOnlyAudioBuffer inputAudio, /* i : buffer with input audio */ + const bool flushInputs /* i : flush input audio */ ); ivas_error IVAS_REND_FeedInputObjectMetadata( @@ -378,7 +379,7 @@ ivas_error IVAS_REND_SetTotalNumberOfObjects( ivas_error IVAS_REND_SetIsmMetadataDelay( IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ - const Word32 sync_md_delay /* i : Metadata Delay in ms to sync with audio delay */ + const Word16 sync_md_delay /* i : Metadata Delay in ms to sync with audio delay */ ); ivas_error IVAS_REND_GetNumAllObjects( @@ -394,7 +395,7 @@ ivas_error IVAS_REND_GetSamples( /* Functions to be called after rendering */ void IVAS_REND_Close( - IVAS_REND_HANDLE* phIvasRend /* i/o: Pointer to renderer handle */ + IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */ ); /* Split binaural rendering functions */ diff --git a/lib_rend/lib_rend_fx.c b/lib_rend/lib_rend_fx.c index 3a77187247452d81598b74d96e9f4bf68d7b6194..9a7a38809212ba51694ac0f1f55e25377652f284 100644 --- a/lib_rend/lib_rend_fx.c +++ b/lib_rend/lib_rend_fx.c @@ -30,9 +30,14 @@ *******************************************************************************************************/ +#include "basop32.h" #include "basop_util.h" #include "options.h" +#include "cnst.h" +#include "common_api_types.h" +#include "enh32.h" #include "lib_rend.h" +#include "move.h" #include "prot_fx.h" #include "ivas_prot_fx.h" #include "ivas_prot_rend_fx.h" @@ -42,6 +47,8 @@ #include "ivas_cnst.h" #include "ivas_rom_com.h" #include "ivas_rom_rend.h" +#include "stl.h" +#include "typedef.h" #include #include #include @@ -86,6 +93,7 @@ typedef struct typedef struct { const Word32 *pOutSampleRate; + const Word32 *pMaxGlobalDelayNs; const AUDIO_CONFIG *pOutConfig; const LSSETUP_CUSTOM_STRUCT *pCustomLsOut; const EFAP_WRAPPER *pEfapOutWrapper; @@ -102,9 +110,11 @@ typedef struct AUDIO_CONFIG inConfig; IVAS_REND_InputId id; IVAS_REND_AudioBuffer inputBuffer; + TD_RINGBUF_HANDLE delayBuffer; Word32 gain_fx; /* Linear, not in dB Q30 */ rendering_context ctx; Word32 numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */ + Word16 delayNumSamples; } input_base; typedef struct @@ -128,7 +138,7 @@ typedef struct #ifdef NONBE_1377_REND_DIRATT_CONF Word16 object_id; #endif - Word32 ism_metadata_delay_ms_fx; /* Q0 */ + Word16 ism_metadata_delay_ms_fx; /* Q0 */ } input_ism; typedef struct @@ -199,6 +209,7 @@ typedef struct hrtf_handles struct IVAS_REND { Word32 sampleRateOut; + Word32 maxGlobalDelayNs; IVAS_LIMITER_HANDLE hLimiter; input_ism inputsIsm[RENDERER_MAX_ISM_INPUTS]; @@ -211,10 +222,10 @@ struct IVAS_REND EFAP_WRAPPER efapOutWrapper; IVAS_LSSETUP_CUSTOM_STRUCT customLsOut; + Word16 splitRendBFI; SPLIT_REND_WRAPPER *splitRendWrapper; IVAS_REND_AudioBuffer splitRendEncBuffer; IVAS_REND_HeadRotData headRotData; - Word16 splitRendBFI; EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData; COMBINED_ORIENTATION_HANDLE hCombinedOrientationData; @@ -222,6 +233,10 @@ struct IVAS_REND Word8 rendererConfigEnabled; RENDER_CONFIG_DATA *hRendererConfig; /* Renderer config pointer */ +#ifdef DEBUGGING + Word32 numClipping; /* Counter of clipped output samples */ +#endif + Word16 num_subframes; hrtf_handles hHrtfs; }; @@ -257,6 +272,7 @@ static ivas_error allocateInputBaseBufferData_fx( return IVAS_ERR_OK; } + static void freeInputBaseBufferData_fx( Word32 **data /* Qx */ ) { @@ -268,6 +284,19 @@ static void freeInputBaseBufferData_fx( return; } + +static Word16 latencyNsToSamples( + Word32 sampleRate, + Word32 latency_ns ) +{ + Word16 var1, exp; + Word32 var2; + var1 = BASOP_Util_Divide3232_Scale( sampleRate, 1000000000, &exp ); + var2 = L_shr_r( Mpy_32_32( latency_ns, L_deposit_h( var1 ) ), negate( exp ) ); /* Q0 */ + + return extract_l( var2 ); +} + static ivas_error allocateMcLfeDelayBuffer_fx( Word32 **lfeDelayBuffer, /* Qx */ const Word16 data_size ) @@ -280,6 +309,7 @@ static ivas_error allocateMcLfeDelayBuffer_fx( return IVAS_ERR_OK; } + static void freeMcLfeDelayBuffer_fx( Word32 **lfeDelayBuffer /* Qx */ ) { @@ -394,7 +424,7 @@ static void copyBufferToCLDFBarray_fx( static void accumulateCLDFBArrayToBuffer_fx( Word32 re[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], Word32 im[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - IVAS_REND_AudioBuffer *buffer ) + const IVAS_REND_AudioBuffer *buffer ) { UWord32 smplIdx, slotIdx; UWord32 numCldfbSamples, num_bands; @@ -1277,6 +1307,9 @@ static void initRendInputBase_fx( inputBase->ctx = rendCtx; inputBase->numNewSamplesPerChannel = 0; move32(); + inputBase->delayNumSamples = 0; + move32(); + inputBase->delayBuffer = NULL; inputBase->inputBuffer.config.numSamplesPerChannel = 0; inputBase->inputBuffer.config.numChannels = 0; @@ -1331,6 +1364,7 @@ static rendering_context getRendCtx( /* Note: when refactoring this, always take the ADDRESS of a member of the * renderer struct, so that the context stores a POINTER to the member, even * if the member is a pointer or handle itself. */ + ctx.pMaxGlobalDelayNs = &hIvasRend->maxGlobalDelayNs; ctx.pOutConfig = &hIvasRend->outputConfig; ctx.pOutSampleRate = &hIvasRend->sampleRateOut; ctx.pCustomLsOut = &hIvasRend->customLsOut; @@ -1375,6 +1409,346 @@ static bool isIoConfigPairSupported( return true; } +static Word32 getRendInputDelayIsm( + const input_ism *inputIsm, + bool splitPreRendCldfb ) +{ + Word32 latency_ns; + latency_ns = 0; + move32(); + (void) ( splitPreRendCldfb ); /* unused */ + + /* set the rendering delay in InputBase */ + latency_ns = L_max( latency_ns, + inputIsm->tdRendWrapper.binaural_latency_ns ); + IF( inputIsm->crendWrapper != NULL ) + { + latency_ns = L_max( latency_ns, + inputIsm->crendWrapper->binaural_latency_ns ); + } + + return latency_ns; +} + + +static void setRendInputDelayIsm( + void *input, + bool splitPreRendCldfb ) +{ + input_ism *inputIsm; + inputIsm = (input_ism *) input; + + inputIsm->base.delayNumSamples = latencyNsToSamples( *inputIsm->base.ctx.pOutSampleRate, + getRendInputDelayIsm( inputIsm, splitPreRendCldfb ) ); +} + + +static Word32 getRendInputDelayMc( + const input_mc *inputMc, + bool splitPreRendCldfb ) +{ + Word32 latency_ns; + latency_ns = 0; + move32(); + (void) ( splitPreRendCldfb ); /* unused */ + + latency_ns = L_max( latency_ns, + inputMc->tdRendWrapper.binaural_latency_ns ); + IF( inputMc->crendWrapper != NULL ) + { + latency_ns = L_max( latency_ns, + inputMc->crendWrapper->binaural_latency_ns ); + } + + return latency_ns; +} + + +static void setRendInputDelayMc( + void *input, + bool splitPreRendCldfb ) +{ + input_mc *inputMc; + inputMc = (input_mc *) input; + + inputMc->base.delayNumSamples = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, + getRendInputDelayMc( inputMc, splitPreRendCldfb ) ); +} + + +static Word32 getRendInputDelaySba( + const input_sba *inputSba, + bool splitPreRendCldfb ) +{ + Word32 latency_ns; + + latency_ns = 0; + move32(); + + IF( inputSba->cldfbRendWrapper.hCldfbRend != NULL ) + { + Word32 filterbank_delay; + + filterbank_delay = 0; + move32(); + + IF( EQ_16( splitPreRendCldfb, 0 ) ) + { + filterbank_delay = IVAS_FB_DEC_DELAY_NS; + } + + latency_ns = L_max( latency_ns, + L_add( inputSba->cldfbRendWrapper.binaural_latency_ns, + filterbank_delay ) ); + } + + IF( inputSba->crendWrapper != NULL ) + { + latency_ns = L_max( latency_ns, + inputSba->crendWrapper->binaural_latency_ns ); + } + + return latency_ns; +} + + +static void setRendInputDelaySba( + void *input, + bool splitPreRendCldfb ) +{ + input_sba *inputSba; + inputSba = (input_sba *) input; + + inputSba->base.delayNumSamples = latencyNsToSamples( *inputSba->base.ctx.pOutSampleRate, + getRendInputDelaySba( inputSba, splitPreRendCldfb ) ); +} + + +static Word32 getRendInputDelayMasa( + const input_masa *inputMasa, + bool splitPreRendCldfb ) +{ + Word32 latency_ns; + + latency_ns = 0; + move32(); + + test(); + test(); + IF( ( EQ_32( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA1 ) && + EQ_32( *inputMasa->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_MONO ) ) || + ( EQ_32( getAudioConfigType( *inputMasa->base.ctx.pOutConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) ) ) + { + latency_ns = 0; /* no delay */ + } + ELSE + { + Word32 filterbank_delay; + + filterbank_delay = 0; + move32(); + + /* no delay applied for split rendering */ + IF( EQ_16( splitPreRendCldfb, 0 ) ) + { + filterbank_delay = IVAS_FB_DEC_DELAY_NS; + } + latency_ns = L_max( latency_ns, + filterbank_delay ); + } + return latency_ns; +} + + +static void setRendInputDelayMasa( + void *input, + bool splitPreRendCldfb ) +{ + input_masa *inputMasa; + inputMasa = (input_masa *) input; + + inputMasa->base.delayNumSamples = latencyNsToSamples( *inputMasa->base.ctx.pOutSampleRate, + getRendInputDelayMasa( inputMasa, splitPreRendCldfb ) ); +} + + +static Word32 getMaxGlobalDelayNs( IVAS_REND_CONST_HANDLE hIvasRend ) +{ + Word16 i; + Word32 latency_ns; + Word32 max_latency_ns; + bool splitPreRendCldfb; + + max_latency_ns = 0; + /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/ + IF( hIvasRend->hRendererConfig != NULL ) + { + splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD ); + } + ELSE + { + splitPreRendCldfb = false; + } + + /* Compute the maximum delay across all inputs */ + FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ ) + { + IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) ) + { + latency_ns = getRendInputDelayIsm( &hIvasRend->inputsIsm[i], splitPreRendCldfb ); + max_latency_ns = L_max( max_latency_ns, latency_ns ); + } + } + + FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ ) + { + IF( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelayMc( &hIvasRend->inputsMc[i], splitPreRendCldfb ); + max_latency_ns = L_max( max_latency_ns, latency_ns ); + } + } + + FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ ) + { + IF( hIvasRend->inputsSba[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelaySba( &hIvasRend->inputsSba[i], splitPreRendCldfb ); + max_latency_ns = L_max( max_latency_ns, latency_ns ); + } + } + + FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ ) + { + IF( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelayMasa( &hIvasRend->inputsMasa[i], splitPreRendCldfb ); + max_latency_ns = L_max( max_latency_ns, latency_ns ); + } + } + + return max_latency_ns; +} + + +static void setMaxGlobalDelayNs( IVAS_REND_HANDLE hIvasRend ) +{ + hIvasRend->maxGlobalDelayNs = getMaxGlobalDelayNs( (IVAS_REND_CONST_HANDLE) hIvasRend ); +} + +static ivas_error alignInputDelay( + input_base *inputBase, + const IVAS_REND_ReadOnlyAudioBuffer inputAudio, + const Word32 maxGlobalDelayNs, + const Word32 sampleRateOut, + const Word16 cldfb2tdSampleShift, + const bool flushInputs ) +{ + ivas_error error; + input_ism *inputIsm; + Word16 maxGlobalDelaySamples, numSamplesToPush, numSamplesToPop; + UWord16 ringBufferSize, preDelay; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + Word16 i; + const Word32 *p_read_channels[MAX_INPUT_CHANNELS]; + Word32 *p_write_channels[MAX_INPUT_CHANNELS]; +#endif + + maxGlobalDelaySamples = latencyNsToSamples( sampleRateOut, maxGlobalDelayNs ); + maxGlobalDelaySamples = shl( maxGlobalDelaySamples, cldfb2tdSampleShift ); + + /* check if we need to open the delay buffer */ + IF( inputBase->delayBuffer == NULL ) + { + /* buffer has to accomodate maxGlobalDelaySamples + 2 * frameSize */ + ringBufferSize = add( maxGlobalDelaySamples, + shl( inputAudio.config.numSamplesPerChannel, 1 ) ); + + /* pre delay for this input is maximum delay - input delay */ + preDelay = sub( maxGlobalDelaySamples, + shl( inputBase->delayNumSamples, cldfb2tdSampleShift ) ); + + IF( GT_32( preDelay, 0 ) ) + { + IF( ( error = ivas_TD_RINGBUF_Open( &inputBase->delayBuffer, ringBufferSize, inputAudio.config.numChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* for the first frame we need to push zeros to align the input delay to the global delay + * and then push a frame of actual data */ +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + ivas_TD_RINGBUF_PushConstant( inputBase->delayBuffer, 0, preDelay ); +#else + ivas_TD_RINGBUF_PushZeros( inputBase->delayBuffer, preDelay ); +#endif + + /* for ISM inputs, ensure the metadata sync delay is updated */ + IF( getAudioConfigType( inputBase->inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) + { + Word64 tmp; + inputIsm = (input_ism *) inputBase; + + tmp = W_mult0_32_32( L_add( maxGlobalDelayNs, 500000 /* + 0.5ms for rounding */ ) /* Q0 */, 2147 /* (1 / 1e6f) in Q31 */ ); // Q31 + inputIsm->ism_metadata_delay_ms_fx = add( inputIsm->ism_metadata_delay_ms_fx, extract_h( W_extract_h( tmp ) ) ); + } + } + } + + IF( inputBase->delayBuffer != NULL ) + { + /* push in the new input data and pop to retrieve a complete input frame + * if we are flushing the inputs, we don't push in any new data */ + IF( NE_16( flushInputs, 0 ) ) + { + numSamplesToPush = 0; + move16(); + + numSamplesToPop = ivas_TD_RINGBUF_Size( inputBase->delayBuffer ); + } + ELSE + { + numSamplesToPush = inputAudio.config.numSamplesPerChannel; + move16(); + + numSamplesToPop = inputAudio.config.numSamplesPerChannel; + move16(); + } + +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + FOR( i = 0; i < inputAudio.config.numChannels; ++i ) + { + Word32 tmp; + + tmp = imult3216( L_deposit_l( numSamplesToPush ), i ); + p_read_channels[i] = inputAudio.data_fx + tmp; + } + ivas_TD_RINGBUF_PushChannels( inputBase->delayBuffer, p_read_channels, numSamplesToPush ); + + FOR( i = 0; i < inputAudio.config.numChannels; ++i ) + { + Word32 tmp; + + tmp = imult3216( L_deposit_l( numSamplesToPop ), i ); + p_write_channels[i] = inputBase->inputBuffer.data_fx + tmp; + } + ivas_TD_RINGBUF_PopChannels( inputBase->delayBuffer, p_write_channels, numSamplesToPop ); +#else + ivas_TD_RINGBUF_Push( inputBase->delayBuffer, inputAudio.data_fx, numSamplesToPush ); + ivas_TD_RINGBUF_Pop( inputBase->delayBuffer, inputBase->inputBuffer.data_fx, numSamplesToPop ); +#endif + } + ELSE + { + /* delay buffer isn't open - we don't need it */ + mvl2l( inputAudio.data_fx, + inputBase->inputBuffer.data_fx, + i_mult( inputAudio.config.numSamplesPerChannel, inputAudio.config.numChannels ) ); + } + + return IVAS_ERR_OK; +} + static ivas_error initIsmMasaRendering( input_ism *inputIsm, const Word32 inSampleRate ) @@ -1607,6 +1981,7 @@ static void clearInputIsm( rendCtx = inputIsm->base.ctx; freeInputBaseBufferData_fx( &inputIsm->base.inputBuffer.data_fx ); + ivas_TD_RINGBUF_Close( &inputIsm->base.delayBuffer ); initRendInputBase_fx( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); @@ -2601,12 +2976,7 @@ static ivas_error initMcBinauralRendering( move32(); binauralDelayNs = L_max( binauralDelayNs, inputMc->tdRendWrapper.binaural_latency_ns ); - Word16 exp = 0; - move16(); - Word16 var1 = BASOP_Util_Divide3232_Scale( *inputMc->base.ctx.pOutSampleRate, 1000000000, &exp ); - Word32 var2 = L_shr_r( Mpy_32_32( binauralDelayNs, L_deposit_h( var1 ) ), negate( exp ) ); /* Q0 */ - inputMc->binauralDelaySmp = extract_l( var2 ); - move16(); + inputMc->binauralDelaySmp = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, binauralDelayNs ); // inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f ); IF( GT_16( inputMc->binauralDelaySmp, MAX_BIN_DELAY_SAMPLES ) ) @@ -2812,6 +3182,8 @@ static void clearInputMc( rendCtx = inputMc->base.ctx; freeMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx ); freeInputBaseBufferData_fx( &inputMc->bufferData_fx ); + ivas_TD_RINGBUF_Close( &inputMc->base.delayBuffer ); + initRendInputBase_fx( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); /* Free input's internal handles */ @@ -3103,7 +3475,7 @@ static ivas_error setRendInputActiveSba( return error; } - return error; + return IVAS_ERR_OK; } static void clearInputSba( @@ -3114,6 +3486,7 @@ static void clearInputSba( rendCtx = inputSba->base.ctx; freeInputBaseBufferData_fx( &inputSba->bufferData_fx ); + ivas_TD_RINGBUF_Close( &inputSba->base.delayBuffer ); initRendInputBase_fx( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); @@ -3203,6 +3576,7 @@ static void clearInputMasa( rendCtx = inputMasa->base.ctx; freeInputBaseBufferData_fx( &inputMasa->bufferData_fx ); + ivas_TD_RINGBUF_Close( &inputMasa->base.delayBuffer ); masaPrerendClose_fx( &inputMasa->hMasaPrerend ); @@ -3261,16 +3635,23 @@ ivas_error IVAS_REND_Open( } hIvasRend = *phIvasRend; + move32(); hIvasRend->sampleRateOut = outputSampleRate; + move32(); hIvasRend->outputConfig = outConfig; + move32(); hIvasRend->customLsOut = defaultCustomLs(); hIvasRend->hLimiter = NULL; + move32(); hIvasRend->efapOutWrapper.hEfap = NULL; + move32(); hIvasRend->efapOutWrapper.pCustomLsSetup = NULL; + move32(); hIvasRend->num_subframes = num_subframes; + move16(); /* Initialize limiter */ - IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) ) + IF( NE_32( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) ) { return error; } @@ -3328,27 +3709,39 @@ ivas_error IVAS_REND_Open( isar_init_split_rend_handles( hIvasRend->splitRendWrapper ); } -#ifdef TEMP_FIX_2088_MSAN_INIT_ERROR hIvasRend->splitRendEncBuffer.data_fx = NULL; -#endif + move32(); + hIvasRend->splitRendEncBuffer.config.is_cldfb = 0; + move16(); + hIvasRend->splitRendEncBuffer.config.numChannels = 0; + move16(); + hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = 0; + move16(); FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) { initRendInputBase_fx( &hIvasRend->inputsIsm[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 ); hIvasRend->inputsIsm[i].crendWrapper = NULL; + move32(); hIvasRend->inputsIsm[i].hReverb = NULL; + move32(); hIvasRend->inputsIsm[i].tdRendWrapper.hBinRendererTd = NULL; + move32(); FOR( j = 0; j < MAX_HEAD_ROT_POSES - 1; ++j ) { hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hBinRendererTd = NULL; + move32(); hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hHrtfTD = NULL; + move32(); } hIvasRend->inputsIsm[i].nonDiegeticPan = nonDiegeticPan; move16(); hIvasRend->inputsIsm[i].nonDiegeticPanGain_fx = nonDiegeticPanGain; move32(); hIvasRend->inputsIsm[i].hOMasa = NULL; + move32(); hIvasRend->inputsIsm[i].bufferData_fx = NULL; + move32(); } FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i ) @@ -3356,20 +3749,29 @@ ivas_error IVAS_REND_Open( initRendInputBase_fx( &hIvasRend->inputsMc[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 ); hIvasRend->inputsMc[i].efapInWrapper.hEfap = NULL; + move32(); hIvasRend->inputsMc[i].crendWrapper = NULL; + move32(); hIvasRend->inputsMc[i].hReverb = NULL; + move32(); hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL; + move32(); hIvasRend->inputsMc[i].bufferData_fx = NULL; + move32(); hIvasRend->inputsMc[i].lfeDelayBuffer_fx = NULL; + move32(); hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan; move16(); hIvasRend->inputsMc[i].nonDiegeticPanGain_fx = nonDiegeticPanGain; move32(); hIvasRend->inputsMc[i].hMcMasa = NULL; + move32(); FOR( j = 0; j < MAX_HEAD_ROT_POSES - 1; ++j ) { hIvasRend->inputsMc[i].splitTdRendWrappers[j].hBinRendererTd = NULL; + move32(); hIvasRend->inputsMc[i].splitTdRendWrappers[j].hHrtfTD = NULL; + move32(); } } @@ -3378,10 +3780,15 @@ ivas_error IVAS_REND_Open( initRendInputBase_fx( &hIvasRend->inputsSba[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 ); hIvasRend->inputsSba[i].crendWrapper = NULL; + move32(); hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend = NULL; + move32(); hIvasRend->inputsSba[i].cldfbRendWrapper.hHrtfFastConv = NULL; + move32(); hIvasRend->inputsSba[i].bufferData_fx = NULL; + move32(); hIvasRend->inputsSba[i].hDirAC = NULL; + move32(); } FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i ) @@ -3389,17 +3796,25 @@ ivas_error IVAS_REND_Open( initRendInputBase_fx( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 ); hIvasRend->inputsMasa[i].metadataHasBeenFed = false; + move16(); hIvasRend->inputsMasa[i].bufferData_fx = NULL; + move32(); hIvasRend->inputsMasa[i].hMasaPrerend = NULL; + move32(); hIvasRend->inputsMasa[i].hMasaExtRend = NULL; - move16(); + move32(); } hIvasRend->hHrtfs.hHrtfFastConv = NULL; + move32(); hIvasRend->hHrtfs.hHrtfParambin = NULL; + move32(); hIvasRend->hHrtfs.hHrtfTD = NULL; + move32(); hIvasRend->hHrtfs.hHrtfCrend = NULL; + move32(); hIvasRend->hHrtfs.hHrtfStatistics = NULL; + move32(); IF( asHrtfBinary ) { @@ -3534,7 +3949,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( hIvasRend->customLsOut = makeCustomLsSetup( layout ); /* Re-initialize limiter - number of output channels may have changed */ - IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) ) + IF( NE_32( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) ) { return error; } @@ -3595,7 +4010,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( * *-------------------------------------------------------------------*/ -ivas_error IVAS_REND_NumOutChannels( +ivas_error IVAS_REND_GetNumOutChannels( IVAS_REND_CONST_HANDLE hIvasRend, Word16 *numOutChannels ) { @@ -3876,7 +4291,7 @@ static Word16 getCldfbRendFlag( const IVAS_REND_AudioConfigType new_configType ) { Word16 i; - Word16 numMasaInputs = 0, numSbaInputs = 0, numIsmInputs = 0, numMcInputs = 0; + Word16 numMasaInputs = 0, numSbaInputs = 0; Word16 isCldfbRend; move16(); @@ -3887,6 +4302,11 @@ static Word16 getCldfbRendFlag( isCldfbRend = 0; move16(); + /* This function is called during three different phases of renderer processing: + * - IVAS_REND_AddInput() + * - IVAS_REND_FeedRenderConfig() + * - IVAS_REND_GetSplitBinauralBitstream() + * Only the last case can assume all inputs are present for the current frame to be rendered */ IF( hIvasRend->hRendererConfig != NULL ) { FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i ) @@ -3899,23 +4319,8 @@ static Word16 getCldfbRendFlag( numSbaInputs = add( numSbaInputs, ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1 ); move16(); } - FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) - { - numIsmInputs = add( numIsmInputs, ( hIvasRend->inputsIsm[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) ? 0 : 1 ); - move16(); - } - FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i ) - { - numMcInputs = add( numMcInputs, ( hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? 0 : 1 ); - move16(); - } - IF( GT_16( numIsmInputs, 0 ) || GT_16( numMcInputs, 0 ) ) - { - isCldfbRend = 0; - move16(); - } - ELSE IF( GT_16( numMasaInputs, 0 ) || ( GT_16( numSbaInputs, 0 ) && EQ_32( hIvasRend->hRendererConfig->split_rend_config.rendererSelection, IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) ) + IF( GT_16( numMasaInputs, 0 ) || ( GT_16( numSbaInputs, 0 ) && EQ_32( hIvasRend->hRendererConfig->split_rend_config.rendererSelection, IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) ) { isCldfbRend = 1; move16(); @@ -3927,12 +4332,12 @@ static Word16 getCldfbRendFlag( /*------------------------------------------------------------------------- - * Function ivas_pre_rend_init() + * Function isar_pre_rend_init() * * *------------------------------------------------------------------------*/ -static ivas_error ivas_pre_rend_init( +static ivas_error isar_pre_rend_init( SPLIT_REND_WRAPPER *pSplitRendWrapper, IVAS_REND_AudioBuffer *pSplitRendEncBuffer, ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config, @@ -3942,11 +4347,21 @@ static ivas_error ivas_pre_rend_init( const Word16 cldfb_in_flag, const Word16 num_subframes ) { + bool realloc; ivas_error error; IVAS_REND_AudioBufferConfig bufConfig; + realloc = false; + + /* only perform init if split rendering output */ test(); - IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) + IF( NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) + { + return IVAS_ERR_OK; + } + + /* these functions should only be called once during initial allocation */ + IF( pSplitRendEncBuffer->data_fx == NULL ) { IF( EQ_32( pSplit_rend_config->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) ) { @@ -3961,41 +4376,51 @@ static ivas_error ivas_pre_rend_init( { return error; } + } - /*allocate for CLDFB in and change to TD during process if needed*/ - bufConfig.numSamplesPerChannel = MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL; - bufConfig.numChannels = i_mult( BINAURAL_CHANNELS, pSplitRendWrapper->multiBinPoseData.num_poses ); - bufConfig.is_cldfb = 1; - pSplitRendEncBuffer->config = bufConfig; + /* We may need to change the allocated buffer size if a new input is added. + * If the cldfb_in_flag is different from what was previously allocated for the buffer, change the size */ + test(); + IF( pSplitRendEncBuffer->data_fx != NULL && ( NE_16( cldfb_in_flag, pSplitRendEncBuffer->config.is_cldfb ) ) ) + { + realloc = true; + } + + test(); + IF( pSplitRendEncBuffer->data_fx == NULL || NE_16( realloc, 0 ) ) + { + /* set buffer config */ + bufConfig.is_cldfb = cldfb_in_flag; move16(); + + bufConfig.numSamplesPerChannel = L_FRAME_MAX; move16(); + IF( NE_16( cldfb_in_flag, 0 ) ) + { + bufConfig.numSamplesPerChannel = MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL; + move16(); + } + + bufConfig.numChannels = i_mult( BINAURAL_CHANNELS, pSplitRendWrapper->multiBinPoseData.num_poses ); move16(); + pSplitRendEncBuffer->config = bufConfig; move32(); + /* allocate memory */ + IF( NE_16( realloc, 0 ) ) + { + free( pSplitRendEncBuffer->data_fx ); + } + IF( ( pSplitRendEncBuffer->data_fx = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( Word32 ) ) ) == NULL ) { return IVAS_ERR_FAILED_ALLOC; } pSplitRendEncBuffer->q_factor = 0; - pSplitRendEncBuffer->pq_fact = &pSplitRendEncBuffer->q_factor; - } - ELSE - { - IVAS_REND_AudioBufferConfig bufConfig2; - - bufConfig2.numSamplesPerChannel = 0; - bufConfig2.numChannels = 0; - bufConfig2.is_cldfb = 0; - pSplitRendEncBuffer->config = bufConfig2; - pSplitRendEncBuffer->data_fx = NULL; - pSplitRendEncBuffer->pq_fact = NULL; - pSplitRendEncBuffer->q_factor = 0; - move16(); move16(); + pSplitRendEncBuffer->pq_fact = &pSplitRendEncBuffer->q_factor; move16(); - move32(); - move32(); } return IVAS_ERR_OK; @@ -4023,7 +4448,11 @@ ivas_error IVAS_REND_AddInput_fx( Word32 inputStructSize; #endif ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA *, hrtf_handles *hrtfs ); + void ( *setInputDelay )( void *, bool ); Word32 inputIndex; + bool splitPreRendCldfb; + splitPreRendCldfb = false; + /* Validate function arguments */ test(); @@ -4032,15 +4461,23 @@ ivas_error IVAS_REND_AddInput_fx( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - IF( ( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) && hIvasRend->splitRendEncBuffer.data_fx == NULL && hIvasRend->hRendererConfig != NULL ) + IF( hIvasRend->hRendererConfig != NULL ) { Word16 cldfb_in_flag; cldfb_in_flag = getCldfbRendFlag( hIvasRend, getAudioConfigType( inConfig ) ); - IF( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) + IF( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper, + &hIvasRend->splitRendEncBuffer, + &hIvasRend->hRendererConfig->split_rend_config, + hIvasRend->headRotData, hIvasRend->sampleRateOut, + hIvasRend->outputConfig, cldfb_in_flag, + hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) { return error; } + + /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/ + splitPreRendCldfb = EQ_32( hIvasRend->hRendererConfig->split_rend_config.codec, ISAR_SPLIT_REND_CODEC_LCLD ); } @@ -4058,6 +4495,7 @@ ivas_error IVAS_REND_AddInput_fx( inputStructSize = sizeof( *hIvasRend->inputsIsm ); #endif activateInput = setRendInputActiveIsm; + setInputDelay = setRendInputDelayIsm; move32(); move32(); BREAK; @@ -4068,6 +4506,7 @@ ivas_error IVAS_REND_AddInput_fx( inputStructSize = sizeof( *hIvasRend->inputsMc ); #endif activateInput = setRendInputActiveMc; + setInputDelay = setRendInputDelayMc; move32(); move32(); BREAK; @@ -4078,6 +4517,7 @@ ivas_error IVAS_REND_AddInput_fx( inputStructSize = sizeof( *hIvasRend->inputsSba ); #endif activateInput = setRendInputActiveSba; + setInputDelay = setRendInputDelaySba; move32(); move32(); BREAK; @@ -4088,6 +4528,7 @@ ivas_error IVAS_REND_AddInput_fx( inputStructSize = sizeof( *hIvasRend->inputsMasa ); #endif activateInput = setRendInputActiveMasa; + setInputDelay = setRendInputDelayMasa; move32(); move32(); BREAK; @@ -4116,6 +4557,15 @@ ivas_error IVAS_REND_AddInput_fx( return error; } +#ifdef CODE_IMPROVEMENTS + setInputDelay( getInputByIndex_fx( inputsArray, inputIndex, inputType ), splitPreRendCldfb ); +#else + setInputDelay( (Word8 *) inputsArray + inputStructSize * inputIndex, splitPreRendCldfb ); +#endif + + /* set global maximum delay after adding an input */ + setMaxGlobalDelayNs( hIvasRend ); + return IVAS_ERR_OK; } @@ -4476,141 +4926,25 @@ ivas_error IVAS_REND_GetDelay_fx( Word32 *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */ ) { - /* TODO tmu : this function only returns the maximum delay across all inputs - * Ideally each input has its own delay buffer and everything is aligned (binaural and LFE filtering delays are nonuniform) - */ - Word16 i; - Word32 latency_ns; Word32 max_latency_ns; - Word32 timescale_by_ns[7] = { 0, 17180, 34360, 0, 68719, 0, 103079 }; - move32(); - move32(); - move32(); - move32(); - move32(); - move32(); - move32(); - /* Validate function arguments */ test(); test(); IF( hIvasRend == NULL || nSamples == NULL || timeScale == NULL ) { - return IVAS_ERR_UNEXPECTED_NULL_POINTER; - } - - *timeScale = hIvasRend->sampleRateOut; - move32(); - assert( *timeScale == 8000 || *timeScale == 16000 || *timeScale == 32000 || *timeScale == 48000 ); - *nSamples = 0; - move16(); - max_latency_ns = 0; - move32(); - - /* Compute the maximum delay across all inputs */ - FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ ) - { - IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) ) - { - IF( hIvasRend->inputsIsm[i].crendWrapper != NULL ) - { - latency_ns = hIvasRend->inputsIsm[i].crendWrapper->binaural_latency_ns; - } - ELSE - { - latency_ns = 0; - } - move32(); - - latency_ns = L_max( latency_ns, hIvasRend->inputsIsm[i].tdRendWrapper.binaural_latency_ns ); - max_latency_ns = L_max( max_latency_ns, latency_ns ); - } - } - - FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ ) - { - IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) ) - { - IF( ( hIvasRend->inputsMc[i].crendWrapper != NULL ) ) - { - latency_ns = hIvasRend->inputsMc[i].crendWrapper->binaural_latency_ns; - } - ELSE - { - latency_ns = 0; - } - move32(); - - latency_ns = L_max( latency_ns, hIvasRend->inputsMc[i].tdRendWrapper.binaural_latency_ns ); - max_latency_ns = L_max( max_latency_ns, latency_ns ); - } - } - - FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ ) - { - IF( NE_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) ) - { - test(); - IF( hIvasRend->splitRendWrapper != NULL && hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL ) - { - IF( EQ_32( hIvasRend->hRendererConfig->split_rend_config.rendererSelection, IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) - { - latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns; - move32(); - } - ELSE - { - IF( ( hIvasRend->inputsSba[i].crendWrapper != NULL ) ) - { - latency_ns = hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns; - } - ELSE - { - latency_ns = 0; - } - move32(); - } - max_latency_ns = L_max( max_latency_ns, latency_ns ); - } - ELSE IF( hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend != NULL ) - { - latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns; - move32(); - latency_ns = L_add( latency_ns, IVAS_FB_DEC_DELAY_NS ); - max_latency_ns = L_max( max_latency_ns, latency_ns ); - } - ELSE - { - IF( hIvasRend->inputsSba[i].crendWrapper != NULL ) - { - latency_ns = hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns; - } - ELSE - { - latency_ns = 0; - } - move32(); - max_latency_ns = L_max( max_latency_ns, latency_ns ); - } - } - } - - FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ ) - { - IF( NE_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) ) - { - latency_ns = (Word32) ( IVAS_FB_DEC_DELAY_NS ); - move32(); - max_latency_ns = L_max( max_latency_ns, latency_ns ); - } + return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - //*nSamples = (Word16) roundf( (float) max_latency_ns * *timeScale / 1000000000.f ); - Word32 temp = Mpy_32_32( *timeScale, 268436 ); // Q0 + Q31 - Q31 -> Q0, ( 1 / 8000 ) * 2 ^ 31 - *nSamples = extract_l( Mpy_32_32_r( max_latency_ns, timescale_by_ns[temp] ) ); + *nSamples = 0; move16(); + *timeScale = hIvasRend->sampleRateOut; + move32(); + max_latency_ns = getMaxGlobalDelayNs( hIvasRend ); + + *nSamples = latencyNsToSamples( hIvasRend->sampleRateOut, max_latency_ns ); + return IVAS_ERR_OK; } @@ -4622,14 +4956,16 @@ ivas_error IVAS_REND_GetDelay_fx( *-------------------------------------------------------------------*/ ivas_error IVAS_REND_FeedInputAudio_fx( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - const IVAS_REND_InputId inputId, /* i : ID of the input */ - const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + const IVAS_REND_InputId inputId, /* i : ID of the input */ + const IVAS_REND_ReadOnlyAudioBuffer inputAudio, /* i : buffer with input audio */ + const bool flushInputs /* i : flush input audio */ ) { ivas_error error; input_base *inputBase; Word16 numInputChannels; + /* Note: this is called cldfb2tdSampleFact in float */ Word16 cldfb2tdShift; /* Validate function arguments */ @@ -4693,7 +5029,16 @@ ivas_error IVAS_REND_FeedInputAudio_fx( inputBase->inputBuffer.config = inputAudio.config; - MVR2R_WORD32( inputAudio.data_fx, inputBase->inputBuffer.data_fx, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels ); + if ( ( error = alignInputDelay( + inputBase, + inputAudio, + hIvasRend->maxGlobalDelayNs, + hIvasRend->sampleRateOut, + cldfb2tdShift, + flushInputs ) ) != IVAS_ERR_OK ) + { + return error; + } inputBase->numNewSamplesPerChannel = shr( inputAudio.config.numSamplesPerChannel, cldfb2tdShift ); move32(); @@ -5102,6 +5447,7 @@ ivas_error IVAS_REND_FeedRenderConfig( { Word16 cldfb_in_flag; cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); + IF( hIvasRend->splitRendWrapper != NULL ) { ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer ); @@ -5109,7 +5455,7 @@ ivas_error IVAS_REND_FeedRenderConfig( hIvasRend->splitRendWrapper = NULL; } - IF( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) + IF( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) { return error; } @@ -5956,7 +6302,7 @@ static ivas_error renderIsmToBinaural( push_wmops( "renderIsmToBinaural" ); /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = extract_l( Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, 429496730 /* 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) ); + ism_md_subframe_update_ext = extract_l( Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, ONE_BY_SUBFRAME_LEN_MS_Q31 ) ); copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpTDRendBuffer ); FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i ) @@ -6226,7 +6572,7 @@ static ivas_error renderIsmToBinauralReverb( push_wmops( "renderIsmToBinauralRoom" ); /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = extract_l( Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, 429496730 /* 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) ); + ism_md_subframe_update_ext = extract_l( Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, ONE_BY_SUBFRAME_LEN_MS_Q31 ) ); copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx ); FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i ) @@ -6479,8 +6825,10 @@ static ivas_error renderIsmToSplitBinaural( const SPLIT_REND_WRAPPER *pSplitRendWrapper; IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES]; IVAS_QUATERNION localHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES]; - Word16 i; + Word16 i, ch, slot_idx, num_bands; Word32 tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; + Word32 tmpBinaural_CldfbRe[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word32 tmpBinaural_CldfbIm[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; Word16 output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel; COMBINED_ORIENTATION_HANDLE pCombinedOrientationData; Word16 ism_md_subframe_update_ext, exp; @@ -6557,6 +6905,7 @@ static ivas_error renderIsmToSplitBinaural( IF( ismInput->hReverb != NULL ) { + exp = add( exp, 2 ); FOR( i = 0; i < BINAURAL_CHANNELS; i++ ) { FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ ) @@ -6566,10 +6915,35 @@ static ivas_error renderIsmToSplitBinaural( } } } - /* Copy rendered audio to tmp storage buffer. Copying directly to output would - * overwrite original audio, which is still needed for rendering next head pose. */ - Copy32( tmpProcessing[0], tmpBinaural[i_mult( 2, pos_idx )], output_frame ); - Copy32( tmpProcessing[1], tmpBinaural[add( i_mult( 2, pos_idx ), 1 )], output_frame ); + + IF( NE_16( outAudio.config.is_cldfb, 0 ) ) + { + /* Perform CLDFB analysis on rendered audio, since the output buffer is CLDFB domain */ + Word16 q_cldfb; + + q_cldfb = exp; + num_bands = extract_l( Mpy_32_32( imult3216( *ismInput->base.ctx.pOutSampleRate, BINAURAL_MAXBANDS ), 44740 /* 1/48000 in Q31 */ ) ); /* Q0 */ + FOR( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) + { + FOR( slot_idx = 0; slot_idx < IVAS_CLDFB_NO_COL_MAX; slot_idx++ ) + { + cldfbAnalysis_ts_fx( &tmpProcessing[ch][num_bands * slot_idx], + &tmpBinaural_CldfbRe[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0], + &tmpBinaural_CldfbIm[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0], + num_bands, + ismInput->base.ctx.pSplitRendWrapper->hCldfbHandles->cldfbAna[pos_idx + ch], + &q_cldfb ); + } + } + } + ELSE + { + + /* Copy rendered audio to tmp storage buffer. Copying directly to output would + * overwrite original audio, which is still needed for rendering next head pose. */ + Copy32( tmpProcessing[0], tmpBinaural[i_mult( 2, pos_idx )], output_frame ); + Copy32( tmpProcessing[1], tmpBinaural[add( i_mult( 2, pos_idx ), 1 )], output_frame ); + } /* Overwrite processing buffer with original input audio again */ copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpProcessing ); @@ -6581,7 +6955,14 @@ static ivas_error renderIsmToSplitBinaural( Copy_Quat_fx( &originalHeadRot[i], &pCombinedOrientationData->Quaternions[i] ); } - accumulate2dArrayToBuffer_fx( tmpBinaural, &outAudio ); + if ( outAudio.config.is_cldfb ) + { + accumulateCLDFBArrayToBuffer_fx( tmpBinaural_CldfbRe, tmpBinaural_CldfbIm, &outAudio ); + } + else + { + accumulate2dArrayToBuffer_fx( tmpBinaural, &outAudio ); + } pop_wmops(); /* Encoding to split rendering bitstream done at a higher level */ @@ -6637,6 +7018,8 @@ static ivas_error renderInputIsm( { ivas_error error; IVAS_REND_AudioBuffer inAudio; + /* Note: in float this is called cldfb2tdSampleFact - it is either 2 or 1, so we handle it as a shift here */ + Word16 cldfb2tdSampleShift; Word16 exp = *outAudio.pq_fact; move16(); @@ -6644,7 +7027,16 @@ static ivas_error renderInputIsm( move32(); inAudio = ismInput->base.inputBuffer; - IF( NE_32( ismInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) ) + /* Note: in float this is a factor, so it is 1 or 2 there instead of 0 or 1 here */ + cldfb2tdSampleShift = 0; + move16(); + IF( outAudio.config.is_cldfb ) + { + cldfb2tdSampleShift = 1; + move16(); + } + + IF( NE_32( L_shl( ismInput->base.numNewSamplesPerChannel, cldfb2tdSampleShift ), 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" ); } @@ -6794,7 +7186,7 @@ static ivas_error renderLfeToBinaural_fx( num_cpy_smpl_cur_frame = sub( frame_size, num_cpy_smpl_prev_frame ); /* Assuming LFE should be delayed by less that the duration of one frame */ - assert( mcInput->binauralDelaySmp < frame_size ); + assert( mcInput->binauralDelaySmp <= MAX_BIN_DELAY_SAMPLES ); /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */ v_multc_fx( mcInput->lfeDelayBuffer_fx, gain_fx, tmpLfeBuffer, num_cpy_smpl_prev_frame ); /* Qx - 1 */ @@ -8735,7 +9127,7 @@ ivas_error IVAS_REND_SetTotalNumberOfObjects( ivas_error IVAS_REND_SetIsmMetadataDelay( IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ - const Word32 sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */ + const Word16 sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */ ) { Word16 i; @@ -8747,7 +9139,7 @@ ivas_error IVAS_REND_SetIsmMetadataDelay( FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) { hIvasRend->inputsIsm[i].ism_metadata_delay_ms_fx = sync_md_delay; - move32(); + move16(); } return IVAS_ERR_OK; @@ -8761,15 +9153,13 @@ ivas_error IVAS_REND_SetIsmMetadataDelay( *-------------------------------------------------------------------*/ static ivas_error getSamplesInternal( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */ - IVAS_REND_BitstreamBuffer *hBits /* i/o: buffer for input/output bitstream. Needed in split rendering */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ ) { ivas_error error; Word16 numOutChannels; Word16 cldfb2tdSampleShift; - IVAS_REND_AudioBuffer outAudioOrig; /* Validate function arguments */ test(); @@ -8878,40 +9268,21 @@ static ivas_error getSamplesInternal( } } - IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) ) + IF( NE_32( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) ) { return error; } - IF( NE_16( numOutChannels, outAudio.config.numChannels ) && NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) + IF( NE_16( numOutChannels, outAudio.config.numChannels ) && + NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && + NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) { return IVAS_ERR_WRONG_NUM_CHANNELS; } - /* Clear original output buffer */ + /* Clear output buffer */ set32_fx( outAudio.data_fx, 0, imult1616( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ) ); - outAudioOrig = outAudio; - - /* Use internal buffer if outputting split rendering bitstream */ - test(); - IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || - EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) - { - Word16 num_poses_orig; - num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; - move16(); - outAudio.config = hIvasRend->splitRendEncBuffer.config; - outAudio.data_fx = hIvasRend->splitRendEncBuffer.data_fx; - - ISAR_PRE_REND_GetMultiBinPoseData( &hIvasRend->hRendererConfig->split_rend_config, &hIvasRend->splitRendWrapper->multiBinPoseData, hIvasRend->headRotData.sr_pose_pred_axis ); - - assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" ); - - /* Clear output buffer for split rendering bitstream */ - set32_fx( outAudio.data_fx, 0, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); - } - IF( NE_32( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ), IVAS_ERR_OK ) ) { return error; @@ -8929,220 +9300,301 @@ static ivas_error getSamplesInternal( return error; } - test(); - IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) + return IVAS_ERR_OK; +} + + +/*-------------------------------------------------------------------* + * IVAS_REND_GetSamples() + * + * + *-------------------------------------------------------------------*/ +ivas_error IVAS_REND_GetSamples( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ +) +{ + ivas_error error; + + IF( ( error = getSamplesInternal( hIvasRend, outAudio ) ) != IVAS_ERR_OK ) { - ISAR_SPLIT_REND_BITS_DATA bits; - Word16 cldfb_in_flag, i, j, k, ch, ro_md_flag; - Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; - Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + return error; + } + + + IF( EQ_16( outAudio.config.is_cldfb, 0 ) ) + { + Word32 limiter_threshold = L_lshl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact ); +#ifndef DISABLE_LIMITER + limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_threshold, *outAudio.pq_fact ); +#endif + } + + /* update global cominbed orientation start index */ + ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel ); + + return IVAS_ERR_OK; +} - FOR( i = 0; i < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; i++ ) - { - FOR( j = 0; j < CLDFB_NO_COL_MAX; j++ ) - { - FOR( k = 0; k < CLDFB_NO_CHANNELS_MAX; k++ ) - { - Cldfb_RealBuffer_Binaural[i][j][k] = 0; - Cldfb_ImagBuffer_Binaural[i][j][k] = 0; - move32(); - move32(); - } - } - } - Word32 *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; -#ifdef FIX_1119_SPLIT_RENDERING_VOIP /* Temporary fix. Proper implementation of port 391 can only be added once port 369 is complete. */ - Word32 *p_Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; - Word32 *p_Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; +/*-------------------------------------------------------------------* + * IVAS_REND_GetSplitBinauralBitstream() + * + * + *-------------------------------------------------------------------*/ + +ivas_error IVAS_REND_GetSplitBinauralBitstream( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */ + IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */ +) +{ + ivas_error error; + Word16 ch; + Word16 cldfb_in_flag; + Word16 i, ro_md_flag; + Word16 num_poses_orig; + Word32 *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; + Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + IVAS_REND_AudioBufferConfig *pSplitEncBufConfig; + ISAR_SPLIT_REND_CONFIG_HANDLE pSplitRendConfig; + ISAR_SPLIT_REND_BITS_DATA bits; + Word16 max_bands; + Word16 Q_out[2]; + Word16 pcm_out_flag; +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + Word32 *p_Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; + Word32 *p_Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX]; + Word16 j; - FOR( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i ) + FOR( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i ) + { + FOR( j = 0; j < CLDFB_NO_COL_MAX; ++j ) { - FOR( j = 0; j < CLDFB_NO_COL_MAX; ++j ) - { - p_Cldfb_RealBuffer_Binaural[i][j] = Cldfb_RealBuffer_Binaural[i][j]; - p_Cldfb_ImagBuffer_Binaural[i][j] = Cldfb_ImagBuffer_Binaural[i][j]; - } + p_Cldfb_RealBuffer_Binaural[i][j] = Cldfb_RealBuffer_Binaural[i][j]; + p_Cldfb_ImagBuffer_Binaural[i][j] = Cldfb_ImagBuffer_Binaural[i][j]; } + } #endif - FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ ) - { - tmpBinaural[ch] = tmpBinaural_buff[ch]; - move32(); - } + max_bands = 0; + move16(); - IF( EQ_16( outAudio.config.is_cldfb, 1 ) ) - { - cldfb_in_flag = 1; - move16(); - copyBufferToCLDFBarray_fx( outAudio, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural ); - } - ELSE - { - cldfb_in_flag = 0; - move16(); - copyBufferTo2dArray_fx( outAudio, tmpBinaural_buff ); - } + Q_out[0] = Q31; + move16(); + Q_out[1] = Q31; + move16(); - /* Encode split rendering bitstream */ - convertBitsBufferToInternalBitsBuff( *hBits, &bits ); + pcm_out_flag = 0; + move16(); - ro_md_flag = 0; + if ( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) + { + pcm_out_flag = 1; move16(); - FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) - { - IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) ) - { - ro_md_flag = 1; - move16(); - break; - } - } + } - Word16 q1 = 31, q2 = 31, Q_buff; - Word16 Q_out[CLDFB_NO_COL_MAX]; - Q_out[0] = 31; - Word16 num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; + FOR( ch = 0; ch < i_mult( MAX_HEAD_ROT_POSES, BINAURAL_CHANNELS ); ch++ ) + { + tmpBinaural[ch] = tmpBinaural_buff[ch]; + } - FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ ) - { - FOR( j = 0; j < CLDFB_NO_COL_MAX; j++ ) - { - q1 = s_min( q1, L_norm_arr( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) ); - q2 = s_min( q2, L_norm_arr( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) ); - } - } - Q_buff = s_min( q1, q2 ); - FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ ) - { - FOR( j = 0; j < CLDFB_NO_COL_MAX; j++ ) - { - scale_sig32( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff ); - scale_sig32( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff ); - } - } - Q_buff = Q_buff + *outAudio.pq_fact; + cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); + pSplitEncBufConfig = &hIvasRend->splitRendEncBuffer.config; + pSplitRendConfig = &hIvasRend->hRendererConfig->split_rend_config; - IF( EQ_16( cldfb_in_flag, 0 ) ) - { - /*TD input*/ - num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; + *hIvasRend->splitRendEncBuffer.pq_fact = *outAudio.pq_fact; + move16(); + hIvasRend->splitRendEncBuffer.q_factor = outAudio.q_factor; + move16(); - FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i ) - { - Q_out[0] = s_min( Q_out[0], L_norm_arr( tmpBinaural_buff[i], L_FRAME48k ) ); - } + /* 0 DoF / No pose correction retains frame size */ + pSplitEncBufConfig->is_cldfb = cldfb_in_flag; + move16(); - FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i ) - { - scale_sig32( tmpBinaural_buff[i], L_FRAME48k, Q_out[0] ); - } + test(); + IF( EQ_16( pSplitRendConfig->dof, 0 ) || EQ_32( pSplitRendConfig->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) ) + { + pSplitEncBufConfig->numSamplesPerChannel = outAudio.config.numSamplesPerChannel; + move16(); + } + /* Pose correction requires 20ms */ + ELSE + { + pSplitEncBufConfig->numSamplesPerChannel = shl( div_l( hIvasRend->sampleRateOut, FRAMES_PER_SEC ), 1 ); + } + + /* Note: float was "pSplitEncBufConfig->numSamplesPerChannel *= cldfb_in_flag ? 2 : 1;" */ + IF( NE_16( cldfb_in_flag, 0 ) ) + { + pSplitEncBufConfig->numSamplesPerChannel = shl( pSplitEncBufConfig->numSamplesPerChannel, 1 ); + } + + num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; + move16(); + + ISAR_PRE_REND_GetMultiBinPoseData( pSplitRendConfig, + &hIvasRend->splitRendWrapper->multiBinPoseData, + hIvasRend->headRotData.sr_pose_pred_axis ); + assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" ); + + /* hIvasRend->splitRendEncBuffer contains multi-pose data for BINAURAL_SPLIT_CODED output + outAudio used later for main pose BINAURAL_SPLIT_PCM output */ + IF( ( error = getSamplesInternal( hIvasRend, hIvasRend->splitRendEncBuffer ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* copy outputs */ + IF( EQ_16( hIvasRend->splitRendEncBuffer.config.is_cldfb, 1 ) ) + { + cldfb_in_flag = 1; + move16(); + copyBufferToCLDFBarray_fx( hIvasRend->splitRendEncBuffer, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural ); + } + ELSE + { + cldfb_in_flag = 0; + move16(); + copyBufferTo2dArray_fx( hIvasRend->splitRendEncBuffer, tmpBinaural_buff ); + } + *outAudio.pq_fact = *hIvasRend->splitRendEncBuffer.pq_fact; + + /* Encode split rendering bitstream */ + convertBitsBufferToInternalBitsBuff( *hBits, &bits ); + + ro_md_flag = 0; + move16(); + FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) + { + IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) ) + { + ro_md_flag = 1; - Q_out[0] = Q_out[0] + *outAudio.pq_fact; + break; } + } #ifdef FIX_1119_SPLIT_RENDERING_VOIP - IF( NE_32( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, hIvasRend->headRotData.headPositions[0], hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, hIvasRend->hRendererConfig->split_rend_config.codec, - hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms, - hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms, - &bits, - p_Cldfb_RealBuffer_Binaural, p_Cldfb_ImagBuffer_Binaural, - extract_l( Mpy_32_32( hIvasRend->sampleRateOut, 2684355 /*(BINAURAL_MAXBANDS / 48000) in Q31*/ ) ), tmpBinaural, 1, cldfb_in_flag, extract_l( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ), ro_md_flag, Q_buff, &Q_out[0] ) ), - IVAS_ERR_OK ) ) + Word16 q1 = 31, q2 = 31, Q_buff; #else - IF( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, hIvasRend->headRotData.headPositions[0], hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, hIvasRend->hRendererConfig->split_rend_config.codec, - hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms, - hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms, - &bits, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, extract_l( Mpy_32_32( hIvasRend->sampleRateOut, 2684355 /*(BINAURAL_MAXBANDS / 48000) in Q31*/ ) ), tmpBinaural, 1, cldfb_in_flag, ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, ro_md_flag, Q_buff, &Q_out[0] ) ) != IVAS_ERR_OK ) + Word16 q1 = 31, q2 = 31, Q_buff, j; #endif + Word16 num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; + + FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ ) + { + FOR( j = 0; j < CLDFB_NO_COL_MAX; j++ ) { - return error; + q1 = s_min( q1, L_norm_arr( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) ); + q2 = s_min( q2, L_norm_arr( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) ); } - - Word16 pcm_out_flag = ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0; - IF( NE_16( pcm_out_flag, 0 ) ) + } + Q_buff = s_min( q1, q2 ); + FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ ) + { + FOR( j = 0; j < CLDFB_NO_COL_MAX; j++ ) { - FOR( j = 0; j < BINAURAL_CHANNELS; j++ ) - { - scale_sig32( tmpBinaural_buff[j], L_FRAME48k, sub( *outAudio.pq_fact, Q_out[j] ) ); // *outAudio.pq_fact - } + scale_sig32( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff ); + scale_sig32( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff ); } + } + Q_buff = Q_buff + *outAudio.pq_fact; - convertInternalBitsBuffToBitsBuffer( hBits, bits ); + IF( EQ_16( cldfb_in_flag, 0 ) ) + { + /*TD input*/ + num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; - /* reset to outAudioOrig in case of PCM output */ - outAudio.config = outAudioOrig.config; - outAudio.data_fx = outAudioOrig.data_fx; + FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i ) + { + Q_out[0] = s_min( Q_out[0], L_norm_arr( tmpBinaural_buff[i], L_FRAME48k ) ); + } - IF( NE_16( pcm_out_flag, 0 ) ) + FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i ) { - accumulate2dArrayToBuffer_fx( tmpBinaural_buff, &outAudio ); + scale_sig32( tmpBinaural_buff[i], L_FRAME48k, Q_out[0] ); } + + Q_out[0] = Q_out[0] + *outAudio.pq_fact; } - IF( outAudio.config.is_cldfb == 0 ) - { - Word32 limiter_thresold = L_lshl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact ); -#ifndef DISABLE_LIMITER - limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_thresold, *outAudio.pq_fact ); + max_bands = extract_l( Mpy_32_32( imult3216( hIvasRend->sampleRateOut, BINAURAL_MAXBANDS ), 44740 /* 1/48000 in Q31 */ ) ); +#ifdef FIX_1119_SPLIT_RENDERING_VOIP + IF( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, + hIvasRend->headRotData.headPositions[0], + pSplitRendConfig->splitRendBitRate, + pSplitRendConfig->codec, + pSplitRendConfig->isar_frame_size_ms, + pSplitRendConfig->codec_frame_size_ms, + &bits, + p_Cldfb_RealBuffer_Binaural, + p_Cldfb_ImagBuffer_Binaural, + max_bands, + tmpBinaural, + 1, + cldfb_in_flag, + pcm_out_flag, + ro_md_flag, + Q_buff, + Q_out ) ) != IVAS_ERR_OK ) +#else + IF( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, + hIvasRend->headRotData.headPositions[0], + pSplitRendConfig->splitRendBitRate, + pSplitRendConfig->codec, + pSplitRendConfig->isar_frame_size_ms, + pSplitRendConfig->codec_frame_size_ms, + &bits, + Cldfb_RealBuffer_Binaural, + Cldfb_ImagBuffer_Binaural, + max_bands, + tmpBinaural, + 1, + cldfb_in_flag, + pcm_out_flag, + ro_md_flag, + Q_buff, + Q_out ) ) != IVAS_ERR_OK ) #endif + { + return error; } - /* update global cominbed orientation start index */ - ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel ); - - return IVAS_ERR_OK; -} - - -/*-------------------------------------------------------------------* - * IVAS_REND_GetSamples() - * - * - *-------------------------------------------------------------------*/ - -ivas_error IVAS_REND_GetSamples( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ -) -{ - return getSamplesInternal( hIvasRend, outAudio, NULL ); -} - - -/*-------------------------------------------------------------------* - * IVAS_REND_GetSplitBinauralBitstream() - * - * - *-------------------------------------------------------------------*/ - -ivas_error IVAS_REND_GetSplitBinauralBitstream( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */ - IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */ -) -{ - Word16 cldfb_in_flag; + IF( pcm_out_flag ) + { + FOR( j = 0; j < BINAURAL_CHANNELS; j++ ) + { + scale_sig32( tmpBinaural_buff[j], L_FRAME48k, sub( *outAudio.pq_fact, Q_out[j] ) ); // *outAudio.pq_fact + } + } - cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); - hIvasRend->splitRendEncBuffer.config.is_cldfb = cldfb_in_flag; + convertInternalBitsBuffToBitsBuffer( hBits, bits ); - test(); - if ( hIvasRend->hRendererConfig->split_rend_config.dof == 0 || hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) + /* copy over first pose data to outAudio */ + IF( pcm_out_flag ) { - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = outAudio.config.numSamplesPerChannel; + /* set outAudio to zero - getSamplesInternal only cleared splitRendEncBuffer */ + set_zero_fx( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ) ); + accumulate2dArrayToBuffer_fx( tmpBinaural_buff, &outAudio ); } - else + + IF( EQ_16( outAudio.config.is_cldfb, 0 ) ) { - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = (Word16) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC ); + Word32 limiter_threshold = L_lshl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact ); +#ifndef DISABLE_LIMITER +#ifdef DEBUGGING + hIvasRend->numClipping += +#endif + limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_threshold, *outAudio.pq_fact ); +#endif } - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel *= cldfb_in_flag ? 2 : 1; + /* update global cominbed orientation start index */ + ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel ); - /* hIvasRend->splitRendEncBuffer used for BINAURAL_SPLIT_CODED output - outAudio used for BINAURAL_SPLIT_PCM output */ - return getSamplesInternal( hIvasRend, outAudio, hBits ); + return IVAS_ERR_OK; }