Skip to content
......@@ -7,7 +7,7 @@
* estoppel or otherwise. *
******************************************************************************/
/*! \file lc3.h
/*! \file lc3plus.h
* This header provides the API for LC3plus.
*
* This library is targeting devices with extreme memory limitations, so memory management
......
......@@ -9,7 +9,7 @@
#include "options.h"
#include "wmc_auto.h"
#include "setup_dec_lc3.h"
#include "setup_dec_lc3plus.h"
#include "functions.h"
#include <stdio.h>
#include <assert.h>
......
......@@ -9,7 +9,7 @@
#include "options.h"
#include "wmc_auto.h"
#include "setup_enc_lc3.h"
#include "setup_enc_lc3plus.h"
#include "functions.h"
#include <stdio.h>
......
......@@ -1076,6 +1076,11 @@ ivas_error ivas_rend_initCrendWrapper(
( *pCrend )->binaural_latency_ns = 0;
( *pCrend )->hHrtfCrend = NULL;
for ( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
{
( *pCrend )->hCrend[pos_idx] = NULL;
}
for ( pos_idx = 0; pos_idx < num_poses; pos_idx++ )
{
hCrend = NULL;
......@@ -1340,8 +1345,7 @@ ivas_error ivas_rend_openCrend(
*------------------------------------------------------------------------*/
void ivas_rend_closeCrend(
CREND_WRAPPER_HANDLE *pCrend,
const int16_t num_poses )
CREND_WRAPPER_HANDLE *pCrend )
{
int16_t i;
int16_t pos_idx;
......@@ -1357,7 +1361,7 @@ void ivas_rend_closeCrend(
ivas_hrtf_close( &( *pCrend )->hHrtfCrend );
}
for ( pos_idx = 0; pos_idx < num_poses; pos_idx++ )
for ( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
{
hCrend = ( *pCrend )->hCrend[pos_idx];
if ( hCrend != NULL )
......@@ -1501,8 +1505,8 @@ static ivas_error ivas_rend_crendConvolver(
const float *pFreq_filt_re, *pFreq_filt_im;
float *pFreq_buf_re = NULL, *pFreq_buf_im = NULL;
float *pFreq_buf2_re = NULL, *pFreq_buf2_im = NULL;
float pOut[L_FRAME48k * 2];
float tmp_out_re[L_FRAME48k], tmp_out_im[L_FRAME48k];
float pOut[2 /*Re,Im*/ * L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
float tmp_out_re[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES], tmp_out_im[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
CREND_HANDLE hCrend;
ivas_error error;
......@@ -1708,7 +1712,8 @@ ivas_error ivas_rend_crendProcessSubframe(
int16_t subframe_idx, subframe_len;
int16_t nchan_out, nchan_in, ch, first_sf, last_sf, slot_size, slots_to_render;
float *tc_local[MAX_OUTPUT_CHANNELS];
float pcm_tmp[BINAURAL_CHANNELS][L_FRAME48k];
float *p_output[BINAURAL_CHANNELS];
float pcm_tmp[BINAURAL_CHANNELS][L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
float *p_pcm_tmp[BINAURAL_CHANNELS];
IVAS_REND_AudioConfigType inConfigType;
ivas_error error;
......@@ -1747,6 +1752,7 @@ ivas_error ivas_rend_crendProcessSubframe(
for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
{
p_pcm_tmp[ch] = pcm_tmp[ch];
p_output[ch] = output[ch];
}
if ( hTcBuffer != NULL )
......@@ -1827,10 +1833,6 @@ ivas_error ivas_rend_crendProcessSubframe(
{
tc_local[ch] += subframe_len;
}
for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
{
p_pcm_tmp[ch] += subframe_len;
}
if ( hTcBuffer != NULL )
{
......@@ -1842,14 +1844,16 @@ ivas_error ivas_rend_crendProcessSubframe(
return IVAS_ERR_INVALID_INPUT_FORMAT;
}
/* update combined orientation access index */
ivas_combined_orientation_update_index( hCombinedOrientationData, subframe_len );
for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
{
/* move to output */
mvr2r( pcm_tmp[ch], p_output[ch], subframe_len );
p_output[ch] += subframe_len;
}
/* move to output */
for ( ch = 0; ch < nchan_out; ch++ )
{
mvr2r( pcm_tmp[ch], output[ch], n_samples_to_render );
/* update combined orientation access index */
ivas_combined_orientation_update_index( hCombinedOrientationData, subframe_len );
}
if ( hTcBuffer != NULL )
......
......@@ -318,7 +318,15 @@ ivas_error ivas_dirac_dec_init_binaural_data(
int16_t nchan_to_allocate;
int16_t n_samples_granularity;
nchan_to_allocate = BINAURAL_CHANNELS;
if ( st_ivas->hDiracDecBin[0] != NULL && st_ivas->hDiracDecBin[0]->useTdDecorr )
{
nchan_to_allocate = 2 * BINAURAL_CHANNELS;
}
else if ( st_ivas->hOutSetup.separateChannelEnabled )
{
nchan_to_allocate++;
}
if ( st_ivas->ivas_format == MASA_ISM_FORMAT )
{
nchan_to_allocate = BINAURAL_CHANNELS + st_ivas->nchan_ism;
......@@ -444,8 +452,6 @@ void ivas_dirac_dec_binaural_render(
uint16_t nchan_out;
SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
float *output_f_local[MAX_OUTPUT_CHANNELS];
float output_f_local_buff[MAX_OUTPUT_CHANNELS][L_FRAME48k];
int16_t output_length;
hSpatParamRendCom = st_ivas->hSpatParamRendCom;
nchan_out = BINAURAL_CHANNELS;
......@@ -454,7 +460,7 @@ void ivas_dirac_dec_binaural_render(
#endif
for ( ch = 0; ch < nchan_out; ch++ )
{
output_f_local[ch] = output_f_local_buff[ch];
output_f_local[ch] = output_f[ch];
}
slot_size = NS2SA( st_ivas->hDecoderConfig->output_Fs, CLDFB_SLOT_NS );
......@@ -473,7 +479,6 @@ void ivas_dirac_dec_binaural_render(
#ifdef DEBUGGING
assert( slots_to_render == 0 );
#endif
output_length = 0;
for ( subframe_idx = first_sf; subframe_idx < last_sf; subframe_idx++ )
{
int16_t n_samples_sf = slot_size * hSpatParamRendCom->subframe_nbslots[subframe_idx];
......@@ -484,17 +489,10 @@ void ivas_dirac_dec_binaural_render(
output_f_local[ch] += n_samples_sf;
}
output_length += n_samples_sf;
/* update combined orientation access index */
ivas_combined_orientation_update_index( st_ivas->hCombinedOrientationData, n_samples_sf );
}
for ( ch = 0; ch < nchan_out; ch++ )
{
mvr2r( output_f_local_buff[ch], output_f[ch], output_length );
}
if ( hSpatParamRendCom->slots_rendered == hSpatParamRendCom->num_slots )
{
hSpatParamRendCom->dirac_read_idx = ( hSpatParamRendCom->dirac_read_idx + DEFAULT_JBM_SUBFRAMES_5MS ) % hSpatParamRendCom->dirac_md_buffer_length;
......
......@@ -482,13 +482,18 @@ static void ivas_omasa_dmx(
float g1, g2;
float data_out_f[MASA_MAX_TRANSPORT_CHANNELS][L_FRAME48k];
for ( i = 0; i < nchan_transport; i++ )
{
set_zero( data_out_f[i], input_frame );
}
for ( i = 0; i < nchan_ism; i++ )
{
if ( nchan_transport == 1 )
{
v_add( data_out_f[0], data_in_f[i], data_out_f[0], input_frame );
}
else
{
azimuth = ism_azimuth[i];
elevation = ism_elevation[i];
......@@ -510,6 +515,7 @@ static void ivas_omasa_dmx(
prev_gains[i][j] = gains[j];
}
}
}
for ( i = 0; i < nchan_transport; i++ )
{
......
......@@ -271,7 +271,7 @@ int16_t ivas_get_nchan_buffers_dec(
output_config = st_ivas->hDecoderConfig->output_config;
nchan_out_buff = MAX_OUTPUT_CHANNELS;
nchan_out_buff = st_ivas->nchan_transport;
if ( st_ivas->ivas_format == MONO_FORMAT )
{
......@@ -283,128 +283,72 @@ int16_t ivas_get_nchan_buffers_dec(
}
else if ( st_ivas->ivas_format == ISM_FORMAT )
{
nchan_out_buff = st_ivas->nchan_ism;
nchan_out_buff = max( st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_ism );
if ( output_config == IVAS_AUDIO_CONFIG_LS_CUSTOM )
{
nchan_out_buff = max( nchan_out_buff, st_ivas->hOutSetup.nchan_out_woLFE + st_ivas->hOutSetup.num_lfe );
}
else if ( output_config != IVAS_AUDIO_CONFIG_EXTERNAL )
if ( st_ivas->ism_mode == ISM_MODE_PARAM || output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
{
nchan_out_buff = max( audioCfg2channels( st_ivas->transport_config ), audioCfg2channels( st_ivas->intern_config ) );
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( output_config ) );
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( st_ivas->intern_config ) );
}
}
else if ( st_ivas->ivas_format == SBA_FORMAT )
{
int16_t nchan_internal;
nchan_internal = ivas_sba_get_nchan_metadata( sba_analysis_order, ivas_total_brate );
nchan_out_buff = st_ivas->hDecoderConfig->nchan_out;
if ( output_config == IVAS_AUDIO_CONFIG_LS_CUSTOM )
{
nchan_out_buff = max( nchan_out_buff, st_ivas->hOutSetup.nchan_out_woLFE + st_ivas->hOutSetup.num_lfe );
}
else if ( output_config != IVAS_AUDIO_CONFIG_EXTERNAL )
{
nchan_out_buff = max( audioCfg2channels( st_ivas->transport_config ), audioCfg2channels( st_ivas->intern_config ) );
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( output_config ) );
}
nchan_out_buff = max( nchan_out_buff, nchan_internal );
nchan_out_buff = max( nchan_internal, st_ivas->hDecoderConfig->nchan_out );
}
else if ( st_ivas->ivas_format == MASA_FORMAT )
{
nchan_out_buff = CPE_CHANNELS;
if ( output_config == IVAS_AUDIO_CONFIG_LS_CUSTOM )
{
nchan_out_buff = max( nchan_out_buff, st_ivas->hOutSetup.nchan_out_woLFE + st_ivas->hOutSetup.num_lfe );
}
else if ( output_config == IVAS_AUDIO_CONFIG_STEREO || output_config == IVAS_AUDIO_CONFIG_BINAURAL || output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR || output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || output_config == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
{
nchan_out_buff = 2 * CPE_CHANNELS;
}
else if ( output_config != IVAS_AUDIO_CONFIG_EXTERNAL )
{
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( st_ivas->intern_config ) );
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( output_config ) );
}
nchan_out_buff = max( st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_transport );
if ( output_config == IVAS_AUDIO_CONFIG_EXTERNAL && st_ivas->nchan_ism > 0 )
if ( st_ivas->hDiracDecBin[0] != NULL && st_ivas->hDiracDecBin[0]->useTdDecorr )
{
nchan_out_buff = st_ivas->nchan_ism + CPE_CHANNELS;
nchan_out_buff = 2 * BINAURAL_CHANNELS;
}
}
else if ( st_ivas->ivas_format == MASA_ISM_FORMAT )
{
nchan_out_buff = st_ivas->nchan_ism + CPE_CHANNELS;
if ( output_config == IVAS_AUDIO_CONFIG_LS_CUSTOM )
{
nchan_out_buff = max( nchan_out_buff, st_ivas->hOutSetup.nchan_out_woLFE + st_ivas->hOutSetup.num_lfe );
}
else if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC )
{
nchan_out_buff = max( nchan_out_buff, BINAURAL_CHANNELS + st_ivas->nchan_ism );
}
else if ( output_config != IVAS_AUDIO_CONFIG_EXTERNAL )
{
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( st_ivas->intern_config ) );
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( output_config ) );
}
nchan_out_buff = max( st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_transport + st_ivas->nchan_ism );
}
else if ( st_ivas->ivas_format == SBA_ISM_FORMAT )
{
int16_t nchan_internal;
nchan_internal = ivas_sba_get_nchan_metadata( sba_analysis_order, ivas_total_brate );
nchan_out_buff = st_ivas->nchan_ism + st_ivas->nchan_transport;
if ( st_ivas->hMCT != NULL )
if ( st_ivas->ism_mode == ISM_SBA_MODE_DISC )
{
nchan_out_buff = ( ( nchan_out_buff + 1 ) >> 1 ) << 1; /* ensure odd number of channels in MCT */
nchan_internal += st_ivas->nchan_ism;
}
if ( output_config == IVAS_AUDIO_CONFIG_LS_CUSTOM )
if ( st_ivas->hMCT != NULL )
{
nchan_out_buff = max( nchan_out_buff, st_ivas->hOutSetup.nchan_out_woLFE + st_ivas->hOutSetup.num_lfe );
nchan_internal = ( ( nchan_internal + 1 ) >> 1 ) << 1; /* ensure odd number of channels in MCT */
}
else if ( output_config != IVAS_AUDIO_CONFIG_EXTERNAL )
{
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( st_ivas->intern_config ) );
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( output_config ) );
if ( st_ivas->renderer_type == RENDERER_OSBA_AMBI || st_ivas->renderer_type == RENDERER_OSBA_LS )
{
nchan_out_buff = max( nchan_out_buff + st_ivas->nchan_ism, audioCfg2channels( output_config ) ); /* needed for ivas_sba_upmixer_renderer() */
}
else
nchan_out_buff = max( nchan_internal, st_ivas->hDecoderConfig->nchan_out );
if ( output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
{
nchan_out_buff = max( nchan_out_buff + st_ivas->nchan_ism, audioCfg2channels( output_config ) ); /* needed for ivas_spar_dec_upmixer_sf() which is based on 'nchan_out' */
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( st_ivas->intern_config ) );
}
}
else if ( output_config == IVAS_AUDIO_CONFIG_EXTERNAL )
else if ( st_ivas->ivas_format == MC_FORMAT )
{
nchan_out_buff = st_ivas->hDecoderConfig->nchan_out + st_ivas->nchan_ism; /*take into account sba_ch_idx' in ivas_dec() */
}
nchan_out_buff = max( st_ivas->hDecoderConfig->nchan_out, st_ivas->nchan_transport );
if ( !( output_config == IVAS_AUDIO_CONFIG_MONO || output_config == IVAS_AUDIO_CONFIG_STEREO ) )
if ( st_ivas->hOutSetup.separateChannelEnabled )
{
nchan_out_buff = max( nchan_out_buff, nchan_internal + st_ivas->nchan_ism );
nchan_out_buff = max( nchan_out_buff, st_ivas->nchan_transport + 1 );
}
nchan_out_buff = min( nchan_out_buff, MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS );
}
else if ( st_ivas->ivas_format == MC_FORMAT )
{
nchan_out_buff = st_ivas->hDecoderConfig->nchan_out;
if ( output_config == IVAS_AUDIO_CONFIG_LS_CUSTOM )
if ( st_ivas->hDiracDecBin[0] != NULL && st_ivas->hDiracDecBin[0]->useTdDecorr )
{
nchan_out_buff = max( nchan_out_buff, st_ivas->hOutSetup.nchan_out_woLFE + st_ivas->hOutSetup.num_lfe );
nchan_out_buff = 2 * BINAURAL_CHANNELS;
}
else if ( output_config != IVAS_AUDIO_CONFIG_EXTERNAL )
else
{
nchan_out_buff = max( audioCfg2channels( st_ivas->transport_config ), audioCfg2channels( st_ivas->intern_config ) );
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( output_config ) );
nchan_out_buff = max( nchan_out_buff, audioCfg2channels( st_ivas->intern_config ) );
}
}
......@@ -425,29 +369,66 @@ int16_t ivas_get_nchan_buffers_dec(
ivas_error ivas_output_buff_dec(
float *p_output_f[], /* i/o: output audio buffers */
const int16_t nchan_out_buff_old, /* i : previous frame number of output channels */
const int16_t nchan_out_buff /* i : number of output channels */
const int16_t nchan_out_buff, /* i : number of output channels */
const int16_t Opt_tsm, /* i : TSM option flag */
DECODER_TC_BUFFER_HANDLE hTcBuffer /* i : TSM buffer handle */
)
{
int16_t ch;
int16_t ch, nchan_tc_jbm, nsamp_to_allocate, n_samp_full, offset;
if ( nchan_out_buff > nchan_out_buff_old )
for ( ch = 0; ch < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; ch++ )
{
for ( ch = nchan_out_buff_old; ch < nchan_out_buff; ch++ )
p_output_f[ch] = NULL;
}
if ( hTcBuffer->tc_buffer2 != NULL )
{
/* note: these are intra-frame heap memories */
if ( ( p_output_f[ch] = (float *) malloc( ( 48000 / FRAMES_PER_SEC ) * sizeof( float ) ) ) == NULL ) /* note: 32000 == max internal sampling rate */
free( hTcBuffer->tc_buffer2 );
hTcBuffer->tc_buffer2 = NULL;
}
nchan_tc_jbm = 0;
if ( Opt_tsm )
{
return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for floating-point output audio buffer!\n" ) );
/* JBM decoding: output audio buffers are shared with audio buffers from 'hTcBuffer->tc[]' */
nchan_tc_jbm = max( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full );
}
if ( nchan_out_buff <= nchan_tc_jbm && !Opt_tsm )
{
for ( ch = 0; ch < nchan_out_buff; ch++ )
{
p_output_f[ch] = hTcBuffer->tc[ch];
}
}
else
{
for ( ch = nchan_out_buff; ch < nchan_out_buff_old; ch++ )
for ( ch = 0; ch < nchan_tc_jbm; ch++ )
{
free( p_output_f[ch] );
p_output_f[ch] = NULL;
p_output_f[ch] = hTcBuffer->tc[ch];
}
/* non-JBM decoding: allocate output audio buffers */
/* JBM decoding: when not enough audio buffers 'hTcBuffer->tc[]', allocate additional buffers */
n_samp_full = ( 48000 / FRAMES_PER_SEC );
nsamp_to_allocate = ( nchan_out_buff - nchan_tc_jbm ) * n_samp_full;
if ( nsamp_to_allocate > 0 )
{
/* note: these are intra-frame heap memories */
if ( ( hTcBuffer->tc_buffer2 = (float *) malloc( nsamp_to_allocate * sizeof( float ) ) ) == NULL )
{
return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for floating-point output audio buffer!\n" ) );
}
set_zero( hTcBuffer->tc_buffer2, nsamp_to_allocate );
}
offset = 0;
for ( ; ch < nchan_out_buff; ch++ )
{
p_output_f[ch] = &hTcBuffer->tc_buffer2[offset];
offset += n_samp_full;
}
}
......
......@@ -904,8 +904,7 @@ ivas_error ivas_rend_openCrend(
);
void ivas_rend_closeCrend(
CREND_WRAPPER_HANDLE *pCrend,
const int16_t num_poses
CREND_WRAPPER_HANDLE *pCrend
);
ivas_error ivas_Crend_hrtf_init(
......@@ -946,8 +945,7 @@ ivas_error ivas_binaural_reverb_init(
const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *roomAcoustics, /* i/o: room acoustics parameters */
const int32_t sampling_rate, /* i : sampling rate */
const float *defaultTimes, /* i : default reverberation times */
const float *defaultEne /* i : default reverberation energies */
,
const float *defaultEne, /* i : default reverberation energies */
float *earlyEne /* i/o: Early part energies to be modified */
);
......@@ -1583,6 +1581,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 uint32_t capacity_per_channel, /* i : Number of samples stored per channel */
const uint16_t 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 float *data, /* i : Input data */
const uint32_t 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 uint32_t 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 */
float *data, /* i : Output data */
const uint32_t 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 */
......
......@@ -79,10 +79,10 @@
#define MAX_NR_OUTPUTS ( 2 )
const int16_t init_loop_delay[IVAS_REV_MAX_NR_BRANCHES] = { 37, 31, 29, 23, 19, 17, 13, 11 };
const int16_t default_loop_delay_48k[IVAS_REV_MAX_NR_BRANCHES] = { 2309, 1861, 1523, 1259, 1069, 919, 809, 719 };
const int16_t default_loop_delay_32k[IVAS_REV_MAX_NR_BRANCHES] = { 1531, 1237, 1013, 839, 709, 613, 541, 479 };
const int16_t default_loop_delay_16k[IVAS_REV_MAX_NR_BRANCHES] = { 769, 619, 509, 421, 353, 307, 269, 239 };
static const int16_t init_loop_delay[IVAS_REV_MAX_NR_BRANCHES] = { 37, 31, 29, 23, 19, 17, 13, 11 };
static const int16_t default_loop_delay_48k[IVAS_REV_MAX_NR_BRANCHES] = { 2309, 1861, 1523, 1259, 1069, 919, 809, 719 };
static const int16_t default_loop_delay_32k[IVAS_REV_MAX_NR_BRANCHES] = { 1531, 1237, 1013, 839, 709, 613, 541, 479 };
static const int16_t default_loop_delay_16k[IVAS_REV_MAX_NR_BRANCHES] = { 769, 619, 509, 421, 353, 307, 269, 239 };
/*------------------------------------------------------------------------------------------*
* Local Struct definition
......@@ -682,8 +682,6 @@ static ivas_error initialize_reverb_filters(
{
ivas_error error;
error = IVAS_ERR_OK;
/* init correlation and coloration filters */
if ( ( error = ivas_reverb_t2f_f2t_init( &hReverb->fft_filter_ols, hReverb->fft_size, hReverb->fft_subblock_size ) ) != IVAS_ERR_OK )
{
......@@ -710,7 +708,7 @@ static ivas_error initialize_reverb_filters(
return error;
}
return error;
return IVAS_ERR_OK;
}
......@@ -1060,7 +1058,6 @@ ivas_error ivas_reverb_open(
int16_t fft_hist_size, transition_start, transition_length;
int16_t nr_fc_input, nr_fc_fft_filter;
error = IVAS_ERR_OK;
output_frame = (int16_t) ( output_Fs / FRAMES_PER_SEC );
subframe_len = output_frame / MAX_PARAM_SPATIAL_SUBFRAMES;
predelay_bf_len = output_frame;
......@@ -1240,7 +1237,7 @@ ivas_error ivas_reverb_open(
*hReverb = pState;
return error;
return IVAS_ERR_OK;
}
......@@ -1859,12 +1856,13 @@ static ivas_error ivas_binaural_reverb_open(
return IVAS_ERR_OK;
}
/*-------------------------------------------------------------------------
* ivas_binaural_reverb_init()
*
* Allocate and initialize binaural room reverberator handle
* for CLDFB renderers
* Initialize binaural room reverberator handle for FastConv renderer
*------------------------------------------------------------------------*/
ivas_error ivas_binaural_reverb_init(
REVERB_STRUCT_HANDLE *hReverbPr, /* i/o: binaural reverb handle */
const HRTFS_STATISTICS_HANDLE hHrtfStatistics, /* i : HRTF statistics handle */
......@@ -1873,8 +1871,7 @@ ivas_error ivas_binaural_reverb_init(
const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *roomAcoustics, /* i/o: room acoustics parameters */
const int32_t sampling_rate, /* i : sampling rate */
const float *defaultTimes, /* i : default reverberation times */
const float *defaultEne /* i : default reverberation energies */
,
const float *defaultEne, /* i : default reverberation energies */
float *earlyEne /* i/o: Early part energies to be modified */
)
{
......@@ -1883,24 +1880,23 @@ ivas_error ivas_binaural_reverb_init(
float revTimes[CLDFB_NO_CHANNELS_MAX];
float revEne[CLDFB_NO_CHANNELS_MAX];
error = IVAS_ERR_OK;
if ( roomAcoustics != NULL )
{
if ( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics,
hHrtfStatistics,
sampling_rate,
revTimes,
revEne ) ) != IVAS_ERR_OK )
if ( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics, hHrtfStatistics, sampling_rate, revTimes, revEne ) ) != IVAS_ERR_OK )
{
return error;
}
preDelay = (int16_t) roundf( 48000.0f * roomAcoustics->acousticPreDelay / CLDFB_NO_CHANNELS_MAX );
/* Convert preDelay from seconds to CLDFB slots as needed by binaural reverb */
preDelay = (int16_t) roundf( roomAcoustics->acousticPreDelay * CLDFB_SLOTS_PER_SECOND );
}
else
{
#ifdef FIX_1995_REVERB_INIT
for ( bin = 0; bin < numBins; bin++ )
#else
for ( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
#endif
{
revTimes[bin] = defaultTimes[bin];
revEne[bin] = defaultEne[bin];
......@@ -1908,7 +1904,11 @@ ivas_error ivas_binaural_reverb_init(
preDelay = 10;
}
#ifdef FIX_1995_REVERB_INIT
for ( bin = 0; bin < numBins; bin++ )
#else
for ( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
#endif
{
/* Adjust the room effect parameters when the reverberation time is less than a threshold value, to avoid
spectral artefacts with the synthetic reverberator. */
......@@ -1924,13 +1924,17 @@ ivas_error ivas_binaural_reverb_init(
energyModifier = ( adjustedRevTime - revTimes[bin] ) / adjustedRevTime;
/* Adjust early and late energies, by moving late energy to early energy */
if ( earlyEne != NULL )
{
adjustedEarlyEne = earlyEne[bin] + revEne[bin] * energyModifier;
earlyEne[bin] = adjustedEarlyEne; /* Store already here */
}
adjustedLateEne = revEne[bin] * ( 1.0f - energyModifier );
/* Store adjusted room effect parameters to be used in reverb processing */
revTimes[bin] = adjustedRevTime;
revEne[bin] = adjustedLateEne;
earlyEne[bin] = adjustedEarlyEne;
}
}
......@@ -1939,6 +1943,7 @@ ivas_error ivas_binaural_reverb_init(
return error;
}
/*-------------------------------------------------------------------------
* ivas_binaural_reverb_close()
*
......
......@@ -163,9 +163,9 @@ const float ap_lattice_coeffs_3[DIRAC_DECORR_FILTER_LEN_3*DIRAC_MAX_NUM_DECORR_F
const float * const ap_lattice_coeffs[DIRAC_DECORR_NUM_SPLIT_BANDS] =
{
&ap_lattice_coeffs_1[0],
&ap_lattice_coeffs_2[0],
&ap_lattice_coeffs_3[0],
ap_lattice_coeffs_1,
ap_lattice_coeffs_2,
ap_lattice_coeffs_3,
};
const float ap_split_frequencies[DIRAC_DECORR_NUM_SPLIT_BANDS + 1] =
......@@ -177,11 +177,13 @@ const int16_t sba_map_tc[11] =
{
0, 1, 2, 3, 4, 8, 9, 15, 5, 6, 7
};
const int16_t sba_map_tc_512[11] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15
};
/*----------------------------------------------------------------------------------*
* FASTCONV and PARAMETRIC binaural renderer ROM tables
*----------------------------------------------------------------------------------*/
......@@ -380,6 +382,7 @@ const float ivas_reverb_default_DSR[IVAS_REVERB_DEFAULT_N_BANDS] =
6.2001e-08f, 2.8483e-08f, 2.6267e-08f
};
/*----------------------------------------------------------------------------------*
* Renderer SBA & MC enc/dec matrices
*----------------------------------------------------------------------------------*/
......@@ -388,6 +391,7 @@ const float ivas_reverb_default_DSR[IVAS_REVERB_DEFAULT_N_BANDS] =
const float ls_azimuth_CICP1[1] = { 0.0f };
const float ls_elevation_CICP1[1] = { 0.0f };
/*----------------------------------------------------------------------------------*
* EFAP ROM tables
*----------------------------------------------------------------------------------*/
......
......@@ -366,10 +366,10 @@ void rotateFrame_sd(
int16_t azimuth, elevation;
float tmp;
float tmp_gains[MAX_CICP_CHANNELS - 1];
float gains[MAX_CICP_CHANNELS][MAX_CICP_CHANNELS];
float gains_prev[MAX_CICP_CHANNELS][MAX_CICP_CHANNELS];
float output_tmp[MAX_CICP_CHANNELS][L_FRAME48k];
float tmp_gains[MAX_LS_CHANNELS - 1];
float gains[MAX_LS_CHANNELS][MAX_LS_CHANNELS];
float gains_prev[MAX_LS_CHANNELS][MAX_LS_CHANNELS];
float output_tmp[MAX_LS_CHANNELS][L_FRAME48k];
float cross_fade[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
push_wmops( "rotateFrame_sd" );
......@@ -591,11 +591,11 @@ void rotateFrame_sd_cldfb(
)
{
int16_t iBlock, iBand, m, n;
float gains[MAX_CICP_CHANNELS - 1][MAX_CICP_CHANNELS - 1];
float gains[MAX_LS_CHANNELS - 1][MAX_LS_CHANNELS - 1];
int16_t azimuth, elevation;
float g1;
float realRot[MAX_CICP_CHANNELS - 1][MAX_PARAM_SPATIAL_SUBFRAMES * CLDFB_NO_CHANNELS_MAX];
float imagRot[MAX_CICP_CHANNELS - 1][MAX_PARAM_SPATIAL_SUBFRAMES * CLDFB_NO_CHANNELS_MAX];
float realRot[MAX_LS_CHANNELS - 1][MAX_PARAM_SPATIAL_SUBFRAMES * CLDFB_NO_CHANNELS_MAX];
float imagRot[MAX_LS_CHANNELS - 1][MAX_PARAM_SPATIAL_SUBFRAMES * CLDFB_NO_CHANNELS_MAX];
float *p_realRot, *p_imagRot;
float *p_real, *p_imag;
int16_t nInChannels;
......
......@@ -1371,6 +1371,22 @@ typedef struct
} CLDFB_REND_WRAPPER;
/*----------------------------------------------------------------------------------*
* Time domain ring buffer structure
*----------------------------------------------------------------------------------*/
typedef struct
{
float *data; /* samples in interleaved layout */
uint32_t capacity;
uint16_t num_channels;
uint32_t write_pos;
uint32_t read_pos;
int16_t is_full;
} TD_RINGBUF_DATA, *TD_RINGBUF_HANDLE;
/*----------------------------------------------------------------------------------*
* MASA external renderer structure
*----------------------------------------------------------------------------------*/
......
/******************************************************************************************************
(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 <assert.h>
#include <stdlib.h>
#include "ivas_error_utils.h"
#include "ivas_prot_rend.h"
#include "options.h"
#include "wmc_auto.h"
/*-----------------------------------------------------------------------*
* Local function prototypes
*-----------------------------------------------------------------------*/
static uint32_t ivas_td_ringbuf_total_size(
TD_RINGBUF_HANDLE h )
{
if ( h->is_full )
{
return h->capacity;
}
if ( h->read_pos <= h->write_pos )
{
return h->write_pos - h->read_pos;
}
/* else wrap around */
return h->write_pos + h->capacity - h->read_pos;
}
static int16_t ivas_td_ringbuf_has_space_for_num_samples(
TD_RINGBUF_HANDLE h,
const uint32_t num_samples )
{
return (int16_t) ( ivas_td_ringbuf_total_size( h ) + num_samples <= h->capacity );
}
/*-----------------------------------------------------------------------*
* 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 uint32_t capacity_per_channel, /* i : Number of samples stored per channel */
const uint16_t num_channels /* i : Number of channels */
)
{
TD_RINGBUF_HANDLE h;
uint32_t capacity;
capacity = 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" );
}
h->data = NULL;
h->capacity = 0;
h->num_channels = num_channels;
h->write_pos = 0;
h->read_pos = 0;
h->is_full = 0;
*ph = h;
h->data = malloc( capacity * sizeof( float ) );
if ( h->data == NULL )
{
return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for TD ring buffer\n" );
}
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;
}
h = *ph;
if ( h == NULL )
{
return;
}
if ( h->data != NULL )
{
free( h->data );
}
free( h );
*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 float *data, /* i : Input data */
const uint32_t num_samples_per_channel /* i : Number of samples per channel to store */
)
{
uint32_t s;
uint16_t c;
assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) );
for ( s = 0; s < num_samples_per_channel; ++s )
{
for ( c = 0; c < h->num_channels; ++c )
{
h->data[h->write_pos] = *( data + c * num_samples_per_channel + s );
++h->write_pos;
if ( h->write_pos == h->capacity )
{
h->write_pos = 0;
}
}
}
if ( h->read_pos == h->write_pos )
{
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 uint32_t num_samples_per_channel /* i : Number of zeros per channel to store */
)
{
uint32_t s;
uint16_t c;
assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) );
if ( !num_samples_per_channel )
{
return;
}
for ( s = 0; s < num_samples_per_channel; ++s )
{
for ( c = 0; c < h->num_channels; ++c )
{
h->data[h->write_pos] = 0.f;
++h->write_pos;
if ( h->write_pos == h->capacity )
{
h->write_pos = 0;
}
}
}
if ( h->read_pos == h->write_pos )
{
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 */
float *data, /* i : Output data */
const uint32_t num_samples_per_channel /* i : Number of samples per channel to retrieve */
)
{
uint32_t s;
uint16_t c;
assert( ivas_td_ringbuf_total_size( h ) >= num_samples_per_channel * h->num_channels );
for ( s = 0; s < num_samples_per_channel; ++s )
{
for ( c = 0; c < h->num_channels; ++c )
{
*( data + c * num_samples_per_channel + s ) = h->data[h->read_pos];
++h->read_pos;
if ( h->read_pos == h->capacity )
{
h->read_pos = 0;
}
}
}
if ( h->is_full )
{
h->is_full = 0;
}
return;
}
/*---------------------------------------------------------------------*
* ivas_TD_RINGBUF_Size()
*
* Returns number of buffered samples per channel.
*---------------------------------------------------------------------*/
uint32_t ivas_TD_RINGBUF_Size(
const TD_RINGBUF_HANDLE h /* i : Ring buffer handle */
)
{
return ivas_td_ringbuf_total_size( h ) / (uint32_t) h->num_channels;
}
......@@ -81,6 +81,7 @@ typedef struct
typedef struct
{
const int32_t *pOutSampleRate;
const int32_t *pMaxGlobalDelayNs;
const AUDIO_CONFIG *pOutConfig;
const LSSETUP_CUSTOM_STRUCT *pCustomLsOut;
const EFAP_WRAPPER *pEfapOutWrapper;
......@@ -97,9 +98,11 @@ typedef struct
AUDIO_CONFIG inConfig;
IVAS_REND_InputId id;
IVAS_REND_AudioBuffer inputBuffer;
TD_RINGBUF_HANDLE delayBuffer;
float gain; /* Linear, not in dB */
rendering_context ctx;
int32_t numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */
int32_t delayNumSamples;
} input_base;
typedef struct
......@@ -189,6 +192,7 @@ typedef struct hrtf_handles
struct IVAS_REND
{
int32_t sampleRateOut;
int32_t maxGlobalDelayNs;
IVAS_LIMITER_HANDLE hLimiter;
#ifdef DEBUGGING
......@@ -204,11 +208,12 @@ struct IVAS_REND
AUDIO_CONFIG outputConfig;
EFAP_WRAPPER efapOutWrapper;
IVAS_LSSETUP_CUSTOM_STRUCT customLsOut;
int16_t splitRendBFI;
SPLIT_REND_WRAPPER *splitRendWrapper;
IVAS_REND_AudioBuffer splitRendEncBuffer;
IVAS_REND_HeadRotData headRotData;
int16_t splitRendBFI;
EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData;
COMBINED_ORIENTATION_HANDLE hCombinedOrientationData;
......@@ -262,6 +267,13 @@ static void freeInputBaseBufferData(
return;
}
static int16_t latencyNsToSamples(
int32_t sampleRate,
int32_t latency_ns )
{
return (int16_t) roundf( (float) ( latency_ns ) * ( sampleRate / 1000000000.f ) );
}
static ivas_error allocateMcLfeDelayBuffer(
float **lfeDelayBuffer,
const int16_t data_size )
......@@ -369,7 +381,7 @@ static void copyBufferToCLDFBarray(
static void accumulateCLDFBArrayToBuffer(
float re[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
float im[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
IVAS_REND_AudioBuffer *buffer )
const IVAS_REND_AudioBuffer *buffer )
{
uint32_t smplIdx, slotIdx;
uint32_t numCldfbSamples, num_bands;
......@@ -1162,6 +1174,8 @@ static void initRendInputBase(
inputBase->gain = 1.0f;
inputBase->ctx = rendCtx;
inputBase->numNewSamplesPerChannel = 0;
inputBase->delayNumSamples = 0;
inputBase->delayBuffer = NULL;
inputBase->inputBuffer.config.numSamplesPerChannel = 0;
inputBase->inputBuffer.config.numChannels = 0;
......@@ -1210,6 +1224,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;
......@@ -1252,6 +1267,272 @@ static bool isIoConfigPairSupported(
}
static int32_t getRendInputDelayIsm(
const input_ism *inputIsm,
bool splitPreRendCldfb )
{
int32_t latency_ns;
latency_ns = 0;
(void) ( splitPreRendCldfb ); /* unused */
/* set the rendering delay in InputBase */
latency_ns = max( latency_ns,
inputIsm->tdRendWrapper.binaural_latency_ns );
if ( inputIsm->crendWrapper != NULL )
{
latency_ns = 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 int32_t getRendInputDelayMc(
const input_mc *inputMc,
bool splitPreRendCldfb )
{
int32_t latency_ns;
latency_ns = 0;
(void) ( splitPreRendCldfb ); /* unused */
latency_ns = max( latency_ns,
inputMc->tdRendWrapper.binaural_latency_ns );
if ( inputMc->crendWrapper != NULL )
{
latency_ns = 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 int32_t getRendInputDelaySba(
const input_sba *inputSba,
bool splitPreRendCldfb )
{
int32_t latency_ns;
latency_ns = 0;
if ( inputSba->cldfbRendWrapper.hCldfbRend != NULL )
{
latency_ns = max( latency_ns,
inputSba->cldfbRendWrapper.binaural_latency_ns +
( splitPreRendCldfb ? 0 : IVAS_FB_DEC_DELAY_NS ) );
}
if ( inputSba->crendWrapper != NULL )
{
latency_ns = 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 int32_t getRendInputDelayMasa(
const input_masa *inputMasa,
bool splitPreRendCldfb )
{
int32_t latency_ns;
latency_ns = 0;
if ( ( inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA1 && *inputMasa->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_MONO ) ||
( getAudioConfigType( *inputMasa->base.ctx.pOutConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
{
return 0; /* no delay */
}
else
{
/* no delay applied for split rendering */
latency_ns = max( latency_ns,
(int32_t) ( ( splitPreRendCldfb ? 0 : (float) IVAS_FB_DEC_DELAY_NS + 0.5f ) ) );
}
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 int32_t getMaxGlobalDelayNs( IVAS_REND_CONST_HANDLE hIvasRend )
{
int16_t i;
int32_t latency_ns;
int32_t 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 ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
{
latency_ns = getRendInputDelayIsm( &hIvasRend->inputsIsm[i], splitPreRendCldfb );
max_latency_ns = 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 = 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 = 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 = 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 int32_t maxGlobalDelayNs,
const int32_t sampleRateOut,
const int16_t cldfb2tdSampleFact,
const bool flushInputs )
{
ivas_error error;
input_ism *inputIsm;
int16_t maxGlobalDelaySamples;
int32_t numSamplesToPush, numSamplesToPop;
uint32_t ringBufferSize, preDelay;
maxGlobalDelaySamples = latencyNsToSamples( sampleRateOut, maxGlobalDelayNs );
maxGlobalDelaySamples *= cldfb2tdSampleFact;
/* check if we need to open the delay buffer */
if ( inputBase->delayBuffer == NULL )
{
/* buffer has to accomodate maxGlobalDelaySamples + 2 * frameSize */
ringBufferSize = maxGlobalDelaySamples + 2 * inputAudio.config.numSamplesPerChannel;
/* pre delay for this input is maximum delay - input delay */
preDelay = maxGlobalDelaySamples - inputBase->delayNumSamples * cldfb2tdSampleFact;
if ( 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 = maxGlobalDelayNs / 1e6f;
}
}
}
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 */
numSamplesToPush = flushInputs ? 0 : inputAudio.config.numSamplesPerChannel;
numSamplesToPop = flushInputs ? ivas_TD_RINGBUF_Size( inputBase->delayBuffer ) : (uint32_t) inputAudio.config.numSamplesPerChannel;
ivas_TD_RINGBUF_Push( inputBase->delayBuffer, inputAudio.data, numSamplesToPush );
ivas_TD_RINGBUF_Pop( inputBase->delayBuffer, inputBase->inputBuffer.data, numSamplesToPop );
}
else
{
/* delay buffer isn't open - we don't need it */
mvr2r( inputAudio.data,
inputBase->inputBuffer.data,
inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
}
return IVAS_ERR_OK;
}
static ivas_error initIsmMasaRendering(
input_ism *inputIsm,
const int32_t inSampleRate )
......@@ -1263,7 +1544,7 @@ static ivas_error initIsmMasaRendering(
ivas_td_binaural_close( &inputIsm->tdRendWrapper.hBinRendererTd );
}
ivas_rend_closeCrend( &inputIsm->crendWrapper, inputIsm->base.ctx.pSplitRendWrapper != NULL ? inputIsm->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 );
ivas_rend_closeCrend( &inputIsm->crendWrapper );
ivas_reverb_close( &inputIsm->hReverb );
......@@ -1387,10 +1668,12 @@ static void clearInputIsm(
rendCtx = inputIsm->base.ctx;
freeInputBaseBufferData( &inputIsm->base.inputBuffer.data );
ivas_TD_RINGBUF_Close( &inputIsm->base.delayBuffer );
initRendInputBase( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
/* Free input's internal handles */
ivas_rend_closeCrend( &inputIsm->crendWrapper, inputIsm->base.ctx.pSplitRendWrapper != NULL ? inputIsm->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 );
ivas_rend_closeCrend( &inputIsm->crendWrapper );
ivas_reverb_close( &inputIsm->hReverb );
......@@ -1832,7 +2115,7 @@ static ivas_error updateLfePanGainsForAmbiOut(
ivas_dirac_dec_get_response( (int16_t) inputMc->lfeRouting.lfeOutputAzimuth, (int16_t) inputMc->lfeRouting.lfeOutputElevation, inputMc->lfeRouting.lfePanMtx[i], outAmbiOrder );
/* linear input gain */
v_multc( inputMc->lfeRouting.lfePanMtx[i], inputMc->lfeRouting.lfeInputGain, inputMc->lfeRouting.lfePanMtx[i], IVAS_MAX_OUTPUT_CHANNELS );
v_multc( inputMc->lfeRouting.lfePanMtx[i], inputMc->lfeRouting.lfeInputGain, inputMc->lfeRouting.lfePanMtx[i], RENDERER_MAX_OUTPUT_CHANNELS );
}
return error;
......@@ -2024,13 +2307,13 @@ static ivas_error updateMcPanGains(
{
for ( i = 0; i < inputMc->customLsInput.num_lfe; ++i )
{
mvr2r( inputMc->lfeRouting.lfePanMtx[i], inputMc->panGains[inputMc->customLsInput.lfe_idx[i]], IVAS_MAX_OUTPUT_CHANNELS );
mvr2r( inputMc->lfeRouting.lfePanMtx[i], inputMc->panGains[inputMc->customLsInput.lfe_idx[i]], RENDERER_MAX_OUTPUT_CHANNELS );
}
}
else
{
/* For code simplicity, always copy LFE gains. If config has no LFE, gains will be zero anyway. */
mvr2r( inputMc->lfeRouting.lfePanMtx[0], inputMc->panGains[LFE_CHANNEL], IVAS_MAX_OUTPUT_CHANNELS );
mvr2r( inputMc->lfeRouting.lfePanMtx[0], inputMc->panGains[LFE_CHANNEL], RENDERER_MAX_OUTPUT_CHANNELS );
}
return IVAS_ERR_OK;
......@@ -2088,7 +2371,7 @@ static ivas_error initMcBinauralRendering(
/* if we need to use TD renderer and CREND was open, close it */
if ( useTDRend )
{
ivas_rend_closeCrend( &inputMc->crendWrapper, inputMc->base.ctx.pSplitRendWrapper != NULL ? inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 );
ivas_rend_closeCrend( &inputMc->crendWrapper );
}
if ( !reconfigureFlag || ( !useTDRend && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB && inputMc->hReverb != NULL ) )
......@@ -2157,7 +2440,7 @@ static ivas_error initMcBinauralRendering(
/* determine binaural delay ( used for aligning LFE to output signal ) */
binauralDelayNs = max( ( inputMc->crendWrapper != NULL ) ? inputMc->crendWrapper->binaural_latency_ns : 0, inputMc->tdRendWrapper.binaural_latency_ns );
inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f );
inputMc->binauralDelaySmp = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, binauralDelayNs );
if ( inputMc->binauralDelaySmp > MAX_BIN_DELAY_SAMPLES )
{
......@@ -2180,7 +2463,7 @@ static ivas_error initMcMasaRendering(
ivas_td_binaural_close( &inputMc->tdRendWrapper.hBinRendererTd );
}
ivas_rend_closeCrend( &inputMc->crendWrapper, inputMc->base.ctx.pSplitRendWrapper != NULL ? inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 );
ivas_rend_closeCrend( &inputMc->crendWrapper );
ivas_reverb_close( &inputMc->hReverb );
......@@ -2211,7 +2494,7 @@ static lfe_routing defaultLfeRouting(
for ( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; ++i )
{
set_zero( routing.lfePanMtx[i], IVAS_MAX_OUTPUT_CHANNELS );
set_zero( routing.lfePanMtx[i], RENDERER_MAX_OUTPUT_CHANNELS );
}
routing.pan_lfe = false;
......@@ -2357,6 +2640,8 @@ static void clearInputMc(
freeMcLfeDelayBuffer( &inputMc->lfeDelayBuffer );
freeInputBaseBufferData( &inputMc->bufferData );
ivas_TD_RINGBUF_Close( &inputMc->base.delayBuffer );
initRendInputBase( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
/* Free input's internal handles */
......@@ -2365,7 +2650,7 @@ static void clearInputMc(
efap_free_data( &inputMc->efapInWrapper.hEfap );
}
ivas_rend_closeCrend( &inputMc->crendWrapper, inputMc->base.ctx.pSplitRendWrapper != NULL ? inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 );
ivas_rend_closeCrend( &inputMc->crendWrapper );
ivas_reverb_close( &inputMc->hReverb );
......@@ -2582,7 +2867,7 @@ static ivas_error initSbaMasaRendering(
{
ivas_error error;
ivas_rend_closeCrend( &inputSba->crendWrapper, inputSba->base.ctx.pSplitRendWrapper != NULL ? inputSba->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 );
ivas_rend_closeCrend( &inputSba->crendWrapper );
if ( ( error = ivas_dirac_ana_open( &inputSba->hDirAC, inSampleRate ) ) != IVAS_ERR_OK )
{
......@@ -2644,7 +2929,7 @@ static ivas_error setRendInputActiveSba(
return error;
}
return error;
return IVAS_ERR_OK;
}
......@@ -2656,11 +2941,12 @@ static void clearInputSba(
rendCtx = inputSba->base.ctx;
freeInputBaseBufferData( &inputSba->bufferData );
ivas_TD_RINGBUF_Close( &inputSba->base.delayBuffer );
initRendInputBase( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
/* Free input's internal handles */
ivas_rend_closeCrend( &inputSba->crendWrapper, rendCtx.pSplitRendWrapper != NULL ? rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 );
ivas_rend_closeCrend( &inputSba->crendWrapper );
if ( inputSba->cldfbRendWrapper.hCldfbRend != NULL )
{
......@@ -2735,6 +3021,7 @@ static void clearInputMasa(
rendCtx = inputMasa->base.ctx;
freeInputBaseBufferData( &inputMasa->bufferData );
ivas_TD_RINGBUF_Close( &inputMasa->base.delayBuffer );
masaPrerendClose( &inputMasa->hMasaPrerend );
freeMasaExtRenderer( &inputMasa->hMasaExtRend );
......@@ -2804,7 +3091,7 @@ ivas_error IVAS_REND_Open(
hIvasRend->num_subframes = num_subframes;
/* Initialize limiter */
if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
{
return error;
}
......@@ -2863,6 +3150,9 @@ ivas_error IVAS_REND_Open(
isar_init_split_rend_handles( hIvasRend->splitRendWrapper );
}
hIvasRend->splitRendEncBuffer.data = 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 )
{
......@@ -3058,7 +3348,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout(
hIvasRend->customLsOut = makeCustomLsSetup( layout );
/* Re-initialize limiter - number of output channels may have changed */
if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
{
return error;
}
......@@ -3116,12 +3406,12 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout(
/*-------------------------------------------------------------------*
* IVAS_REND_NumOutChannels()
* IVAS_REND_GetNumOutChannels()
*
*
*-------------------------------------------------------------------*/
ivas_error IVAS_REND_NumOutChannels(
ivas_error IVAS_REND_GetNumOutChannels(
IVAS_REND_CONST_HANDLE hIvasRend,
int16_t *numOutChannels )
{
......@@ -3292,30 +3582,55 @@ static ivas_error getConstInputById(
}
static void *getInputByIndex(
void *inputsArray,
const size_t index,
const IVAS_REND_AudioConfigType inputType )
{
switch ( inputType )
{
case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
return (input_mc *) inputsArray + index;
case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
return (input_sba *) inputsArray + index;
case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
return (input_ism *) inputsArray + index;
case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
return (input_masa *) inputsArray + index;
default:
break;
}
/* this should be unreachable */
assert( 0 );
/* include a final return to make the linter happy and avoid problems with wmc_tool (see #1355) */
return NULL;
}
static ivas_error findFreeInputSlot(
const void *inputs,
const int32_t inputStructSize,
void *inputs,
const IVAS_REND_AudioConfigType inputType,
const int32_t maxInputs,
int32_t *inputIndex )
{
/* Using a void pointer and a separately provided size is a hack for this function
/* Using a void pointer and a separately provided type is a hack for this function
to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa).
Assumptions:
- input_base is always the first member in the input struct
- provided size is correct
- memory alignments of original input type and input_base are the same
*/
int32_t i;
bool canAddInput;
const uint8_t *pByte;
const input_base *pInputBase;
canAddInput = false;
/* Find first unused input in array */
for ( i = 0, pByte = inputs; i < maxInputs; ++i, pByte += inputStructSize )
for ( i = 0; i < maxInputs; ++i )
{
pInputBase = (const input_base *) pByte;
pInputBase = (const input_base *) getInputByIndex( inputs, i, inputType );
if ( pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
{
......@@ -3345,10 +3660,15 @@ static int16_t getCldfbRendFlag(
const IVAS_REND_AudioConfigType new_configType )
{
int16_t i;
int16_t numMasaInputs = 0, numSbaInputs = 0, numIsmInputs = 0, numMcInputs = 0;
int16_t numMasaInputs = 0, numSbaInputs = 0;
int16_t isCldfbRend;
isCldfbRend = 0;
/* 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 )
......@@ -3359,20 +3679,7 @@ static int16_t getCldfbRendFlag(
{
numSbaInputs += ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1;
}
for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
{
numIsmInputs += ( hIvasRend->inputsIsm[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) ? 0 : 1;
}
for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
{
numMcInputs += ( hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? 0 : 1;
}
if ( numIsmInputs > 0 || numMcInputs > 0 )
{
isCldfbRend = 0;
}
else if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) )
if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) )
{
isCldfbRend = 1;
}
......@@ -3382,12 +3689,12 @@ static int16_t 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,
......@@ -3397,10 +3704,20 @@ static ivas_error ivas_pre_rend_init(
const int16_t cldfb_in_flag,
const int16_t num_subframes )
{
bool realloc;
ivas_error error;
IVAS_REND_AudioBufferConfig bufConfig;
if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
realloc = false;
/* only perform init if split rendering output */
if ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
{
return IVAS_ERR_OK;
}
/* these functions should only be called once during initial allocation */
if ( pSplitRendEncBuffer->data == NULL )
{
if ( pSplit_rend_config->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
{
......@@ -3415,28 +3732,34 @@ static ivas_error ivas_pre_rend_init(
{
return error;
}
}
/* 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 */
if ( pSplitRendEncBuffer->data != NULL && ( cldfb_in_flag != pSplitRendEncBuffer->config.is_cldfb ) )
{
realloc = true;
}
/*allocate for CLDFB in and change to TD during process if needed*/
bufConfig.numSamplesPerChannel = MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL;
if ( pSplitRendEncBuffer->data == NULL || realloc )
{
/* set buffer config */
bufConfig.is_cldfb = cldfb_in_flag;
bufConfig.numSamplesPerChannel = cldfb_in_flag ? MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL : L_FRAME_MAX;
bufConfig.numChannels = BINAURAL_CHANNELS * pSplitRendWrapper->multiBinPoseData.num_poses;
bufConfig.is_cldfb = 1;
pSplitRendEncBuffer->config = bufConfig;
/* allocate memory */
if ( realloc )
{
free( pSplitRendEncBuffer->data );
}
if ( ( pSplitRendEncBuffer->data = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( float ) ) ) == NULL )
{
return IVAS_ERR_FAILED_ALLOC;
}
}
else
{
IVAS_REND_AudioBufferConfig bufConfig2;
bufConfig2.numSamplesPerChannel = 0;
bufConfig2.numChannels = 0;
bufConfig2.is_cldfb = 0;
pSplitRendEncBuffer->config = bufConfig2;
pSplitRendEncBuffer->data = NULL;
}
return IVAS_ERR_OK;
}
......@@ -3457,9 +3780,13 @@ ivas_error IVAS_REND_AddInput(
ivas_error error;
int32_t maxNumInputsOfType;
void *inputsArray;
int32_t inputStructSize;
IVAS_REND_AudioConfigType inputType;
ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA *, hrtf_handles * );
void ( *setInputDelay )( void *, bool );
int32_t inputIndex;
bool splitPreRendCldfb;
splitPreRendCldfb = false;
/* Validate function arguments */
if ( hIvasRend == NULL || inputId == NULL )
......@@ -3467,59 +3794,75 @@ ivas_error IVAS_REND_AddInput(
return IVAS_ERR_UNEXPECTED_NULL_POINTER;
}
if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) && hIvasRend->splitRendEncBuffer.data == NULL && hIvasRend->hRendererConfig != NULL )
if ( hIvasRend->hRendererConfig != NULL )
{
int16_t 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 = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD );
}
switch ( getAudioConfigType( inConfig ) )
inputType = getAudioConfigType( inConfig );
switch ( inputType )
{
case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS;
inputsArray = hIvasRend->inputsIsm;
inputStructSize = sizeof( *hIvasRend->inputsIsm );
activateInput = setRendInputActiveIsm;
setInputDelay = setRendInputDelayIsm;
break;
case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
maxNumInputsOfType = RENDERER_MAX_MC_INPUTS;
inputsArray = hIvasRend->inputsMc;
inputStructSize = sizeof( *hIvasRend->inputsMc );
activateInput = setRendInputActiveMc;
setInputDelay = setRendInputDelayMc;
break;
case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS;
inputsArray = hIvasRend->inputsSba;
inputStructSize = sizeof( *hIvasRend->inputsSba );
activateInput = setRendInputActiveSba;
setInputDelay = setRendInputDelaySba;
break;
case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS;
inputsArray = hIvasRend->inputsMasa;
inputStructSize = sizeof( *hIvasRend->inputsMasa );
activateInput = setRendInputActiveMasa;
setInputDelay = setRendInputDelayMasa;
break;
default:
return IVAS_ERR_INVALID_INPUT_FORMAT;
}
/* Find first free input in array corresponding to input type */
if ( ( error = findFreeInputSlot( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ) != IVAS_ERR_OK )
if ( ( error = findFreeInputSlot( inputsArray, inputType, maxNumInputsOfType, &inputIndex ) ) != IVAS_ERR_OK )
{
return error;
}
*inputId = makeInputId( inConfig, inputIndex );
if ( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, hIvasRend->hRendererConfig, &hIvasRend->hHrtfs ) ) != IVAS_ERR_OK )
if ( ( error = activateInput( getInputByIndex( inputsArray, inputIndex, inputType ), inConfig, *inputId, hIvasRend->hRendererConfig, &hIvasRend->hHrtfs ) ) != IVAS_ERR_OK )
{
return error;
}
setInputDelay( getInputByIndex( inputsArray, inputIndex, inputType ), splitPreRendCldfb );
/* set global maximum delay after adding an input */
setMaxGlobalDelayNs( hIvasRend );
return IVAS_ERR_OK;
}
......@@ -3667,7 +4010,7 @@ ivas_error IVAS_REND_SetInputLfeMtx(
/* copy LFE panning matrix */
for ( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; i++ )
{
mvr2r( ( *lfePanMtx )[i], pInputMc->lfeRouting.lfePanMtx[i], IVAS_MAX_OUTPUT_CHANNELS );
mvr2r( ( *lfePanMtx )[i], pInputMc->lfeRouting.lfePanMtx[i], RENDERER_MAX_OUTPUT_CHANNELS );
}
if ( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ) != IVAS_ERR_OK )
......@@ -3772,6 +4115,9 @@ ivas_error IVAS_REND_RemoveInput(
return IVAS_ERR_INVALID_INPUT_FORMAT;
}
/* set global maximum delay after removing an input */
setMaxGlobalDelayNs( hIvasRend );
return IVAS_ERR_OK;
}
......@@ -3848,11 +4194,6 @@ ivas_error IVAS_REND_GetDelay(
int32_t *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)
*/
int16_t i;
int32_t latency_ns;
int32_t max_latency_ns;
/* Validate function arguments */
......@@ -3861,76 +4202,16 @@ ivas_error IVAS_REND_GetDelay(
return IVAS_ERR_UNEXPECTED_NULL_POINTER;
}
*timeScale = hIvasRend->sampleRateOut;
*nSamples = 0;
max_latency_ns = 0;
/* Compute the maximum delay across all inputs */
for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
{
if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
{
latency_ns = max( ( hIvasRend->inputsIsm[i].crendWrapper != NULL ) ? hIvasRend->inputsIsm[i].crendWrapper->binaural_latency_ns : 0,
hIvasRend->inputsIsm[i].tdRendWrapper.binaural_latency_ns );
max_latency_ns = 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 = max( ( hIvasRend->inputsMc[i].crendWrapper != NULL ) ? hIvasRend->inputsMc[i].crendWrapper->binaural_latency_ns : 0,
hIvasRend->inputsMc[i].tdRendWrapper.binaural_latency_ns );
max_latency_ns = 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 )
{
if ( hIvasRend->splitRendWrapper != NULL && hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL )
{
if ( hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV )
{
latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns;
}
else
{
latency_ns = ( hIvasRend->inputsSba[i].crendWrapper != NULL ) ? hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns : 0;
}
max_latency_ns = max( max_latency_ns, latency_ns );
}
else if ( hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend != NULL )
{
latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns;
latency_ns += IVAS_FB_DEC_DELAY_NS;
max_latency_ns = max( max_latency_ns, latency_ns );
}
else
{
latency_ns = ( hIvasRend->inputsSba[i].crendWrapper != NULL ) ? hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns : 0;
max_latency_ns = max( max_latency_ns, latency_ns );
}
}
}
*timeScale = hIvasRend->sampleRateOut;
for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
{
if ( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
{
latency_ns = (int32_t) ( (float) IVAS_FB_DEC_DELAY_NS + 0.5f );
max_latency_ns = max( max_latency_ns, latency_ns );
}
}
max_latency_ns = getMaxGlobalDelayNs( hIvasRend );
*nSamples = (int16_t) roundf( (float) max_latency_ns * *timeScale / 1000000000.f );
*nSamples = latencyNsToSamples( hIvasRend->sampleRateOut, max_latency_ns );
return IVAS_ERR_OK;
}
/*-------------------------------------------------------------------*
* IVAS_REND_FeedInputAudio()
*
......@@ -3940,7 +4221,8 @@ ivas_error IVAS_REND_GetDelay(
ivas_error IVAS_REND_FeedInputAudio(
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 error;
......@@ -3996,9 +4278,16 @@ ivas_error IVAS_REND_FeedInputAudio(
}
inputBase->inputBuffer.config = inputAudio.config;
mvr2r( inputAudio.data, inputBase->inputBuffer.data, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
if ( ( error = alignInputDelay(
inputBase,
inputAudio,
hIvasRend->maxGlobalDelayNs,
hIvasRend->sampleRateOut,
cldfb2tdSampleFact,
flushInputs ) ) != IVAS_ERR_OK )
{
return error;
}
inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel / cldfb2tdSampleFact;
return IVAS_ERR_OK;
......@@ -4306,6 +4595,7 @@ ivas_error IVAS_REND_FeedRenderConfig(
if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL )
{
ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb );
if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb,
hIvasRend->hHrtfs.hHrtfStatistics,
pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands,
......@@ -4323,6 +4613,7 @@ ivas_error IVAS_REND_FeedRenderConfig(
if ( pMasaInput->hMasaExtRend->hReverb != NULL )
{
ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hReverb );
if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hReverb,
hIvasRend->hHrtfs.hHrtfStatistics,
pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands,
......@@ -4355,6 +4646,7 @@ ivas_error IVAS_REND_FeedRenderConfig(
return error;
}
}
if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL )
{
if ( ( error = ivas_reverb_open( &pMcInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK )
......@@ -4405,6 +4697,7 @@ ivas_error IVAS_REND_FeedRenderConfig(
{
int16_t 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 );
......@@ -4412,7 +4705,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;
}
......@@ -5141,7 +5434,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 = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) );
ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000.f / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) );
copyBufferTo2dArray( ismInput->base.inputBuffer, tmpTDRendBuffer );
if ( ( error = ivas_td_binaural_renderer_ext( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, ism_md_subframe_update_ext,
......@@ -5345,7 +5638,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 = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) );
ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000.f / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) );
copyBufferTo2dArray( ismInput->base.inputBuffer, tmpRendBuffer );
......@@ -5511,8 +5804,10 @@ static ivas_error renderIsmToSplitBinaural(
const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
const SPLIT_REND_WRAPPER *pSplitRendWrapper;
IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
int16_t i;
int16_t i, ch, slot_idx, num_bands;
float tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
float tmpBinaural_CldfbRe[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
float tmpBinaural_CldfbIm[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
int16_t output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel;
COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
int16_t ism_md_subframe_update_ext;
......@@ -5523,7 +5818,7 @@ static ivas_error renderIsmToSplitBinaural(
pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
/* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) );
ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000.f / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) );
pCombinedOrientationData = *ismInput->base.ctx.pCombinedOrientationData;
......@@ -5579,10 +5874,29 @@ static ivas_error renderIsmToSplitBinaural(
return error;
}
if ( outAudio.config.is_cldfb )
{
/* Perform CLDFB analysis on rendered audio, since the output buffer is CLDFB domain */
num_bands = (int16_t) ( ( BINAURAL_MAXBANDS * *ismInput->base.ctx.pOutSampleRate ) / 48000 );
for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
{
for ( slot_idx = 0; slot_idx < IVAS_CLDFB_NO_COL_MAX; slot_idx++ )
{
cldfbAnalysis_ts( &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] );
}
}
}
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. */
mvr2r( tmpProcessing[0], tmpBinaural[2 * pos_idx], output_frame );
mvr2r( tmpProcessing[1], tmpBinaural[2 * pos_idx + 1], output_frame );
mvr2r( tmpProcessing[0], tmpBinaural[BINAURAL_CHANNELS * pos_idx], output_frame );
mvr2r( tmpProcessing[1], tmpBinaural[BINAURAL_CHANNELS * pos_idx + 1], output_frame );
}
/* Overwrite processing buffer with original input audio again */
copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing );
......@@ -5594,7 +5908,14 @@ static ivas_error renderIsmToSplitBinaural(
pCombinedOrientationData->Quaternions[i] = originalHeadRot[i];
}
if ( outAudio.config.is_cldfb )
{
accumulateCLDFBArrayToBuffer( tmpBinaural_CldfbRe, tmpBinaural_CldfbIm, &outAudio );
}
else
{
accumulate2dArrayToBuffer( tmpBinaural, &outAudio );
}
pop_wmops();
/* Encoding to split rendering bitstream done at a higher level */
......@@ -5629,11 +5950,13 @@ static ivas_error renderInputIsm(
{
ivas_error error;
IVAS_REND_AudioBuffer inAudio;
int16_t cldfb2tdSampleFact;
error = IVAS_ERR_OK;
inAudio = ismInput->base.inputBuffer;
if ( ismInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel )
cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1;
if ( ismInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != 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" );
}
......@@ -5758,8 +6081,7 @@ static ivas_error renderLfeToBinaural(
num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp;
num_cpy_smpl_cur_frame = 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( mcInput->lfeDelayBuffer, gain, tmpLfeBuffer, num_cpy_smpl_prev_frame );
......@@ -7338,14 +7660,12 @@ 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 mode*/
IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
)
{
ivas_error error;
int16_t numOutChannels;
int16_t cldfb2tdSampleFact;
IVAS_REND_AudioBuffer outAudioOrig;
/* Validate function arguments */
if ( hIvasRend == NULL || outAudio.data == NULL )
......@@ -7405,33 +7725,20 @@ static ivas_error getSamplesInternal(
}
}
if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
{
return error;
}
if ( numOutChannels != outAudio.config.numChannels && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
if ( numOutChannels != outAudio.config.numChannels &&
hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
{
return IVAS_ERR_WRONG_NUM_CHANNELS;
}
/* Clear original output buffer */
set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
outAudioOrig = outAudio;
/* Use internal buffer if outputting split rendering bitstream */
if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
{
int16_t num_poses_orig;
num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
outAudio = hIvasRend->splitRendEncBuffer;
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 */
/* Clear output buffer */
set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
}
if ( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
{
......@@ -7453,30 +7760,114 @@ static ivas_error getSamplesInternal(
return error;
}
if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || 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 */
)
{
ISAR_SPLIT_REND_BITS_DATA bits;
int16_t cldfb_in_flag;
float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
ivas_error error;
if ( ( error = getSamplesInternal( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
{
return error;
}
if ( outAudio.config.is_cldfb == 0 )
{
#ifndef DISABLE_LIMITER
#ifdef DEBUGGING
hIvasRend->numClipping +=
#endif
limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD );
#endif
}
/* update global cominbed orientation start index */
ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
return IVAS_ERR_OK;
}
/*-------------------------------------------------------------------*
* 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;
int16_t ch;
int16_t cldfb_in_flag;
int16_t i, ro_md_flag;
int16_t num_poses_orig;
float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
float 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;
for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
for ( ch = 0; ch < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ch++ )
{
tmpBinaural[ch] = tmpBinaural_buff[ch];
}
if ( outAudio.config.is_cldfb == 1 )
cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
pSplitEncBufConfig = &hIvasRend->splitRendEncBuffer.config;
pSplitRendConfig = &hIvasRend->hRendererConfig->split_rend_config;
/* 0 DoF / No pose correction retains frame size */
pSplitEncBufConfig->is_cldfb = cldfb_in_flag;
if ( pSplitRendConfig->dof == 0 || pSplitRendConfig->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
{
pSplitEncBufConfig->numSamplesPerChannel = outAudio.config.numSamplesPerChannel;
}
/* Pose correction requires 20ms */
else
{
pSplitEncBufConfig->numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC );
}
pSplitEncBufConfig->numSamplesPerChannel *= cldfb_in_flag ? 2 : 1;
num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
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 ( hIvasRend->splitRendEncBuffer.config.is_cldfb == 1 )
{
cldfb_in_flag = 1;
copyBufferToCLDFBarray( outAudio, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
copyBufferToCLDFBarray( hIvasRend->splitRendEncBuffer, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
}
else
{
cldfb_in_flag = 0;
copyBufferTo2dArray( outAudio, tmpBinaural_buff );
copyBufferTo2dArray( hIvasRend->splitRendEncBuffer, tmpBinaural_buff );
}
/* Encode split rendering bitstream */
......@@ -7494,10 +7885,10 @@ static ivas_error getSamplesInternal(
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,
pSplitRendConfig->splitRendBitRate,
pSplitRendConfig->codec,
pSplitRendConfig->isar_frame_size_ms,
pSplitRendConfig->codec_frame_size_ms,
&bits,
Cldfb_RealBuffer_Binaural,
Cldfb_ImagBuffer_Binaural,
......@@ -7513,14 +7904,13 @@ static ivas_error getSamplesInternal(
convertInternalBitsBuffToBitsBuffer( hBits, bits );
/* reset to outAudioOrig in case of PCM output */
outAudio = outAudioOrig;
/* copy over first pose data to outAudio */
if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
{
/* set outAudio to zero - getSamplesInternal only cleared splitRendEncBuffer */
set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
accumulate2dArrayToBuffer( tmpBinaural_buff, &outAudio );
}
}
if ( outAudio.config.is_cldfb == 0 )
{
......@@ -7539,54 +7929,6 @@ static ivas_error getSamplesInternal(
}
/*-------------------------------------------------------------------*
* 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 */
)
{
int16_t cldfb_in_flag;
cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
hIvasRend->splitRendEncBuffer.config.is_cldfb = cldfb_in_flag;
if ( hIvasRend->hRendererConfig->split_rend_config.dof == 0 || hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
{
hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = outAudio.config.numSamplesPerChannel;
}
else
{
hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC );
}
hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel *= cldfb_in_flag ? 2 : 1;
/* hIvasRend->splitRendEncBuffer used for BINAURAL_SPLIT_CODED output
outAudio used for BINAURAL_SPLIT_PCM output */
return getSamplesInternal( hIvasRend, outAudio, hBits );
}
/*-------------------------------------------------------------------*
* IVAS_REND_GetSplitRendBitstreamHeader()
*
......@@ -7701,8 +8043,8 @@ void IVAS_REND_Close(
*-------------------------------------------------------------------*/
ivas_error IVAS_REND_openCldfb(
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[RENDERER_MAX_INPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[RENDERER_MAX_OUTPUT_CHANNELS],
const int16_t num_in_chs,
const int16_t num_out_chs,
const int32_t output_Fs )
......@@ -7717,7 +8059,7 @@ ivas_error IVAS_REND_openCldfb(
return error;
}
}
for ( ; n < IVAS_MAX_INPUT_CHANNELS; n++ )
for ( ; n < RENDERER_MAX_INPUT_CHANNELS; n++ )
{
cldfbAna[n] = NULL;
}
......@@ -7729,7 +8071,7 @@ ivas_error IVAS_REND_openCldfb(
return error;
}
}
for ( ; n < IVAS_MAX_OUTPUT_CHANNELS; n++ )
for ( ; n < RENDERER_MAX_OUTPUT_CHANNELS; n++ )
{
cldfbSyn[n] = NULL;
}
......@@ -7745,12 +8087,12 @@ ivas_error IVAS_REND_openCldfb(
*-------------------------------------------------------------------*/
void IVAS_REND_closeCldfb(
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS] )
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[RENDERER_MAX_INPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[RENDERER_MAX_OUTPUT_CHANNELS] )
{
int16_t n;
for ( n = 0; n < IVAS_MAX_INPUT_CHANNELS; n++ )
for ( n = 0; n < RENDERER_MAX_INPUT_CHANNELS; n++ )
{
if ( cldfbAna[n] != NULL )
{
......@@ -7759,7 +8101,7 @@ void IVAS_REND_closeCldfb(
}
}
for ( n = 0; n < IVAS_MAX_OUTPUT_CHANNELS; n++ )
for ( n = 0; n < RENDERER_MAX_OUTPUT_CHANNELS; n++ )
{
if ( cldfbSyn[n] != NULL )
{
......@@ -8503,7 +8845,11 @@ static ivas_error initMasaExtRenderer(
return error;
}
if ( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ) != IVAS_ERR_OK )
if ( outConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
{
hMasaExtRend->nchan_output = inputMasa->base.ctx.pCustomLsOut->num_spk + inputMasa->base.ctx.pCustomLsOut->num_lfe;
}
else if ( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ) != IVAS_ERR_OK )
{
return error;
}
......
......@@ -41,6 +41,8 @@
* Renderer constants
*---------------------------------------------------------------------*/
#define RENDERER_MAX_OUTPUT_CHANNELS IVAS_MAX_LS_CHANNELS
#define RENDERER_MAX_INPUT_CHANNELS IVAS_MAX_LS_CHANNELS
#define RENDERER_MAX_ISM_INPUTS IVAS_MAX_NUM_OBJECTS
#define RENDERER_MAX_MC_INPUTS 1
#define RENDERER_MAX_SBA_INPUTS 1
......@@ -55,7 +57,7 @@
* Renderer structures
*---------------------------------------------------------------------*/
typedef float IVAS_REND_LfePanMtx[RENDERER_MAX_INPUT_LFE_CHANNELS][IVAS_MAX_OUTPUT_CHANNELS];
typedef float IVAS_REND_LfePanMtx[RENDERER_MAX_INPUT_LFE_CHANNELS][RENDERER_MAX_OUTPUT_CHANNELS];
typedef struct
{
......@@ -68,6 +70,7 @@ typedef struct
int16_t isar_frame_size_ms;
int16_t lc3plus_highres;
} IVAS_REND_BitstreamBufferConfig;
typedef struct
{
IVAS_REND_BitstreamBufferConfig config;
......@@ -131,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 */
int16_t *numOutChannels /* o : number of output channels */
);
......@@ -218,7 +221,8 @@ ivas_error IVAS_REND_GetHrtfStatisticsHandle(
ivas_error IVAS_REND_FeedInputAudio(
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(
......@@ -386,16 +390,16 @@ void IVAS_REND_Close(
/* Split binaural rendering functions */
ivas_error IVAS_REND_openCldfb(
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[RENDERER_MAX_INPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[RENDERER_MAX_OUTPUT_CHANNELS],
const int16_t num_in_chs,
const int16_t num_out_chs,
const int32_t output_Fs
);
void IVAS_REND_closeCldfb(
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS]
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[RENDERER_MAX_INPUT_CHANNELS],
IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[RENDERER_MAX_OUTPUT_CHANNELS]
);
void IVAS_REND_cldfbAnalysis_ts_wrapper(
......
......@@ -69,9 +69,9 @@ ivas_error aeidFileReader_open(
return IVAS_ERR_FAILED_FILE_OPEN;
}
self = calloc( sizeof( aeidFileReader ), 1 );
self = calloc( 1, sizeof( aeidFileReader ) );
self->aeidFile = aeidFile;
self->file_path = calloc( sizeof( char ), strlen( aeidFilePath ) + 1 );
self->file_path = calloc( strlen( aeidFilePath ) + 1, sizeof( char ) );
strcpy( self->file_path, aeidFilePath );
*aeidReader = self;
......
......@@ -94,7 +94,7 @@ ivas_error AudioFileReader_open(
{
return IVAS_ERR_FAILED_FILE_OPEN;
}
self = calloc( sizeof( AudioFileReader ), 1 );
self = calloc( 1, sizeof( AudioFileReader ) );
self->samplingRate = 0;
self->numChannels = 0;
......