diff --git a/Workspace_msvc/lib_rend.vcxproj b/Workspace_msvc/lib_rend.vcxproj
index c39806d47edcb1f3165b7ddbdcd9643b9e71c6ec..5f78402ecd215c7a91047758c05e9d1dc2c1a271 100644
--- a/Workspace_msvc/lib_rend.vcxproj
+++ b/Workspace_msvc/lib_rend.vcxproj
@@ -175,6 +175,7 @@
+
@@ -209,4 +210,4 @@
-
\ No newline at end of file
+
diff --git a/apps/renderer.c b/apps/renderer.c
index adf664f97d7fe88cbfcf087f98d6106becc71ff2..2d7ba3c8dd3a1135fa999f85ad4c721188a3515f 100644
--- a/apps/renderer.c
+++ b/apps/renderer.c
@@ -31,6 +31,7 @@
*******************************************************************************************************/
#include "lib_rend.h"
+#include "typedef.h"
#include
#include
#include
@@ -797,6 +798,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;
@@ -842,8 +844,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;
@@ -1173,7 +1178,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;
@@ -1490,7 +1498,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;
@@ -1505,8 +1513,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 ) );
@@ -1519,36 +1535,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 );
@@ -1693,19 +1688,26 @@ 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;
+ }
+ else
+ {
+ memset( inBuffer.data_fx, 0, inBuffer.config.numChannels * inBuffer.config.numSamplesPerChannel * sizeof( Word32 ) );
+ }
int16_t num_subframes, sf_idx;
num_subframes = (int16_t) args.render_framesize;
- if ( isCurrentFrameMultipleOf20ms )
+ if ( isCurrentFrameMultipleOf20ms && !flushRendererLastFrame )
{
IsmPositionProvider_getNextFrame( positionProvider, &mtdBuffer );
@@ -1817,7 +1819,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;
@@ -1831,7 +1833,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;
@@ -1847,7 +1849,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;
@@ -1870,7 +1872,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;
@@ -1887,13 +1889,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 )
{
@@ -1956,7 +1958,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 )
@@ -1966,7 +1968,7 @@ int main(
}
}
- if ( audioWriter != NULL )
+ if ( audioWriter != NULL && !flushRendererLastFrame )
{
if ( delayNumSamples * num_out_channels < outBufferSize )
{
@@ -1987,7 +1989,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;
@@ -2059,7 +2061,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 )
@@ -2075,6 +2078,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 )
{
@@ -2087,12 +2097,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" );
@@ -2100,7 +2111,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" );
@@ -2110,7 +2120,8 @@ 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 ) ) );
}
@@ -3509,7 +3520,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 c64e593393ac550472f212fa6107e3ff0e497791..e59a27a46c74147f263fac7fcfafade2de68cb40 100644
--- a/lib_isar/lib_isar_post_rend.c
+++ b/lib_isar/lib_isar_post_rend.c
@@ -1735,12 +1735,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 da4f6542f69b0cfefab4404a2182a7672c1731d3..10adbea2d4aa27a67f68704f5b981037a92bd810 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_prot_rend_fx.h b/lib_rend/ivas_prot_rend_fx.h
index 512d4fd21d8de391b898979b6481250b0f605f5e..fe2f62ed4e21e787ec503122eb2d0e991a29e91c 100644
--- a/lib_rend/ivas_prot_rend_fx.h
+++ b/lib_rend/ivas_prot_rend_fx.h
@@ -33,6 +33,7 @@
#ifndef IVAS_PROT_REND_H
#define IVAS_PROT_REND_H
+#include "typedef.h"
#include
#include "options.h"
#include "ivas_error.h"
@@ -1594,6 +1595,40 @@ void ivas_rend_closeCldfbRend(
CLDFB_REND_WRAPPER *pCldfbRend
);
+/*----------------------------------------------------------------------------------*
+ * Time domain ring buffer prototypes
+ *----------------------------------------------------------------------------------*/
+
+ivas_error ivas_TD_RINGBUF_Open(
+ TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */
+ const UWord32 capacity_per_channel, /* i : Number of samples stored per channel */
+ const UWord16 num_channels /* i : Number of channels */
+);
+
+void ivas_TD_RINGBUF_Close(
+ TD_RINGBUF_HANDLE *ph /* i/o: Ring buffer handle */
+);
+
+void ivas_TD_RINGBUF_Push(
+ TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */
+ const Word32 *data, /* i : Input data */
+ const UWord32 num_samples_per_channel /* i : Number of samples per channel to store */
+);
+
+void ivas_TD_RINGBUF_PushZeros(
+ TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */
+ const UWord32 num_samples_per_channel /* i : Number of zeros per channel to store */
+);
+
+void ivas_TD_RINGBUF_Pop(
+ TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */
+ Word32 *data, /* i : Output data */
+ const UWord32 num_samples_per_channel /* i : Number of samples per channel to retrieve*/
+);
+
+uint32_t ivas_TD_RINGBUF_Size(
+ const TD_RINGBUF_HANDLE h /* i : Ring buffer handle */
+);
/* clang-format on */
diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h
index 85c4dedd2eb33676b4ac2164f52822fe262b8f10..48e3dd34903cfd457e8c63d9f8dbc62b3e5fcf6c 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"
@@ -1429,6 +1430,21 @@ typedef struct
} CLDFB_REND_WRAPPER;
+/*----------------------------------------------------------------------------------*
+ * Time domain ring buffer structure
+ *----------------------------------------------------------------------------------*/
+
+typedef struct
+{
+ Word32 *data; /* samples in interleaved layout */
+ UWord32 capacity;
+ UWord16 num_channels;
+ UWord32 write_pos;
+ UWord32 read_pos;
+ Word16 is_full;
+
+} TD_RINGBUF_DATA, *TD_RINGBUF_HANDLE;
+
/*----------------------------------------------------------------------------------*
* Limiter structure
*----------------------------------------------------------------------------------*/
diff --git a/lib_rend/ivas_td_ring_buffer_fx.c b/lib_rend/ivas_td_ring_buffer_fx.c
new file mode 100644
index 0000000000000000000000000000000000000000..0660bc5068e7098610d0b207c05a8e50f0fce423
--- /dev/null
+++ b/lib_rend/ivas_td_ring_buffer_fx.c
@@ -0,0 +1,346 @@
+/******************************************************************************************************
+
+ (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository. All Rights Reserved.
+
+ This software is protected by copyright law and by international treaties.
+ The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
+ Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
+ Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
+ Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
+ contributors to this repository retain full ownership rights in their respective contributions in
+ the software. This notice grants no license of any kind, including but not limited to patent
+ license, nor is any license granted by implication, estoppel or otherwise.
+
+ Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
+ contributions.
+
+ This software is provided "AS IS", without any express or implied warranties. The software is in the
+ development stage. It is intended exclusively for experts who have experience with such software and
+ solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
+ and fitness for a particular purpose are hereby disclaimed and excluded.
+
+ Any dispute, controversy or claim arising under or in relation to providing this software shall be
+ submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
+ accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
+ the United Nations Convention on Contracts on the International Sales of Goods.
+
+*******************************************************************************************************/
+
+#include "basop32.h"
+#include "move.h"
+#include "typedef.h"
+#include
+#include
+#include "ivas_error_utils.h"
+#include "ivas_prot_rend_fx.h"
+#include "wmc_auto.h"
+
+
+/*-----------------------------------------------------------------------*
+ * Local function prototypes
+ *-----------------------------------------------------------------------*/
+
+static UWord32 ivas_td_ringbuf_total_size(
+ TD_RINGBUF_HANDLE h )
+{
+ UWord32 total_size;
+
+ IF( h->is_full )
+ {
+ total_size = h->capacity;
+ }
+
+ IF( h->read_pos <= h->write_pos )
+ {
+ total_size = L_sub( h->write_pos, h->read_pos );
+ }
+ /* else wrap around */
+ total_size = L_add( h->write_pos, L_sub( h->capacity, h->read_pos ) );
+
+ return total_size;
+}
+
+
+static Word16 ivas_td_ringbuf_has_space_for_num_samples(
+ TD_RINGBUF_HANDLE h,
+ const UWord32 num_samples )
+{
+ // float was : return (Word16) ( ivas_td_ringbuf_total_size( h ) + num_samples <= h->capacity );
+ Word16 has_space;
+ UWord32 total_size_after;
+
+ move16();
+ has_space = 0;
+
+ total_size_after = L_add( ivas_td_ringbuf_total_size( h ), num_samples );
+ IF( LE_32( total_size_after, h->capacity ) )
+ {
+ has_space = 1;
+ }
+ return has_space;
+}
+
+
+/*-----------------------------------------------------------------------*
+ * Global function definitions
+ *-----------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------*
+ * ivas_TD_RINGBUF_Open()
+ *
+ * Allocate a ring buffer for TD data with the given capacity of TD samples per channel.
+ *
+ * May return IVAS_ERR_FAILED_ALLOC on failed allocation, or IVAS_ERR_OK otherwise.
+ *---------------------------------------------------------------------*/
+
+ivas_error ivas_TD_RINGBUF_Open(
+ TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */
+ const UWord32 capacity_per_channel, /* i : Number of samples stored per channel */
+ const UWord16 num_channels /* i : Number of channels */
+)
+{
+ TD_RINGBUF_HANDLE h;
+ UWord32 capacity;
+
+ // TODO: how to integer multiplication 32 x 16 ?
+ capacity = L_mult0( capacity_per_channel, num_channels );
+
+ h = malloc( sizeof( TD_RINGBUF_DATA ) );
+ IF( h == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for TD ring buffer\n" );
+ }
+ // TODO: move for pointer assignment?
+ h->data = NULL;
+ move32();
+ h->capacity = 0;
+ move16();
+ h->num_channels = num_channels;
+ move32();
+ h->write_pos = 0;
+ move32();
+ h->read_pos = 0;
+ move16();
+ h->is_full = 0;
+ // TODO: move for pointer assignment?
+ *ph = h;
+
+ h->data = malloc( capacity * sizeof( Word32 ) );
+ IF( h->data == NULL )
+ {
+ return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for TD ring buffer\n" );
+ }
+
+ move32();
+ h->capacity = capacity;
+
+ return IVAS_ERR_OK;
+}
+
+
+/*---------------------------------------------------------------------*
+ * ivas_TD_RINGBUF_Close()
+ *
+ * Dellocate TD ring buffer. The given handle will be set to NULL.
+
+ *---------------------------------------------------------------------*/
+
+void ivas_TD_RINGBUF_Close(
+ TD_RINGBUF_HANDLE *ph /* i/o: Ring buffer handle */
+)
+{
+ TD_RINGBUF_HANDLE h;
+
+ IF( ph == NULL )
+ {
+ return;
+ }
+ // TODO: move for pointer assignment?
+ h = *ph;
+
+ IF( h == NULL )
+ {
+ return;
+ }
+
+ IF( h->data != NULL )
+ {
+ free( h->data );
+ }
+
+ free( h );
+ // TODO: move for pointer assignment?
+ *ph = NULL;
+
+ return;
+}
+
+
+/*---------------------------------------------------------------------*
+ * ivas_TD_RINGBUF_Push()
+ *
+ * Push samples onto the back of the TD ring buffer.
+ * Returns total number of buffered samples (includes number of channels)
+ *---------------------------------------------------------------------*/
+
+void ivas_TD_RINGBUF_Push(
+ TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */
+ const Word32 *data, /* i : Input data */
+ const UWord32 num_samples_per_channel /* i : Number of samples per channel to store */
+)
+{
+ UWord32 s;
+ UWord16 c;
+
+ // TODO: integer multiplication for 32 * 16?
+ assert( ivas_td_ringbuf_has_space_for_num_samples( h, L_mult0( num_samples_per_channel, h->num_channels ) ) );
+
+ FOR( s = 0; s < num_samples_per_channel; ++s )
+ {
+ FOR( c = 0; c < h->num_channels; ++c )
+ {
+ UWord32 shift_val;
+
+ /* pointer is advance by c * num_samples_per_channel + s */
+ shift_val = L_mult0( c, num_samples_per_channel );
+ shift_val = L_add( s, shift_val );
+
+ // TODO: move for pointer assignment?
+ h->data[h->write_pos] = *( data + shift_val );
+ ++h->write_pos;
+
+ IF( EQ_32( h->write_pos, h->capacity ) )
+ {
+ move32();
+ h->write_pos = 0;
+ }
+ }
+ }
+
+ IF( EQ_32( h->read_pos, h->write_pos ) )
+ {
+ move32();
+ h->is_full = 1;
+ }
+
+ return;
+}
+
+
+/*---------------------------------------------------------------------*
+ * ivas_TD_RINGBUF_PushZeros()
+ *
+ * Push zero samples onto the back of the TD ring buffer.
+ *---------------------------------------------------------------------*/
+
+void ivas_TD_RINGBUF_PushZeros(
+ TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */
+ const UWord32 num_samples_per_channel /* i : Number of zeros per channel to store */
+)
+{
+ UWord32 s;
+ UWord16 c;
+
+ // TODO: integer multiplication for 32 * 16?
+ assert( ivas_td_ringbuf_has_space_for_num_samples( h, L_mult0( num_samples_per_channel, h->num_channels ) ) );
+ IF( EQ_32( num_samples_per_channel, 0 ) )
+ {
+ return;
+ }
+
+ FOR( s = 0; s < num_samples_per_channel; ++s )
+ {
+ FOR( c = 0; c < h->num_channels; ++c )
+ {
+ // TODO: move for pointer assignment?
+ h->data[h->write_pos] = 0;
+ ++h->write_pos;
+
+ IF( EQ_32( h->write_pos, h->capacity ) )
+ {
+ move32();
+ h->write_pos = 0;
+ }
+ }
+ }
+
+ IF( EQ_32( h->read_pos, h->write_pos ) )
+ {
+ move32();
+ h->is_full = 1;
+ }
+
+ return;
+}
+
+
+/*---------------------------------------------------------------------*
+ * ivas_TD_RINGBUF_Pop()
+ *
+ * Pop samples from the front of the TD ring buffer.
+ *---------------------------------------------------------------------*/
+
+void ivas_TD_RINGBUF_Pop(
+ TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */
+ Word32 *data, /* i : Output data */
+ const UWord32 num_samples_per_channel /* i : Number of samples per channel to retrieve */
+)
+{
+ UWord32 s;
+ UWord16 c;
+ Word32 requested_samples;
+
+ // TODO
+ requested_samples = L_mult0( num_samples_per_channel, h->num_channels );
+ assert( GE_32( ivas_td_ringbuf_total_size( h ), requested_samples ) );
+
+ FOR( s = 0; s < num_samples_per_channel; ++s )
+ {
+ FOR( c = 0; c < h->num_channels; ++c )
+ {
+ UWord32 shift_val;
+
+ /* pointer is advanced by c * num_samples_per_channel + s */
+ shift_val = L_mult0( c, num_samples_per_channel );
+ shift_val = L_add( s, shift_val );
+
+ *( data + shift_val ) = h->data[h->read_pos];
+ ++h->read_pos;
+
+ IF( EQ_32( h->write_pos, h->capacity ) )
+ {
+ move32();
+ h->write_pos = 0;
+ }
+ }
+ }
+
+ IF( NE_16( h->is_full, 0 ) )
+ {
+ move16();
+ h->is_full = 0;
+ }
+
+ return;
+}
+
+
+/*---------------------------------------------------------------------*
+ * ivas_TD_RINGBUF_Size()
+ *
+ * Returns number of buffered samples per channel.
+ *---------------------------------------------------------------------*/
+
+UWord32 ivas_TD_RINGBUF_Size(
+ const TD_RINGBUF_HANDLE h /* i : Ring buffer handle */
+)
+{
+ UWord32 size;
+
+ size = div_l( ivas_td_ringbuf_total_size( h ), h->num_channels );
+ return size;
+}
diff --git a/lib_rend/lib_rend.h b/lib_rend/lib_rend.h
index 1f46ca932d417270d2b8a2c80c03061291959156..ec447df7a2695692209827995b9c9f78afaf7eb1 100644
--- a/lib_rend/lib_rend.h
+++ b/lib_rend/lib_rend.h
@@ -129,7 +129,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 */
);
@@ -213,7 +213,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 */
);
@@ -222,7 +222,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(
@@ -397,7 +398,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 edf3231d7be3739e313b2a223dc81e1fbaca4fa4..72023e4083ecf0bc5f7960c6ab51e7c4416418ba 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,7 @@
#include "ivas_cnst.h"
#include "ivas_rom_com.h"
#include "ivas_rom_rend.h"
+#include "stl.h"
#include
#include
#include
@@ -90,6 +96,7 @@ typedef struct
typedef struct
{
const Word32 *pOutSampleRate;
+ const Word32 *pMaxGlobalDelayNs;
const AUDIO_CONFIG *pOutConfig;
const LSSETUP_CUSTOM_STRUCT *pCustomLsOut;
const EFAP_WRAPPER *pEfapOutWrapper;
@@ -106,9 +113,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 */
+ Word32 delayNumSamples;
} input_base;
typedef struct
@@ -209,6 +218,7 @@ typedef struct hrtf_handles
struct IVAS_REND
{
Word32 sampleRateOut;
+ Word32 maxGlobalDelayNs;
IVAS_LIMITER_HANDLE hLimiter;
input_ism inputsIsm[RENDERER_MAX_ISM_INPUTS];
@@ -221,10 +231,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;
@@ -267,6 +277,7 @@ static ivas_error allocateInputBaseBufferData_fx(
return IVAS_ERR_OK;
}
+
static void freeInputBaseBufferData_fx(
Word32 **data /* Qx */ )
{
@@ -278,6 +289,17 @@ static void freeInputBaseBufferData_fx(
return;
}
+
+static Word16 latencyNsToSamples(
+ Word32 sampleRate,
+ Word32 latency_ns )
+{
+ Word16 n_samples;
+
+ n_samples = NS2SA_FX2( sampleRate, latency_ns );
+ return n_samples;
+}
+
static ivas_error allocateMcLfeDelayBuffer_fx(
Word32 **lfeDelayBuffer, /* Qx */
const Word16 data_size )
@@ -290,6 +312,7 @@ static ivas_error allocateMcLfeDelayBuffer_fx(
return IVAS_ERR_OK;
}
+
static void freeMcLfeDelayBuffer_fx(
Word32 **lfeDelayBuffer /* Qx */ )
{
@@ -404,7 +427,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;
@@ -1285,6 +1308,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;
@@ -1339,6 +1365,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;
@@ -1383,6 +1410,318 @@ 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();
+ 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 cldfb2tdSampleFact,
+ const bool flushInputs )
+{
+ ivas_error error;
+ input_ism *inputIsm;
+ Word16 maxGlobalDelaySamples;
+ Word32 numSamplesToPush, numSamplesToPop;
+ UWord32 ringBufferSize, preDelay;
+
+ maxGlobalDelaySamples = latencyNsToSamples( sampleRateOut, maxGlobalDelayNs );
+ maxGlobalDelaySamples = i_mult( maxGlobalDelaySamples, cldfb2tdSampleFact );
+
+ /* 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 = maxGlobalDelaySamples - inputBase->delayNumSamples * cldfb2tdSampleFact;
+ preDelay = sub( maxGlobalDelaySamples,
+ i_mult( inputBase->delayNumSamples, cldfb2tdSampleFact ) );
+
+ 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 */
+ ivas_TD_RINGBUF_PushZeros( inputBase->delayBuffer, preDelay );
+
+ /* for ISM inputs, ensure the metadata sync delay is updated */
+ IF( getAudioConfigType( inputBase->inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED )
+ {
+ inputIsm = (input_ism *) inputBase;
+ inputIsm->ism_metadata_delay_ms_fx = Mpy_32_32( maxGlobalDelayNs /* Q0 */, 2147 /* (1 / 1e6f) in Q31 */ );
+ }
+ }
+ }
+
+ 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;
+ move32();
+
+ numSamplesToPop = ivas_TD_RINGBUF_Size( inputBase->delayBuffer );
+ }
+ ELSE
+ {
+ numSamplesToPush = inputAudio.config.numSamplesPerChannel;
+ move32();
+
+ numSamplesToPop = (Word32) inputAudio.config.numSamplesPerChannel;
+ move32();
+ }
+
+ ivas_TD_RINGBUF_Push( inputBase->delayBuffer, inputAudio.data_fx, numSamplesToPush );
+ ivas_TD_RINGBUF_Pop( inputBase->delayBuffer, inputBase->inputBuffer.data_fx, numSamplesToPop );
+ }
+ 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 )
@@ -1615,6 +1954,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 );
@@ -2609,12 +2949,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 ) )
@@ -2820,6 +3155,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 */
@@ -3120,7 +3457,7 @@ static ivas_error setRendInputActiveSba(
return error;
}
- return error;
+ return IVAS_ERR_OK;
}
static void clearInputSba(
@@ -3131,6 +3468,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 );
@@ -3220,6 +3558,7 @@ static void clearInputMasa(
rendCtx = inputMasa->base.ctx;
freeInputBaseBufferData_fx( &inputMasa->bufferData_fx );
+ ivas_TD_RINGBUF_Close( &inputMasa->base.delayBuffer );
masaPrerendClose_fx( &inputMasa->hMasaPrerend );
@@ -3287,7 +3626,7 @@ ivas_error IVAS_REND_Open(
hIvasRend->num_subframes = num_subframes;
/* 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;
}
@@ -3345,6 +3684,11 @@ ivas_error IVAS_REND_Open(
isar_init_split_rend_handles( hIvasRend->splitRendWrapper );
}
+ hIvasRend->splitRendEncBuffer.data_fx = NULL;
+ hIvasRend->splitRendEncBuffer.config.is_cldfb = 0;
+ hIvasRend->splitRendEncBuffer.config.numChannels = 0;
+ hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = 0;
+
FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
{
@@ -3552,7 +3896,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;
}
@@ -3613,7 +3957,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout(
*
*-------------------------------------------------------------------*/
-ivas_error IVAS_REND_NumOutChannels(
+ivas_error IVAS_REND_GetNumOutChannels(
IVAS_REND_CONST_HANDLE hIvasRend,
Word16 *numOutChannels )
{
@@ -3843,7 +4187,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();
@@ -3854,6 +4198,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 )
@@ -3866,23 +4215,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();
@@ -3894,12 +4228,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,
@@ -3909,11 +4243,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 ) )
{
@@ -3928,41 +4272,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( float ) ) ) == 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();
+ pSplitRendEncBuffer->pq_fact = &pSplitRendEncBuffer->q_factor;
move16();
- move16();
- move32();
- move32();
}
return IVAS_ERR_OK;
@@ -3986,7 +4340,11 @@ ivas_error IVAS_REND_AddInput_fx(
void *inputsArray;
Word32 inputStructSize;
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();
@@ -3995,17 +4353,24 @@ 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 );
SWITCH( getAudioConfigType( inConfig ) )
{
@@ -4014,6 +4379,7 @@ ivas_error IVAS_REND_AddInput_fx(
inputsArray = hIvasRend->inputsIsm;
inputStructSize = sizeof( *hIvasRend->inputsIsm );
activateInput = setRendInputActiveIsm;
+ setInputDelay = setRendInputDelayIsm;
move32();
move32();
BREAK;
@@ -4022,6 +4388,7 @@ ivas_error IVAS_REND_AddInput_fx(
inputsArray = hIvasRend->inputsMc;
inputStructSize = sizeof( *hIvasRend->inputsMc );
activateInput = setRendInputActiveMc;
+ setInputDelay = setRendInputDelayMc;
move32();
move32();
BREAK;
@@ -4030,6 +4397,7 @@ ivas_error IVAS_REND_AddInput_fx(
inputsArray = hIvasRend->inputsSba;
inputStructSize = sizeof( *hIvasRend->inputsSba );
activateInput = setRendInputActiveSba;
+ setInputDelay = setRendInputDelaySba;
move32();
move32();
BREAK;
@@ -4038,6 +4406,7 @@ ivas_error IVAS_REND_AddInput_fx(
inputsArray = hIvasRend->inputsMasa;
inputStructSize = sizeof( *hIvasRend->inputsMasa );
activateInput = setRendInputActiveMasa;
+ setInputDelay = setRendInputDelayMasa;
move32();
move32();
BREAK;
@@ -4058,6 +4427,15 @@ ivas_error IVAS_REND_AddInput_fx(
return error;
}
+#ifdef CODE_IMPROVEMENTS
+ setInputDelay( getInputByIndex( 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;
}
@@ -4373,175 +4751,61 @@ ivas_error IVAS_REND_GetInputNumChannels(
*
*
*-------------------------------------------------------------------*/
-ivas_error IVAS_REND_GetNumAllObjects(
- IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
- Word16 *numChannels /* o : number of all objects */
-)
-{
- test();
- IF( hIvasRend == NULL || numChannels == NULL )
- {
- return IVAS_ERR_UNEXPECTED_NULL_POINTER;
- }
-
- test();
- IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
- {
- *numChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
- move16();
- }
-
- return IVAS_ERR_OK;
-}
-
-
-/*-------------------------------------------------------------------*
- * IVAS_REND_GetDelay()
- *
- *
- *-------------------------------------------------------------------*/
-
-ivas_error IVAS_REND_GetDelay_fx(
- IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer state */
- Word16 *nSamples, /* o : Renderer delay in samples */
- 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 );
- }
- }
+ivas_error IVAS_REND_GetNumAllObjects(
+ IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
+ Word16 *numChannels /* o : number of all objects */
+)
+{
+ test();
+ IF( hIvasRend == NULL || numChannels == NULL )
+ {
+ return IVAS_ERR_UNEXPECTED_NULL_POINTER;
}
- FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
+ test();
+ IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
{
- 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 );
- }
+ *numChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
+ move16();
+ }
+
+ return IVAS_ERR_OK;
+}
+
+
+/*-------------------------------------------------------------------*
+ * IVAS_REND_GetDelay()
+ *
+ *
+ *-------------------------------------------------------------------*/
+
+ivas_error IVAS_REND_GetDelay_fx(
+ IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer state */
+ Word16 *nSamples, /* o : Renderer delay in samples */
+ Word32 *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */
+)
+{
+ Word32 max_latency_ns;
+
+ /* Validate function arguments */
+ test();
+ test();
+ IF( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
+ {
+ 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] ) );
+ assert( *timeScale == 8000 || *timeScale == 16000 || *timeScale == 32000 || *timeScale == 48000 );
+
+ *nSamples = 0;
move16();
+ *timeScale = hIvasRend->sampleRateOut;
+
+ max_latency_ns = getMaxGlobalDelayNs( hIvasRend );
+
+ *nSamples = latencyNsToSamples( hIvasRend->sampleRateOut, max_latency_ns );
+
return IVAS_ERR_OK;
}
@@ -4553,14 +4817,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 */
@@ -4619,7 +4885,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();
@@ -4943,6 +5218,7 @@ Word16 IVAS_REND_FeedRenderConfig(
if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL )
{
ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb );
+
IF( NE_32( ( error = ivas_binaural_reverb_init_fx( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL, NULL ) ), IVAS_ERR_OK ) )
{
return error;
@@ -4951,6 +5227,7 @@ Word16 IVAS_REND_FeedRenderConfig(
if ( pMasaInput->hMasaExtRend->hReverb != NULL )
{
ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hReverb );
+
IF( NE_32( ( error = ivas_binaural_reverb_init_fx( &pMasaInput->hMasaExtRend->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL, NULL ) ), IVAS_ERR_OK ) )
{
return error;
@@ -4975,6 +5252,7 @@ Word16 IVAS_REND_FeedRenderConfig(
return error;
}
}
+
if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL )
{
IF( NE_32( ( error = ivas_reverb_open_fx( &pMcInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
@@ -5021,6 +5299,7 @@ Word16 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 );
@@ -5028,7 +5307,7 @@ Word16 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;
}
@@ -6395,8 +6674,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;
@@ -6473,6 +6754,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++ )
@@ -6482,10 +6764,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 );
@@ -6497,7 +6804,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 */
@@ -6553,6 +6867,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();
@@ -6560,7 +6876,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" );
}
@@ -6710,7 +7035,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_fixed( mcInput->lfeDelayBuffer_fx, gain_fx, tmpLfeBuffer, num_cpy_smpl_prev_frame ); /* Qx - 1 */
@@ -8684,15 +9009,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();
@@ -8797,40 +9120,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;
@@ -8848,150 +9152,6 @@ 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 ) )
- {
- 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];
-
- 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];
-
- FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
- {
- tmpBinaural[ch] = tmpBinaural_buff[ch];
- move32();
- }
-
- 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 );
- }
-
- /* 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;
- 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 ( 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;
-
- IF( EQ_16( cldfb_in_flag, 0 ) )
- {
- /*TD input*/
- num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
-
- 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 ) );
- }
-
- FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i )
- {
- scale_sig32( tmpBinaural_buff[i], L_FRAME48k, Q_out[0] );
- }
-
- Q_out[0] = Q_out[0] + *outAudio.pq_fact;
- }
-
- 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,
-#ifdef FIX_2083_FLOATING_POINT_LEFTOVERS
- &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 )
-#else
- &bits, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, ( const Word16 )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), 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 )
-#endif
- {
- return error;
- }
-
- Word16 pcm_out_flag = ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0;
- IF( NE_16( pcm_out_flag, 0 ) )
- {
- FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
- {
- scale_sig32( tmpBinaural_buff[j], L_FRAME48k, sub( *outAudio.pq_fact, Q_out[j] ) ); // *outAudio.pq_fact
- }
- }
-
- convertInternalBitsBuffToBitsBuffer( hBits, bits );
-
- /* reset to outAudioOrig in case of PCM output */
- outAudio.config = outAudioOrig.config;
- outAudio.data_fx = outAudioOrig.data_fx;
-
- IF( NE_16( pcm_out_flag, 0 ) )
- {
- accumulate2dArrayToBuffer_fx( tmpBinaural_buff, &outAudio );
- }
- }
-
- 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 );
-#endif
- }
-
- /* update global cominbed orientation start index */
- ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
-
return IVAS_ERR_OK;
}
@@ -9001,13 +9161,31 @@ static ivas_error getSamplesInternal(
*
*
*-------------------------------------------------------------------*/
-
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_error error;
+
+ IF( ( error = getSamplesInternal( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+
+ IF( NE_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;
}
@@ -9023,25 +9201,149 @@ ivas_error IVAS_REND_GetSplitBinauralBitstream(
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];
+
+ max_bands = 0;
+ move16();
+
+ Q_out[0] = Q31;
+ move16();
+ Q_out[1] = Q31;
+ move16();
+
+ FOR( ch = 0; ch < i_mult( MAX_HEAD_ROT_POSES, BINAURAL_CHANNELS ); ch++ )
+ {
+ tmpBinaural[ch] = tmpBinaural_buff[ch];
+ }
cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
- hIvasRend->splitRendEncBuffer.config.is_cldfb = cldfb_in_flag;
+ pSplitEncBufConfig = &hIvasRend->splitRendEncBuffer.config;
+ pSplitRendConfig = &hIvasRend->hRendererConfig->split_rend_config;
+
+ /* 0 DoF / No pose correction retains frame size */
+ pSplitEncBufConfig->is_cldfb = cldfb_in_flag;
+ move16();
+
+ 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 = div_s( hIvasRend->sampleRateOut, FRAMES_PER_SEC );
+ }
- if ( hIvasRend->hRendererConfig->split_rend_config.dof == 0 || hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
+ /* Note: float was "pSplitEncBufConfig->numSamplesPerChannel *= cldfb_in_flag ? 2 : 1;" */
+ IF( NE_16( cldfb_in_flag, 0 ) )
{
- hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = outAudio.config.numSamplesPerChannel;
+ pSplitEncBufConfig->numSamplesPerChannel = shl( pSplitEncBufConfig->numSamplesPerChannel, 1 );
}
- else
+
+ 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( NE_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 );
+ }
+
+ /* 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;
+
+ break;
+ }
+ }
+
+ max_bands = extract_l( Mpy_32_32( imult3216( hIvasRend->sampleRateOut, BINAURAL_MAXBANDS ), 44740 /* 1/48000 in Q31 */ ) );
+ 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,
+ ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0,
+ ro_md_flag,
+ hIvasRend->splitRendEncBuffer.q_factor,
+ Q_out ) ) != IVAS_ERR_OK )
+ {
+ return error;
+ }
+
+ convertInternalBitsBuffToBitsBuffer( hBits, bits );
+
+ /* copy over first pose data to outAudio */
+ IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
+ {
+ /* 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 );
+ }
+
+ IF( EQ_16( outAudio.config.is_cldfb, 0 ) )
{
- hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = (Word16) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC );
+#ifndef DISABLE_LIMITER
+#ifdef DEBUGGING
+ hIvasRend->numClipping +=
+#endif
+ limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, IVAS_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;
}