From 7e88fe383c98206202f9a3255d7cadd921b01a05 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Fri, 3 May 2024 16:27:12 +1000 Subject: [PATCH 1/7] Modifying external renderer so it will rotate SBA content when rendering to SBA --- lib_rend/lib_rend.c | 52 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index a0d31fa8a6..13fac79ca2 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "wmc_auto.h" @@ -4640,7 +4641,8 @@ ivas_error IVAS_REND_SetHeadRotation( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - if ( getAudioConfigType( hIvasRend->outputConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) + if ( ( getAudioConfigType( hIvasRend->outputConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) + && ( getAudioConfigType( hIvasRend->outputConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ) { /* Head rotation can be set only with binaural output */ return IVAS_ERR_INVALID_OUTPUT_FORMAT; @@ -6668,23 +6670,61 @@ static void renderSbaToMc( } -static void renderSbaToSba( - const input_sba *sbaInput, +static ivas_error renderSbaToSba( + input_sba *sbaInput, IVAS_REND_AudioBuffer outAudio ) { int16_t i; IVAS_REND_AudioBuffer inAudio; + ivas_error error; + IVAS_REND_AudioBuffer tmpRotBuffer; + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; + int8_t combinedOrientationEnabled; + int16_t subframe_idx; push_wmops( "renderSbaToSba" ); inAudio = sbaInput->base.inputBuffer; + hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData; + combinedOrientationEnabled = 0; + if ( hCombinedOrientationData != NULL ) + { + for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ ) + { + if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + { + combinedOrientationEnabled = 1; + break; + } + } + } + + /* apply rotation */ + if ( combinedOrientationEnabled ) + { + tmpRotBuffer = inAudio; + tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); + + /* copy input for in-place rotation */ + mvr2r( sbaInput->base.inputBuffer.data, tmpRotBuffer.data, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel ); + + if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, + sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev[0], tmpRotBuffer ) ) != IVAS_ERR_OK ) + { + return error; + } + + memcpy(inAudio.data, tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); + free( tmpRotBuffer.data); + } + for ( i = 0; i < inAudio.config.numChannels; ++i ) { renderBufferChannel( inAudio, i, sbaInput->hoaDecMtx[i], outAudio ); } pop_wmops(); - return; + return IVAS_ERR_OK; } #ifdef SPLIT_REND_WITH_HEAD_ROT @@ -7108,7 +7148,7 @@ static ivas_error renderInputSba( renderSbaToMc( sbaInput, outAudio ); break; case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS: - renderSbaToSba( sbaInput, outAudio ); + error = renderSbaToSba( sbaInput, outAudio ); break; case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL: switch ( outConfig ) @@ -7155,7 +7195,7 @@ static ivas_error renderActiveInputsSba( { /* Skip inactive inputs */ continue; - } + } if ( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK ) { -- GitLab From cc43c7e15ad6be671e722e800c8771f9b2a386ad Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Tue, 14 May 2024 10:01:32 +1000 Subject: [PATCH 2/7] Adding pre-rotation to the encoder --- apps/encoder.c | 43 +++++ lib_enc/ivas_enc.c | 400 ++++++++++++++++++++++++++++++++++++++++ lib_enc/ivas_stat_enc.h | 15 ++ lib_enc/lib_enc.c | 44 +++++ lib_enc/lib_enc.h | 6 + 5 files changed, 508 insertions(+) diff --git a/apps/encoder.c b/apps/encoder.c index b00f4f75fd..1b2448db35 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -38,6 +38,7 @@ #include "ism_file_reader.h" #include "jbm_file_reader.h" #include "masa_file_reader.h" +#include "rotation_file_reader.h" #ifdef DEBUGGING #include "debug.h" #endif @@ -146,6 +147,7 @@ typedef struct #endif bool pca; bool ism_extended_metadata; + char *headRotationFilePath; } EncArguments; @@ -190,6 +192,7 @@ int main( MasaFileReader *masaReader = NULL; IsmFileReader *ismReaders[IVAS_MAX_NUM_OBJECTS] = { NULL, NULL, NULL, NULL }; int16_t *pcmBuf = NULL; + RotFileReader *headRotReader = NULL; #ifdef DEBUGGING FILE *f_forcedModeProfile = NULL; #ifdef DEBUG_SBA @@ -339,6 +342,17 @@ int main( } } + convert_backslash( arg.headRotationFilePath ); + + if ( !isEmptyString( arg.headRotationFilePath ) ) + { + if ( RotationFileReader_open( arg.headRotationFilePath, &headRotReader ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error opening file: %s\n", arg.headRotationFilePath ); + exit( -1 ); + } + } + /*------------------------------------------------------------------------------------------* * Handle Channel-aware mode *------------------------------------------------------------------------------------------*/ @@ -756,6 +770,25 @@ int main( } } + /* Read from head rotation trajectory file if specified */ + if ( headRotReader != NULL ) + { + IVAS_QUATERNION headRot; + IVAS_VECTOR3 Pos; + + if ( ( error = HeadRotationFileReading( headRotReader, &headRot, &Pos ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error in Head Rotation File Reading: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + + if ( ( error = IVAS_ENC_SetHeadRotation( hIvasEnc, headRot, Pos ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error setting Head Rotation: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + } + /* *** Encode one frame *** */ if ( ( error = IVAS_ENC_EncodeFrameToSerial( hIvasEnc, pcmBuf, pcmBufSize, bitStream, &numBits ) ) != IVAS_ERR_OK ) { @@ -839,6 +872,8 @@ cleanup: { fclose( f_bitrateProfile ); } + + RotationFileReader_close( &headRotReader ); IVAS_ENC_Close( &hIvasEnc ); @@ -1695,6 +1730,13 @@ static bool parseCmdlIVAS_enc( arg->pca = 1; i++; } + else if ( strcmp( argv_to_upper, "-TRAJECTORY_FILE" ) == 0 ) + { + fprintf( stderr, "Error: Head Roration supplied\n\n" ); + i++; + arg->headRotationFilePath = argv[i]; + i++; + } /*-----------------------------------------------------------------* * Option not recognized @@ -1913,6 +1955,7 @@ static void usage_enc( void ) #endif fprintf( stdout, "-q : Quiet mode, no frame counters\n" ); fprintf( stdout, " default is deactivated\n" ); + fprintf( stdout, "-trajectory_file F : Head rotation trajectory file for simulation of head tracking (only for SBA inputs)\n" ); fprintf( stdout, "\n" ); return; diff --git a/lib_enc/ivas_enc.c b/lib_enc/ivas_enc.c index 5ddcf9a506..854033737f 100644 --- a/lib_enc/ivas_enc.c +++ b/lib_enc/ivas_enc.c @@ -31,6 +31,7 @@ *******************************************************************************************************/ #include +#include #include "options.h" #include "cnst.h" #include "ivas_cnst.h" @@ -43,6 +44,370 @@ #endif #include "wmc_auto.h" +typedef struct +{ + int16_t numSamplesPerChannel; + int16_t numChannels; +} IVAS_ENC_AudioBufferConfig; + +typedef struct +{ + IVAS_ENC_AudioBufferConfig config; + float *data; +} IVAS_ENC_AudioBuffer; + +static float *getSmplPtr( + IVAS_ENC_AudioBuffer buffer, + const uint32_t chnlIdx, + const uint32_t smplIdx ) +{ + return buffer.data + chnlIdx * buffer.config.numSamplesPerChannel + smplIdx; +} + +static ivas_error getAmbisonicsOrder( + AUDIO_CONFIG config, + int16_t *order ) +{ + switch ( config ) + { + case IVAS_AUDIO_CONFIG_FOA: + *order = 1; + break; + case IVAS_AUDIO_CONFIG_HOA2: + *order = 2; + break; + case IVAS_AUDIO_CONFIG_HOA3: + *order = 3; + break; + default: + return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported audio config" ); + } + + return IVAS_ERR_OK; +} + +/*------------------------------------------------------------------------- + * Helper functions used by SHrotmatgen, + * an implementation of the algorithm in + * Ivanic, J. & Ruedenberg, K., J. Phys. Chem. 100, 6342 (1996) + *------------------------------------------------------------------------*/ + +static float SHrot_p( + const int16_t i, + const int16_t l, + const int16_t a, + const int16_t b, + float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], + float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM] ) +{ + float ri1 = 0.0f, rim1 = 0.0f, ri0 = 0.0f, p = 0.0f, R_lm1_1 = 0.0f, R_lm1_2 = 0.0f; + + ri1 = SHrotmat[i + 1 + 1][1 + 1 + 1]; + rim1 = SHrotmat[i + 1 + 1][-1 + 1 + 1]; + ri0 = SHrotmat[i + 1 + 1][0 + 1 + 1]; + + if ( b == -l ) + { + R_lm1_1 = R_lm1[a + l - 1][0]; + R_lm1_2 = R_lm1[a + l - 1][2 * l - 2]; + p = ri1 * R_lm1_1 + rim1 * R_lm1_2; + } + else + { + if ( b == l ) + { + R_lm1_1 = R_lm1[a + l - 1][2 * l - 2]; + R_lm1_2 = R_lm1[a + l - 1][0]; + p = ri1 * R_lm1_1 - rim1 * R_lm1_2; + } + else + { + R_lm1_1 = R_lm1[a + l - 1][b + l - 1]; + p = ri0 * R_lm1_1; + } + } + + return p; +} + +static float SHrot_u( + const int16_t l, + const int16_t m, + const int16_t n, + float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], + float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM] ) +{ + return SHrot_p( 0, l, m, n, SHrotmat, R_lm1 ); +} + +static float SHrot_v( + const int16_t l, + const int16_t m, + const int16_t n, + float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], + float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM] ) +{ + + float result, d, p0, p1; + + if ( m == 0 ) + { + p0 = SHrot_p( 1, l, 1, n, SHrotmat, R_lm1 ); + p1 = SHrot_p( -1, l, -1, n, SHrotmat, R_lm1 ); + result = p0 + p1; + } + else + { + if ( m > 0 ) + { + d = ( m == 1 ) ? 1.0f : 0.0f; + p0 = SHrot_p( 1, l, m - 1, n, SHrotmat, R_lm1 ); + p1 = SHrot_p( -1, l, -m + 1, n, SHrotmat, R_lm1 ); + result = p0 * sqrtf( 1.0f + d ) - p1 * ( 1.0f - d ); + } + else + { + d = ( m == -1 ) ? 1.0f : 0.0f; + p0 = SHrot_p( 1, l, m + 1, n, SHrotmat, R_lm1 ); + p1 = SHrot_p( -1, l, -m - 1, n, SHrotmat, R_lm1 ); + result = p0 * ( 1.0f - d ) + p1 * sqrtf( 1.0f + d ); + } + } + + return result; +} + +static float SHrot_w( + const int16_t l, + const int16_t m, + const int16_t n, + float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], + float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM] ) +{ + float result, p0, p1; + + if ( m == 0 ) + { +#ifdef SPLIT_REND_WITH_HEAD_ROT + assert( 0 && "ERROR should not be called\n" ); +#else + printf( "ERROR should not be called\n" ); +#endif + return 0.0f; + } + else + { + if ( m > 0 ) + { + p0 = SHrot_p( 1, l, m + 1, n, SHrotmat, R_lm1 ); + p1 = SHrot_p( -1, l, -m - 1, n, SHrotmat, R_lm1 ); + result = p0 + p1; + } + else + { + p0 = SHrot_p( 1, l, m - 1, n, SHrotmat, R_lm1 ); + p1 = SHrot_p( -1, l, -m + 1, n, SHrotmat, R_lm1 ); + result = p0 - p1; + } + } + + return result; +} + +static void SHrotmatgen( + float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], /* o : rotation matrix in SHD */ + float Rmat[3][3], /* i : real-space rotation matrix */ + const int16_t order /* i : ambisonics order */ +) +{ + int16_t d = 0; + int16_t band_idx = 0; + int16_t i, j; + int16_t l, m, n; + int16_t absm; + float sqdenom = 0.0f, sql2mm2 = 0.0f, sqdabsm = 0.0f, sqlabsm = 0.0f; + float u = 0.0f, v = 0.0f, w = 0.0f; + float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]; + float R_l[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]; + + SHrotmat[0][0] = 1.0f; + + SHrotmat[1][1] = Rmat[1][1]; + SHrotmat[1][2] = Rmat[1][2]; + SHrotmat[1][3] = Rmat[1][0]; + + SHrotmat[2][1] = Rmat[2][1]; + SHrotmat[2][2] = Rmat[2][2]; + SHrotmat[2][3] = Rmat[2][0]; + + SHrotmat[3][1] = Rmat[0][1]; + SHrotmat[3][2] = Rmat[0][2]; + SHrotmat[3][3] = Rmat[0][0]; + + for ( i = 0; i < 2 * 1 + 1; i++ ) + { + for ( j = 0; j < 2 * 1 + 1; j++ ) + { + R_lm1[i][j] = SHrotmat[i + 1][j + 1]; + } + } + + band_idx = 4; + for ( l = 2; l <= order; l++ ) + { + set_zero( &R_l[0][0], HEADROT_SHMAT_DIM2 ); + + for ( m = -l; m <= l; m++ ) + { + d = ( m == 0 ) ? 1 : 0; + absm = (int16_t) abs( m ); + sql2mm2 = sqrtf( (float) ( l * l - m * m ) ); + sqdabsm = sqrtf( (float) ( ( 1 + d ) * ( l + absm - 1 ) * ( l + absm ) ) ); + sqlabsm = sqrtf( (float) ( ( l - absm - 1 ) * ( l - absm ) ) ); + + for ( n = -l; n <= l; n++ ) + { + if ( abs( n ) == l ) + { + sqdenom = sqrtf( (float) ( ( 2 * l ) * ( 2 * l - 1 ) ) ); + } + else + { + sqdenom = sqrtf( (float) ( l * l - n * n ) ); + } + + u = sql2mm2 / sqdenom; + v = sqdabsm / sqdenom * ( 1 - 2 * d ) * 0.5f; + w = sqlabsm / sqdenom * ( 1 - d ) * ( -0.5f ); + + if ( u != 0 ) + { + u = u * SHrot_u( l, m, n, SHrotmat, R_lm1 ); + } + if ( v != 0 ) + { + v = v * SHrot_v( l, m, n, SHrotmat, R_lm1 ); + } + if ( w != 0 ) + { + w = w * SHrot_w( l, m, n, SHrotmat, R_lm1 ); + } + R_l[m + l][n + l] = u + v + w; + } + } + + for ( i = 0; i < 2 * l + 1; i++ ) + { + for ( j = 0; j < 2 * l + 1; j++ ) + { + SHrotmat[band_idx + i][band_idx + j] = R_l[i][j]; + } + } + + for ( i = 0; i < 2 * l + 1; i++ ) + { + for ( j = 0; j < 2 * l + 1; j++ ) + { + R_lm1[i][j] = R_l[i][j]; + } + } + + band_idx += 2 * l + 1; + } + + return; +} + +static ivas_error rotateFrameSba( + IVAS_ENC_AudioBuffer inAudio, /* i : Input Audio buffer */ + int16_t sba_order, /* i : Input Audio config */ + const ENC_HeadRotData *headRotData, /* i : Head rotation data */ + enc_rotation_gains gains_prev, /* i/o: Previous frame rotation gains */ + IVAS_ENC_AudioBuffer outAudio /* o : Output Audio buffer */ +) +{ + int16_t i, l, n, m; + int16_t m1, m2; + int16_t shd_rot_max_order; + const float *crossfade; + + float *writePtr; + enc_rotation_matrix Rmat; + float tmpRot[2 * HEADROT_ORDER + 1]; + enc_rotation_gains gains; + ivas_error error; + int16_t idx; + float val, cf, oneminuscf; + + push_wmops( "rotateFrameSba" ); + + crossfade = headRotData->crossfade; + + shd_rot_max_order = sba_order; + + /* initialize rotation matrices with zeros */ + for ( i = 0; i < HEADROT_SHMAT_DIM; i++ ) + { + set_zero( gains[i], HEADROT_SHMAT_DIM ); + } + + for ( i = 0; i < 3; i++ ) + { + /* Set to identity */ + set_zero( Rmat[i], 3 ); + Rmat[i][i] = 1.0f; + } + + /* calculate ambisonics rotation matrices for the previous and current frames */ + SHrotmatgen( gains, Rmat, shd_rot_max_order ); + + for ( i = 0; i < inAudio.config.numSamplesPerChannel; i++ ) + { + idx = i; + cf = crossfade[i]; + oneminuscf = 1 - cf; + /* As the rotation matrix becomes block diagonal in a SH basis, we can*/ + /* apply each angular-momentum block individually to save complexity. */ + + /* loop over l blocks */ + m1 = 1; + m2 = 4; + for ( l = 1; l <= shd_rot_max_order; l++ ) + { + /* compute mtx-vector product for this l */ + for ( n = m1; n < m2; n++ ) + { + tmpRot[n - m1] = 0.f; + + for ( m = m1; m < m2; m++ ) + { + val = inAudio.data[m * inAudio.config.numSamplesPerChannel + idx]; + /* crossfade with previous rotation gains */ + tmpRot[n - m1] += ( cf * gains[n][m] * val + oneminuscf * gains_prev[n][m] * val ); + } + } + /* write back the result */ + for ( n = m1; n < m2; n++ ) + { + writePtr = getSmplPtr( outAudio, n, idx ); + ( *writePtr ) = tmpRot[n - m1]; + } + m1 = m2; + m2 += 2 * ( l + 1 ) + 1; + } + } + + /* move SHrotmat to SHrotmat_prev */ + for ( i = 0; i < HEADROT_SHMAT_DIM; i++ ) + { + mvr2r( gains[i], gains_prev[i], HEADROT_SHMAT_DIM ); + } + + pop_wmops(); + + return IVAS_ERR_OK; +} + /*-------------------------------------------------------------------* * ivas_enc() * @@ -238,6 +603,41 @@ ivas_error ivas_enc( } else if ( ivas_format == SBA_FORMAT ) { + /* Rotate the SBA Scene */ + if ( st_ivas->headRotData.headRotEnabled ) + { + int16_t ch; + IVAS_ENC_AudioBuffer data_in; + data_in.config.numChannels = nchan_inp; + data_in.config.numSamplesPerChannel = n_samples_chan; + data_in.data = malloc( nchan_inp * n_samples_chan * sizeof( float ) ); + + /* Copy data to audio buffer (needs to be cleaned up) */ + for ( ch = 0; ch < nchan_inp; ++ch ) + { + mvr2r( data_f[ch], &data_in.data[ch * n_samples_chan], n_samples_chan ); + } + + IVAS_ENC_AudioBuffer data_out; + data_out.config.numChannels = nchan_inp; + data_out.config.numSamplesPerChannel = n_samples_chan; + data_out.data = malloc( nchan_inp * n_samples_chan * sizeof( float ) ); + + if ( ( error = rotateFrameSba( data_in, st_ivas->hEncoderConfig->sba_order, &st_ivas->headRotData, &st_ivas->headRotData.rot_gains_prev[0], data_out ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Copy data to audio buffer (needs to be cleaned up) */ + for ( ch = 0; ch < nchan_inp; ++ch ) + { + mvr2r( &data_out.data[ch * n_samples_chan], data_f[ch], n_samples_chan ); + } + + free( data_in.data ); + free( data_out.data ); + } + if ( ( error = ivas_spar_enc( st_ivas, data_f, input_frame, nb_bits_metadata, hMetaData ) ) != IVAS_ERR_OK ) { return error; diff --git a/lib_enc/ivas_stat_enc.h b/lib_enc/ivas_stat_enc.h index 3962ac055f..f5800cf821 100644 --- a/lib_enc/ivas_stat_enc.h +++ b/lib_enc/ivas_stat_enc.h @@ -39,6 +39,7 @@ #include "ivas_cnst.h" #include "stat_enc.h" #include "ivas_stat_com.h" +#include "common_api_types.h" /*----------------------------------------------------------------------------------* * DFT Stereo encoder structures @@ -1211,6 +1212,18 @@ typedef struct encoder_config_structure } ENCODER_CONFIG, *ENCODER_CONFIG_HANDLE; +typedef float enc_rotation_gains[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS]; +typedef float enc_rotation_matrix[3][3]; + +typedef struct +{ + int8_t headRotEnabled; + IVAS_QUATERNION headPositions; + IVAS_VECTOR3 Pos; + float crossfade[L_FRAME48k]; + enc_rotation_gains rot_gains_prev; + +} ENC_HeadRotData; /*----------------------------------------------------------------------------------* * @@ -1265,6 +1278,8 @@ typedef struct /* Stereo downmix for EVS module */ STEREO_DMX_EVS_ENC_HANDLE hStereoDmxEVS; /* Stereo downmix for EVS encoder handle */ + ENC_HeadRotData headRotData; + } Encoder_Struct; /* clang-format on */ diff --git a/lib_enc/lib_enc.c b/lib_enc/lib_enc.c index 4a4be81734..624cd6b742 100644 --- a/lib_enc/lib_enc.c +++ b/lib_enc/lib_enc.c @@ -468,6 +468,50 @@ ivas_error IVAS_ENC_FeedObjectMetadata( return error; } +/*-------------------------------------------------------------------* + * IVAS_ENC_SetHeadRotation() + * + * + *-------------------------------------------------------------------*/ + +ivas_error IVAS_ENC_SetHeadRotation( + IVAS_ENC_HANDLE hIvasEnc, /* i/o: Renderer handle */ + const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */ + const IVAS_VECTOR3 Pos /* i : listener positions for next rendering call */ +) +{ + IVAS_QUATERNION rotQuat; + + /* Validate function arguments */ + if ( hIvasEnc == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + if ( ( hIvasEnc->st_ivas->hEncoderConfig->ivas_format != SBA_FORMAT ) ) + { + /* Head rotation can be set only with binaural output */ + return IVAS_ERR_INVALID_INPUT_FORMAT; + } + + hIvasEnc->st_ivas->headRotData.headRotEnabled = 1; + + /* check for Euler angle signaling */ + if ( headRot.w == -3.0f ) + { + Euler2Quat( deg2rad( headRot.x ), deg2rad( headRot.y ), deg2rad( headRot.z ), &rotQuat ); + } + else + { + rotQuat = headRot; + } + + hIvasEnc->st_ivas->headRotData.headPositions = rotQuat; + + hIvasEnc->st_ivas->headRotData.Pos = Pos; + + return IVAS_ERR_OK; +} /*---------------------------------------------------------------------* * IVAS_ENC_ConfigureForAmbisonics() diff --git a/lib_enc/lib_enc.h b/lib_enc/lib_enc.h index 2f40c1ab1b..abd13c70f0 100644 --- a/lib_enc/lib_enc.h +++ b/lib_enc/lib_enc.h @@ -280,6 +280,12 @@ ivas_error IVAS_ENC_FeedObjectMetadata( const IVAS_ISM_METADATA metadata /* i : object metadata handle for current frame */ ); +ivas_error IVAS_ENC_SetHeadRotation( + IVAS_ENC_HANDLE hIvasEnc, /* i/o: Renderer handle */ + const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */ + const IVAS_VECTOR3 Pos /* i : listener positions for next rendering call */ +); + /*! r: error code */ ivas_error IVAS_ENC_FeedMasaMetadata( IVAS_ENC_HANDLE hIvasEnc, /* i/o: IVAS encoder handle */ -- GitLab From 512ff30722a877ab575b92fc332648ad2853af3a Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Tue, 14 May 2024 10:51:42 +1000 Subject: [PATCH 3/7] Fixing some warnings --- lib_enc/ivas_enc.c | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/lib_enc/ivas_enc.c b/lib_enc/ivas_enc.c index 854033737f..0765e73d3a 100644 --- a/lib_enc/ivas_enc.c +++ b/lib_enc/ivas_enc.c @@ -64,28 +64,6 @@ static float *getSmplPtr( return buffer.data + chnlIdx * buffer.config.numSamplesPerChannel + smplIdx; } -static ivas_error getAmbisonicsOrder( - AUDIO_CONFIG config, - int16_t *order ) -{ - switch ( config ) - { - case IVAS_AUDIO_CONFIG_FOA: - *order = 1; - break; - case IVAS_AUDIO_CONFIG_HOA2: - *order = 2; - break; - case IVAS_AUDIO_CONFIG_HOA3: - *order = 3; - break; - default: - return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported audio config" ); - } - - return IVAS_ERR_OK; -} - /*------------------------------------------------------------------------- * Helper functions used by SHrotmatgen, * an implementation of the algorithm in @@ -318,7 +296,7 @@ static void SHrotmatgen( return; } -static ivas_error rotateFrameSba( +static void rotateFrameSba( IVAS_ENC_AudioBuffer inAudio, /* i : Input Audio buffer */ int16_t sba_order, /* i : Input Audio config */ const ENC_HeadRotData *headRotData, /* i : Head rotation data */ @@ -335,7 +313,6 @@ static ivas_error rotateFrameSba( enc_rotation_matrix Rmat; float tmpRot[2 * HEADROT_ORDER + 1]; enc_rotation_gains gains; - ivas_error error; int16_t idx; float val, cf, oneminuscf; @@ -405,7 +382,7 @@ static ivas_error rotateFrameSba( pop_wmops(); - return IVAS_ERR_OK; + return; } /*-------------------------------------------------------------------* @@ -623,10 +600,7 @@ ivas_error ivas_enc( data_out.config.numSamplesPerChannel = n_samples_chan; data_out.data = malloc( nchan_inp * n_samples_chan * sizeof( float ) ); - if ( ( error = rotateFrameSba( data_in, st_ivas->hEncoderConfig->sba_order, &st_ivas->headRotData, &st_ivas->headRotData.rot_gains_prev[0], data_out ) ) != IVAS_ERR_OK ) - { - return error; - } + rotateFrameSba( data_in, st_ivas->hEncoderConfig->sba_order, &st_ivas->headRotData, &st_ivas->headRotData.rot_gains_prev[0], data_out ); /* Copy data to audio buffer (needs to be cleaned up) */ for ( ch = 0; ch < nchan_inp; ++ch ) -- GitLab From fda8764e757b60202211912f9f8afa7f68b46020 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Tue, 14 May 2024 11:01:39 +1000 Subject: [PATCH 4/7] Fixing formatting --- apps/encoder.c | 2 +- lib_enc/ivas_enc.c | 12 ++++++------ lib_enc/lib_enc.c | 4 ++-- lib_rend/lib_rend.c | 11 +++++------ 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/apps/encoder.c b/apps/encoder.c index 1b2448db35..f2d2bdca32 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -872,7 +872,7 @@ cleanup: { fclose( f_bitrateProfile ); } - + RotationFileReader_close( &headRotReader ); IVAS_ENC_Close( &hIvasEnc ); diff --git a/lib_enc/ivas_enc.c b/lib_enc/ivas_enc.c index 0765e73d3a..f1df0cdad3 100644 --- a/lib_enc/ivas_enc.c +++ b/lib_enc/ivas_enc.c @@ -297,11 +297,11 @@ static void SHrotmatgen( } static void rotateFrameSba( - IVAS_ENC_AudioBuffer inAudio, /* i : Input Audio buffer */ - int16_t sba_order, /* i : Input Audio config */ - const ENC_HeadRotData *headRotData, /* i : Head rotation data */ - enc_rotation_gains gains_prev, /* i/o: Previous frame rotation gains */ - IVAS_ENC_AudioBuffer outAudio /* o : Output Audio buffer */ + IVAS_ENC_AudioBuffer inAudio, /* i : Input Audio buffer */ + int16_t sba_order, /* i : Input Audio config */ + const ENC_HeadRotData *headRotData, /* i : Head rotation data */ + enc_rotation_gains gains_prev, /* i/o: Previous frame rotation gains */ + IVAS_ENC_AudioBuffer outAudio /* o : Output Audio buffer */ ) { int16_t i, l, n, m; @@ -605,7 +605,7 @@ ivas_error ivas_enc( /* Copy data to audio buffer (needs to be cleaned up) */ for ( ch = 0; ch < nchan_inp; ++ch ) { - mvr2r( &data_out.data[ch * n_samples_chan], data_f[ch], n_samples_chan ); + mvr2r( &data_out.data[ch * n_samples_chan], data_f[ch], n_samples_chan ); } free( data_in.data ); diff --git a/lib_enc/lib_enc.c b/lib_enc/lib_enc.c index 624cd6b742..b667e31448 100644 --- a/lib_enc/lib_enc.c +++ b/lib_enc/lib_enc.c @@ -475,9 +475,9 @@ ivas_error IVAS_ENC_FeedObjectMetadata( *-------------------------------------------------------------------*/ ivas_error IVAS_ENC_SetHeadRotation( - IVAS_ENC_HANDLE hIvasEnc, /* i/o: Renderer handle */ + IVAS_ENC_HANDLE hIvasEnc, /* i/o: Renderer handle */ const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */ - const IVAS_VECTOR3 Pos /* i : listener positions for next rendering call */ + const IVAS_VECTOR3 Pos /* i : listener positions for next rendering call */ ) { IVAS_QUATERNION rotQuat; diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 7ae10bd9ea..ed5344dfc9 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -4647,8 +4647,7 @@ ivas_error IVAS_REND_SetHeadRotation( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - if ( ( getAudioConfigType( hIvasRend->outputConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) - && ( getAudioConfigType( hIvasRend->outputConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ) + if ( ( getAudioConfigType( hIvasRend->outputConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) && ( getAudioConfigType( hIvasRend->outputConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ) { /* Head rotation can be set only with binaural output */ return IVAS_ERR_INVALID_OUTPUT_FORMAT; @@ -6715,13 +6714,13 @@ static ivas_error renderSbaToSba( mvr2r( sbaInput->base.inputBuffer.data, tmpRotBuffer.data, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel ); if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, - sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev[0], tmpRotBuffer ) ) != IVAS_ERR_OK ) + sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev[0], tmpRotBuffer ) ) != IVAS_ERR_OK ) { return error; } - memcpy(inAudio.data, tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); - free( tmpRotBuffer.data); + memcpy( inAudio.data, tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); + free( tmpRotBuffer.data ); } for ( i = 0; i < inAudio.config.numChannels; ++i ) @@ -7201,7 +7200,7 @@ static ivas_error renderActiveInputsSba( { /* Skip inactive inputs */ continue; - } + } if ( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK ) { -- GitLab From a95cfc8b5a8820e2b073868b127a8149f389f06f Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Tue, 14 May 2024 11:15:39 +1000 Subject: [PATCH 5/7] Fixing error in trajectory file loading --- apps/encoder.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/encoder.c b/apps/encoder.c index f2d2bdca32..d0e8e288c6 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -342,10 +342,10 @@ int main( } } - convert_backslash( arg.headRotationFilePath ); - - if ( !isEmptyString( arg.headRotationFilePath ) ) + if ( ( arg.headRotationFilePath != NULL ) && ( !isEmptyString( arg.headRotationFilePath ) ) ) { + convert_backslash( arg.headRotationFilePath ); + if ( RotationFileReader_open( arg.headRotationFilePath, &headRotReader ) != IVAS_ERR_OK ) { fprintf( stderr, "Error opening file: %s\n", arg.headRotationFilePath ); -- GitLab From 2491e304044290d4839a6b0bf0b4f748c49ae114 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Tue, 14 May 2024 12:09:16 +1000 Subject: [PATCH 6/7] Fixing uninitialised variable issue. --- apps/encoder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/encoder.c b/apps/encoder.c index d0e8e288c6..9c3ca51b14 100644 --- a/apps/encoder.c +++ b/apps/encoder.c @@ -930,6 +930,7 @@ static void initArgStruct( EncArguments *arg ) arg->mimeOutput = false; arg->ism_extended_metadata = false; arg->complexityLevel = IVAS_ENC_COMPLEXITY_LEVEL_THREE; + arg->headRotationFilePath = NULL; #ifdef DEBUGGING arg->forcedMode = IVAS_ENC_FORCE_UNFORCED; -- GitLab From 4c9d760da5d43ed7e0c6ebad7ccaebafc49c2d25 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Tue, 14 May 2024 12:49:28 +1000 Subject: [PATCH 7/7] Fixing MSAN issue. --- lib_enc/ivas_init_enc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib_enc/ivas_init_enc.c b/lib_enc/ivas_init_enc.c index 0371378d73..d818f53eef 100644 --- a/lib_enc/ivas_init_enc.c +++ b/lib_enc/ivas_init_enc.c @@ -930,6 +930,15 @@ ivas_error ivas_init_encoder( set_f( st_ivas->mem_hp20_in[i], 0.0f, L_HP20_MEM ); } + /*-----------------------------------------------------------------* + * Initialise Head Rotation Data + *-----------------------------------------------------------------*/ + st_ivas->headRotData.headRotEnabled = 0; + for ( i = 0; i < MAX_INPUT_CHANNELS; ++i ) + { + set_f( st_ivas->headRotData.rot_gains_prev[i], 0.0f, MAX_INPUT_CHANNELS ); + } + return error; } -- GitLab