diff --git a/Workspace_msvc/lib_util.vcxproj b/Workspace_msvc/lib_util.vcxproj index 72ff2dfe6182abfbe7d1a6783c324a3958d398a6..9c68dbb36d26bb969bf1f470c4b4d85d104e7876 100644 --- a/Workspace_msvc/lib_util.vcxproj +++ b/Workspace_msvc/lib_util.vcxproj @@ -157,6 +157,7 @@ + @@ -181,6 +182,7 @@ + diff --git a/apps/decoder.c b/apps/decoder.c index f1787da629d5f14a58460b901f5c5caa660f720c..da56077639d920f5aa486fd382dd6b89bb78d447 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -41,7 +41,11 @@ #include "ism_file_writer.h" #include "ls_custom_file_reader.h" #include "hrtf_file_reader.h" +#ifdef EXTERNAL_ORIENTATIONS +#include "rotation_file_reader.h" +#else #include "head_rotation_file_reader.h" +#endif #include "vector3_pair_file_reader.h" #include "jbm_file_writer.h" #include "evs_rtp_payload.h" @@ -100,6 +104,10 @@ typedef struct char *refrotTrajFileName; bool enableReferenceVectorTracking; char *referenceVectorTrajFileName; +#ifdef EXTERNAL_ORIENTATIONS + bool enableExternalOrientation; + char *externalOrientationTrajFileName; +#endif #ifdef SUPPORT_JBM_TRACEFILE char *jbmTraceFilename; #endif @@ -148,12 +156,20 @@ typedef struct static bool parseCmdlIVAS_dec( int16_t argc, char **argv, DecArguments *arg ); static void usage_dec( void ); +#ifdef EXTERNAL_ORIENTATIONS +static ivas_error decodeG192( DecArguments arg, BS_READER_HANDLE hBsReader, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); +#else static ivas_error decodeG192( DecArguments arg, BS_READER_HANDLE hBsReader, HeadRotFileReader *headRotReader, HeadRotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ); +#endif static ivas_error decodeVoIP( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HANDLE hIvasDec ); #ifdef DEBUGGING #ifdef VARIABLE_SPEED_DECODING +#ifdef EXTERNAL_ORIENTATIONS +static ivas_error decodeVariableSpeed( DecArguments arg, BS_READER_HANDLE hBsReader, RotFileReader *headRotReader, RotFileReader *externalOrientationFileReader, RotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, IVAS_DEC_HANDLE hIvasDec ); +#else static ivas_error decodeVariableSpeed( DecArguments arg, BS_READER_HANDLE hBsReader, HeadRotFileReader *headRotReader, HeadRotFileReader *refRotReader, Vector3PairFileReader *referenceVectorReader, IVAS_DEC_HANDLE hIvasDec ); #endif +#endif static ivas_error printBitstreamInfoVoip( DecArguments arg, BS_READER_HANDLE hBsReader, IVAS_DEC_HANDLE hIvasDec ); static int16_t app_own_random( int16_t *seed ); static IVAS_DEC_FORCED_REND_MODE parseForcedRendModeDec( char *forcedRendModeChar ); @@ -176,8 +192,14 @@ int main( BS_READER_HANDLE hBsReader = NULL; LsCustomFileReader *hLsCustomReader = NULL; hrtfFileReader *hrtfReader = NULL; +#ifdef EXTERNAL_ORIENTATIONS + RotFileReader *headRotReader = NULL; + RotFileReader *externalOrientationFileReader = NULL; + RotFileReader *refRotReader = NULL; +#else HeadRotFileReader *headRotReader = NULL; HeadRotFileReader *refRotReader = NULL; +#endif Vector3PairFileReader *referenceVectorReader = NULL; ivas_error error = IVAS_ERR_UNKNOWN; int16_t pcmBuf[MAX_OUTPUT_PCM_BUFFER_SIZE]; @@ -281,7 +303,11 @@ int main( goto cleanup; } +#ifdef EXTERNAL_ORIENTATIONS + if ( ( error = RotationFileReader_open( arg.headrotTrajFileName, &headRotReader ) ) != IVAS_ERR_OK ) +#else if ( ( error = HeadRotationFileReader_open( arg.headrotTrajFileName, &headRotReader ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError: Can't open head-rotation file %s \n\n", arg.headrotTrajFileName ); goto cleanup; @@ -308,7 +334,11 @@ int main( goto cleanup; } +#ifdef EXTERNAL_ORIENTATIONS + if ( ( error = RotationFileReader_open( arg.refrotTrajFileName, &refRotReader ) ) != IVAS_ERR_OK ) +#else if ( ( error = HeadRotationFileReader_open( arg.refrotTrajFileName, &refRotReader ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError: Can't open reference rotation file %s \n\n", arg.refrotTrajFileName ); goto cleanup; @@ -342,6 +372,21 @@ int main( } } +#ifdef EXTERNAL_ORIENTATIONS + /*------------------------------------------------------------------------------------------* + * Open external orientation file + *------------------------------------------------------------------------------------------*/ + + if ( arg.enableExternalOrientation ) + { + if ( ( error = RotationFileReader_open( arg.externalOrientationTrajFileName, &externalOrientationFileReader ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: Can't open external orientation file %s \n\n", arg.externalOrientationTrajFileName ); + goto cleanup; + } + } +#endif + /*------------------------------------------------------------------------------------------* * Open custom loudspeaker layout file *------------------------------------------------------------------------------------------*/ @@ -378,7 +423,11 @@ int main( /*------------------------------------------------------------------------------------------* * Configure the decoder *------------------------------------------------------------------------------------------*/ +#ifdef EXTERNAL_ORIENTATIONS + if ( ( error = IVAS_DEC_Configure( hIvasDec, arg.output_Fs, arg.outputFormat, arg.customLsOutputEnabled, arg.hrtfReaderEnabled, arg.enableHeadRotation, arg.enableExternalOrientation, arg.orientation_tracking, arg.renderConfigEnabled, arg.Opt_non_diegetic_pan, arg.non_diegetic_pan_gain, arg.delayCompensationEnabled ) ) != IVAS_ERR_OK ) +#else if ( ( error = IVAS_DEC_Configure( hIvasDec, arg.output_Fs, arg.outputFormat, arg.customLsOutputEnabled, arg.hrtfReaderEnabled, arg.enableHeadRotation, arg.orientation_tracking, arg.renderConfigEnabled, arg.Opt_non_diegetic_pan, arg.non_diegetic_pan_gain, arg.delayCompensationEnabled ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nConfigure failed: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); @@ -642,13 +691,21 @@ int main( #ifdef DEBUGGING else if ( arg.variableSpeedMode ) { - error = decodeVariableSpeed( arg, hBsReader, headRotReader, refRotReader, referenceVectorReader, hIvasDec ); + error = decodeVariableSpeed( arg, hBsReader, headRotReader, +#ifdef EXTERNAL_ORIENTATIONS + externalOrientationFileReader, +#endif + refRotReader, referenceVectorReader, hIvasDec ); } #endif #endif else { - error = decodeG192( arg, hBsReader, headRotReader, refRotReader, referenceVectorReader, hIvasDec, pcmBuf ); + error = decodeG192( arg, hBsReader, headRotReader, +#ifdef EXTERNAL_ORIENTATIONS + externalOrientationFileReader, +#endif + refRotReader, referenceVectorReader, hIvasDec, pcmBuf ); } if ( error == IVAS_ERR_OK || error == IVAS_ERR_END_OF_FILE ) @@ -711,8 +768,14 @@ cleanup: IVAS_DEC_Close( &hIvasDec ); CustomLsReader_close( &hLsCustomReader ); hrtfFileReader_close( &hrtfReader ); +#ifdef EXTERNAL_ORIENTATIONS + RotationFileReader_close( &headRotReader ); + RotationFileReader_close( &externalOrientationFileReader ); + RotationFileReader_close( &refRotReader ); +#else HeadRotationFileReader_close( &headRotReader ); HeadRotationFileReader_close( &refRotReader ); +#endif Vector3PairFileReader_close( &referenceVectorReader ); RenderConfigReader_close( &renderConfigReader ); @@ -856,6 +919,10 @@ static bool parseCmdlIVAS_dec( arg->headrotTrajFileName = NULL; arg->enableReferenceVectorTracking = false; arg->referenceVectorTrajFileName = NULL; +#ifdef EXTERNAL_ORIENTATIONS + arg->enableExternalOrientation = false; + arg->externalOrientationTrajFileName = NULL; +#endif #ifdef SUPPORT_JBM_TRACEFILE arg->jbmTraceFilename = NULL; @@ -1166,6 +1233,23 @@ static bool parseCmdlIVAS_dec( arg->referenceVectorTrajFileName = argv[i]; i++; } +#ifdef EXTERNAL_ORIENTATIONS + else if ( strcmp( argv_to_upper, "-EXOF" ) == 0 ) + { + arg->enableExternalOrientation = true; + i++; + + if ( argc - i <= 4 || argv[i][0] == '-' ) + { + fprintf( stderr, "Error: External orientation file name not specified!\n\n" ); + usage_dec(); + return false; + } + + arg->externalOrientationTrajFileName = argv[i]; + i++; + } +#endif else if ( strcmp( argv_to_upper, "-RENDER_CONFIG" ) == 0 ) { arg->renderConfigEnabled = true; @@ -1404,6 +1488,9 @@ static void usage_dec( void ) fprintf( stdout, "-level level : Complexity level, level = (1, 2, 3), will be defined after characterisation. \n" ); fprintf( stdout, " Currently, all values default to level 3 (full functionality).\n" ); #endif +#ifdef EXTERNAL_ORIENTATIONS + fprintf( stdout, "-exof File : External orientation file for external orientation trajectory\n" ); +#endif #ifdef DEBUG_MODE_INFO #ifdef DEBUG_MODE_INFO_TWEAK fprintf( stdout, "-info : specify subfolder name for debug output\n" ); @@ -1591,8 +1678,14 @@ static ivas_error initOnFirstGoodFrame( static ivas_error decodeG192( DecArguments arg, BS_READER_HANDLE hBsReader, +#ifdef EXTERNAL_ORIENTATIONS + RotFileReader *headRotReader, + RotFileReader *externalOrientationFileReader, + RotFileReader *refRotReader, +#else HeadRotFileReader *headRotReader, HeadRotFileReader *refRotReader, +#endif Vector3PairFileReader *referenceVectorReader, IVAS_DEC_HANDLE hIvasDec, int16_t *pcmBuf ) @@ -1707,7 +1800,12 @@ static ivas_error decodeG192( IVAS_QUATERNION quaternion; if ( ( error = HeadRotationFileReading( refRotReader, &quaternion, NULL ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), HeadRotationFileReader_getFilePath( refRotReader ) ); + fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), +#ifdef EXTERNAL_ORIENTATIONS + RotationFileReader_getFilePath( refRotReader ) ); +#else + HeadRotationFileReader_getFilePath( refRotReader ) ); +#endif goto cleanup; } @@ -1726,7 +1824,12 @@ static ivas_error decodeG192( { if ( ( error = HeadRotationFileReading( headRotReader, &Quaternions[i], &Pos[i] ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), HeadRotationFileReader_getFilePath( headRotReader ) ); + fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), +#ifdef EXTERNAL_ORIENTATIONS + RotationFileReader_getFilePath( headRotReader ) ); +#else + HeadRotationFileReader_getFilePath( headRotReader ) ); +#endif goto cleanup; } } @@ -1737,6 +1840,35 @@ static ivas_error decodeG192( goto cleanup; } } + +#ifdef EXTERNAL_ORIENTATIONS + if ( arg.enableExternalOrientation ) + { + IVAS_QUATERNION Quaternions[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableHeadRotation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableExternalOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableRotationInterpolation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int16_t numFramesToTargetOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + + for ( i = 0; i < IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + + if ( ( error = ExternalOrientationFileReading( externalOrientationFileReader, &Quaternions[i], &enableHeadRotation[i], &enableExternalOrientation[i], &enableRotationInterpolation[i], &numFramesToTargetOrientation[i] ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading external orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), + RotationFileReader_getFilePath( externalOrientationFileReader ) ); + goto cleanup; + } + } + + if ( ( error = IVAS_DEC_FeedExternalOrientationData( hIvasDec, Quaternions, enableHeadRotation, enableExternalOrientation, enableRotationInterpolation, numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedExternalOrientationData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } +#endif + /* Run decoder for one frame (get rendered output) */ if ( ( error = IVAS_DEC_GetSamples( hIvasDec, pcmBuf, &nOutSamples ) ) != IVAS_ERR_OK ) { @@ -2469,8 +2601,14 @@ cleanup: static ivas_error decodeVariableSpeed( DecArguments arg, BS_READER_HANDLE hBsReader, +#ifdef EXTERNAL_ORIENTATIONS + RotFileReader *headRotReader, + RotFileReader *externalOrientationFileReader, + RotFileReader *refRotReader, +#else HeadRotFileReader *headRotReader, HeadRotFileReader *refRotReader, +#endif Vector3PairFileReader *referenceVectorReader, IVAS_DEC_HANDLE hIvasDec ) @@ -2574,7 +2712,12 @@ static ivas_error decodeVariableSpeed( IVAS_QUATERNION quaternion; if ( ( error = HeadRotationFileReading( refRotReader, &quaternion, NULL ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), HeadRotationFileReader_getFilePath( refRotReader ) ); + fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), +#ifdef EXTERNAL_ORIENTATIONS + RotationFileReader_getFilePath( refRotReader ) ); +#else + HeadRotationFileReader_getFilePath( refRotReader ) ); +#endif goto cleanup; } @@ -2594,7 +2737,12 @@ static ivas_error decodeVariableSpeed( { if ( ( error = HeadRotationFileReading( headRotReader, &Quaternions[i], &Pos[i] ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), HeadRotationFileReader_getFilePath( headRotReader ) ); + fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), +#ifdef EXTERNAL_ORIENTATIONS + RotationFileReader_getFilePath( headRotReader ) ); +#else + HeadRotationFileReader_getFilePath( headRotReader ) ); +#endif goto cleanup; } } @@ -2606,6 +2754,34 @@ static ivas_error decodeVariableSpeed( } } +#ifdef EXTERNAL_ORIENTATIONS + if ( arg.enableExternalOrientation ) + { + IVAS_QUATERNION Quaternions[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableHeadRotation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableExternalOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableRotationInterpolation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int16_t numFramesToTargetOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + + for ( i = 0; i < IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + + if ( ( error = ExternalOrientationFileReading( externalOrientationFileReader, &Quaternions[i], &enableHeadRotation[i], &enableExternalOrientation[i], &enableRotationInterpolation[i], &numFramesToTargetOrientation[i] ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading external orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), + RotationFileReader_getFilePath( externalOrientationFileReader ) ); + goto cleanup; + } + } + + if ( ( error = IVAS_DEC_FeedExternalOrientationData( hIvasDec, Quaternions, enableHeadRotation, enableExternalOrientation, enableRotationInterpolation, numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedExternalOrientationData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } +#endif + /* decode and get samples */ do { @@ -2827,7 +3003,12 @@ static ivas_error decodeVariableSpeed( IVAS_QUATERNION quaternion; if ( ( error = HeadRotationFileReading( refRotReader, &quaternion, NULL ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), HeadRotationFileReader_getFilePath( refRotReader ) ); + fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), +#ifdef EXTERNAL_ORIENTATIONS + RotationFileReader_getFilePath( refRotReader ) ); +#else + HeadRotationFileReader_getFilePath( refRotReader ) ); +#endif goto cleanup; } @@ -2846,7 +3027,12 @@ static ivas_error decodeVariableSpeed( { if ( ( error = HeadRotationFileReading( headRotReader, &Quaternions[i], &Pos[i] ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), HeadRotationFileReader_getFilePath( headRotReader ) ); + fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), +#ifdef EXTERNAL_ORIENTATIONS + RotationFileReader_getFilePath( headRotReader ) ); +#else + HeadRotationFileReader_getFilePath( headRotReader ) ); +#endif goto cleanup; } } @@ -2858,6 +3044,34 @@ static ivas_error decodeVariableSpeed( } } +#ifdef EXTERNAL_ORIENTATIONS + if ( arg.enableExternalOrientation ) + { + IVAS_QUATERNION Quaternions[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableHeadRotation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableExternalOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableRotationInterpolation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int16_t numFramesToTargetOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + + for ( i = 0; i < IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + + if ( ( error = ExternalOrientationFileReading( externalOrientationFileReader, &Quaternions[i], &enableHeadRotation[i], &enableExternalOrientation[i], &enableRotationInterpolation[i], &numFramesToTargetOrientation[i] ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading external orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), + RotationFileReader_getFilePath( externalOrientationFileReader ) ); + goto cleanup; + } + } + + if ( ( error = IVAS_DEC_FeedExternalOrientationData( hIvasDec, Quaternions, enableHeadRotation, enableExternalOrientation, enableRotationInterpolation, numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedExternalOrientationData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } +#endif + /* decode and get samples */ if ( ( error = IVAS_DEC_VoIP_Flush( hIvasDec, nOutSamples, pcmBuf, &nSamplesAvailableNext, &nSamplesFlushed ) ) != IVAS_ERR_OK ) { diff --git a/apps/renderer.c b/apps/renderer.c index d285499e224742a0eb0f18376c648493af7860d4..7bee92331fab3321ff1a15ecff32ea6248297a23 100644 --- a/apps/renderer.c +++ b/apps/renderer.c @@ -41,7 +41,11 @@ #include "audio_file_writer.h" #include "cmdl_tools.h" #include "cmdln_parser.h" +#ifdef EXTERNAL_ORIENTATIONS +#include "rotation_file_reader.h" +#else #include "head_rotation_file_reader.h" +#endif #include "vector3_pair_file_reader.h" #include "hrtf_file_reader.h" #include "ism_file_reader.h" @@ -142,6 +146,9 @@ typedef struct char headRotationFilePath[RENDERER_MAX_CLI_ARG_LENGTH]; char referenceVectorFilePath[RENDERER_MAX_CLI_ARG_LENGTH]; char referenceRotationFilePath[RENDERER_MAX_CLI_ARG_LENGTH]; +#ifdef EXTERNAL_ORIENTATIONS + char externalOrientationFilePath[RENDERER_MAX_CLI_ARG_LENGTH]; +#endif char customHrtfFilePath[RENDERER_MAX_CLI_ARG_LENGTH]; char renderConfigFilePath[RENDERER_MAX_CLI_ARG_LENGTH]; int8_t orientation_tracking; @@ -180,6 +187,9 @@ typedef enum CmdLnOptionId_listFormats, CmdLnOptionId_inputGain, CmdLnOptionId_referenceVectorFile, +#ifdef EXTERNAL_ORIENTATIONS + CmdLnOptionId_exteriorOrientationFile, +#endif } CmdLnOptionId; static const CmdLnParser_Option cliOptions[] = { @@ -299,6 +309,14 @@ static const CmdLnParser_Option cliOptions[] = { .matchShort = "rvf", .description = "Reference vector trajectory file for simulation of head tracking (only for BINAURAL and BINAURAL_ROOM outputs)", }, +#ifdef EXTERNAL_ORIENTATIONS + { + .id = CmdLnOptionId_exteriorOrientationFile, + .match = "exterior_orientation_file", + .matchShort = "exof", + .description = "External orientation trajectory file for simulation of external orientations", + }, +#endif }; @@ -537,9 +555,15 @@ int main( char **argv ) { IVAS_REND_HANDLE hIvasRend; +#ifdef EXTERNAL_ORIENTATIONS + RotFileReader *headRotReader = NULL; + RotFileReader *externalOrientationFileReader = NULL; + RotFileReader *referenceRotReader = NULL; +#else HeadRotFileReader *headRotReader = NULL; - Vector3PairFileReader *referenceVectorReader = NULL; HeadRotFileReader *referenceRotReader = NULL; +#endif + Vector3PairFileReader *referenceVectorReader = NULL; hrtfFileReader *hrtfFileReader = NULL; IsmPositionProvider *positionProvider; #ifdef FIX_296_CFG_LFE_SCENE_DESC @@ -609,10 +633,17 @@ int main( convert_backslash( args.referenceVectorFilePath ); convert_backslash( args.referenceRotationFilePath ); convert_backslash( args.inLfePanningMatrixFile ); +#ifdef EXTERNAL_ORIENTATIONS + convert_backslash( args.externalOrientationFilePath ); +#endif if ( !isEmptyString( args.headRotationFilePath ) ) { +#ifdef EXTERNAL_ORIENTATIONS + if ( RotationFileReader_open( args.headRotationFilePath, &headRotReader ) != IVAS_ERR_OK ) +#else if ( HeadRotationFileReader_open( args.headRotationFilePath, &headRotReader ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "Error opening file: %s\n", args.headRotationFilePath ); exit( -1 ); @@ -621,7 +652,11 @@ int main( if ( !isEmptyString( args.referenceRotationFilePath ) ) { +#ifdef EXTERNAL_ORIENTATIONS + if ( RotationFileReader_open( args.referenceRotationFilePath, &referenceRotReader ) != IVAS_ERR_OK ) +#else if ( HeadRotationFileReader_open( args.referenceRotationFilePath, &referenceRotReader ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "Error opening file: %s\n", args.referenceRotationFilePath ); exit( -1 ); @@ -636,6 +671,17 @@ int main( } } +#ifdef EXTERNAL_ORIENTATIONS + if ( !isEmptyString( args.externalOrientationFilePath ) ) + { + if ( RotationFileReader_open( args.externalOrientationFilePath, &externalOrientationFileReader ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error opening file: %s\n", args.externalOrientationFilePath ); + exit( -1 ); + } + } +#endif + if ( !isEmptyString( args.customHrtfFilePath ) ) { if ( hrtfFileReader_open( args.customHrtfFilePath, &hrtfFileReader ) != IVAS_ERR_OK ) @@ -1066,6 +1112,41 @@ int main( } } +#ifdef EXTERNAL_ORIENTATIONS + /* Read from external orientation file if specified */ + if ( externalOrientationFileReader != NULL ) + { + IVAS_QUATERNION quatBuffer[RENDERER_HEAD_POSITIONS_PER_FRAME]; + int8_t enableHeadRotation[RENDERER_HEAD_POSITIONS_PER_FRAME]; + int8_t enableExternalOrientation[RENDERER_HEAD_POSITIONS_PER_FRAME]; + int8_t enableRotationInterpolation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int16_t numFramesToTargetOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + + for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) + { + if ( ( error = ExternalOrientationFileReading( externalOrientationFileReader, &quatBuffer[i], &enableHeadRotation[i], &enableExternalOrientation[i], &enableRotationInterpolation[i], &numFramesToTargetOrientation[i] ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error in External Orientation File Reading: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + } + + if ( ( error = IVAS_REND_SetExternalOrientation( hIvasRend, quatBuffer, enableHeadRotation, enableExternalOrientation, enableRotationInterpolation, numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error setting External Orientation: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + } + + /* Combine external orientations and head rotation */ + + if ( ( error = IVAS_REND_CombineHeadAndExternalOrientation( hIvasRend ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error combining external and head orientations: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } +#endif + for ( i = 0; i < args.inConfig.numMultiChannelBuses; ++i ) { if ( ( error = IVAS_REND_GetInputNumChannels( hIvasRend, mcIds[i], &numChannels ) ) != IVAS_ERR_OK ) @@ -1244,9 +1325,15 @@ int main( #endif AudioFileReader_close( &audioReader ); AudioFileWriter_close( &audioWriter ); +#ifdef EXTERNAL_ORIENTATIONS + RotationFileReader_close( &headRotReader ); + RotationFileReader_close( &externalOrientationFileReader ); + RotationFileReader_close( &referenceRotReader ); +#else HeadRotationFileReader_close( &headRotReader ); - Vector3PairFileReader_close( &referenceVectorReader ); HeadRotationFileReader_close( &referenceRotReader ); +#endif + Vector3PairFileReader_close( &referenceVectorReader ); hrtfFileReader_close( &hrtfFileReader ); IVAS_REND_Close( &hIvasRend ); IsmPositionProvider_close( positionProvider ); @@ -1712,6 +1799,9 @@ static CmdlnArgs defaultArgs( clearString( args.referenceRotationFilePath ); clearString( args.customHrtfFilePath ); clearString( args.renderConfigFilePath ); +#ifdef EXTERNAL_ORIENTATIONS + clearString( args.externalOrientationFilePath ); +#endif args.orientation_tracking = HEAD_ORIENT_TRK_NONE; args.nonDiegeticPan = 0; @@ -1802,6 +1892,12 @@ static void parseOption( assert( numOptionValues == 1 ); strncpy( args->referenceRotationFilePath, optionValues[0], RENDERER_MAX_CLI_ARG_LENGTH - 1 ); break; +#ifdef EXTERNAL_ORIENTATIONS + case CmdLnOptionId_exteriorOrientationFile: + assert( numOptionValues == 1 ); + strncpy( args->externalOrientationFilePath, optionValues[0], RENDERER_MAX_CLI_ARG_LENGTH - 1 ); + break; +#endif case CmdLnOptionId_customHrtfFile: assert( numOptionValues == 1 ); strncpy( args->customHrtfFilePath, optionValues[0], RENDERER_MAX_CLI_ARG_LENGTH - 1 ); diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index 0fae8ff215c57979cdd682cf5600f1d1f62260fa..eb71119d9e213ba56eed93eba2fc94b7b79d7490 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -75,6 +75,9 @@ typedef enum IVAS_ERR_WRONG_MODE, IVAS_ERR_INVALID_OUTPUT_FORMAT, IVAS_ERR_HEAD_ROTATION_NOT_SUPPORTED, +#ifdef EXTERNAL_ORIENTATIONS + IVAS_ERR_EXT_ORIENTATION_NOT_SUPPORTED, +#endif IVAS_ERR_INVALID_HRTF, IVAS_ERR_INVALID_INPUT_FORMAT, IVAS_ERR_INVALID_INDEX, /* ToDo: should be merged with IVAS_ERR_INDEX_OUT_OF_BOUNDS */ @@ -232,6 +235,10 @@ static inline const char *ivas_error_to_string( ivas_error error_code ) return "Wrong mode"; case IVAS_ERR_HEAD_ROTATION_NOT_SUPPORTED: return "Head rotation not supported"; +#ifdef EXTERNAL_ORIENTATIONS + case IVAS_ERR_EXT_ORIENTATION_NOT_SUPPORTED: + return "External orientation not supported"; +#endif case IVAS_ERR_INVALID_HRTF: return "Unsupported HRTF filter set"; case IVAS_ERR_INVALID_INPUT_FORMAT: diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 2ad9dc88054636fee8eb4e3150691be45a048854..b4759ee7208a8323918efd36d697c50d8db25f5d 100644 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -118,7 +118,7 @@ ivas_error ivas_spar_md_enc_init const int16_t sba_order /* i : Ambisonic (SBA) order */ ); -ivas_error ivas_sba_enc_reconfigure( +ivas_error ivas_sba_enc_reconfigure( Encoder_Struct *st_ivas /* i/o: IVAS encoder structure */ ); /*! r: maximum SBA metadata bit-budget */ @@ -822,11 +822,11 @@ void ivas_jbm_dec_get_md_map( int16_t *map /* o : metadata index map */ ); -int16_t ivas_jbm_dec_get_num_tc_channels( +int16_t ivas_jbm_dec_get_num_tc_channels( Decoder_Struct *st_ivas /* i : IVAS decoder handle */ ); -TC_BUFFER_MODE ivas_jbm_dec_get_tc_buffer_mode( +TC_BUFFER_MODE ivas_jbm_dec_get_tc_buffer_mode( Decoder_Struct *st_ivas /* i : IVAS decoder handle */ ); @@ -3181,7 +3181,7 @@ void restore_metadata_buffer( #ifndef IND_LIST_DYN const int16_t last_ind_start, #endif - const int16_t bit_pos_start + const int16_t bit_pos_start ); /*! r: codeword index */ @@ -3526,7 +3526,7 @@ void ivas_dirac_enc( const int16_t dtx_vad, /* i : DTX vad flag */ const IVAS_FORMAT ivas_format, /* i : ivas format */ int16_t hodirac_flag /* i : hodirac flag */ -); +); ivas_error ivas_dirac_config( void *st_ivas, /* i/o: IVAS encoder/decoder state structure */ const int16_t enc_dec /* i : encoder or decoder flag */ @@ -3547,7 +3547,7 @@ void ivas_get_dirac_sba_max_md_bits( int16_t *bits_frame_nominal, int16_t *metadata_max_bits, int16_t *qmetadata_max_bit_req, - const int16_t nbands + const int16_t nbands ); ivas_error ivas_dirac_sba_config( @@ -4831,25 +4831,25 @@ int16_t ivas_get_bits_to_encode( int32_t val ); -void ivas_huffman_encode( - ivas_huffman_cfg_t *huff_cfg, - int16_t in, - int16_t *hcode, - int16_t *hlen +void ivas_huffman_encode( + ivas_huffman_cfg_t *huff_cfg, + int16_t in, + int16_t *hcode, + int16_t *hlen ); -void ivas_spar_huff_coeffs_com_init( - ivas_huff_coeffs_t *pHuff_coeffs, - ivas_spar_md_com_cfg *pSpar_cfg, - const int16_t table_idx, - const int16_t enc_dec +void ivas_spar_huff_coeffs_com_init( + ivas_huff_coeffs_t *pHuff_coeffs, + ivas_spar_md_com_cfg *pSpar_cfg, + const int16_t table_idx, + const int16_t enc_dec ); -void ivas_spar_arith_coeffs_com_init( +void ivas_spar_arith_coeffs_com_init( ivas_arith_coeffs_t *pArith_coeffs, ivas_spar_md_com_cfg *pSpar_cfg, - const int16_t table_idx, - const int16_t enc_dec + const int16_t table_idx, + const int16_t enc_dec ); int16_t ivas_arith_encode_cmplx_cell_array( @@ -4866,74 +4866,74 @@ int16_t ivas_arith_encode_cmplx_cell_array( const int16_t wc_strat_arith ); -ivas_error ivas_huffman_decode( - ivas_huffman_cfg_t *huff_cfg, - Decoder_State *st0, - int16_t *dec_out +ivas_error ivas_huffman_decode( + ivas_huffman_cfg_t *huff_cfg, + Decoder_State *st0, + int16_t *dec_out ); -void ivas_arith_decode_cmplx_cell_array( - ivas_arith_t *pArith_re, - ivas_arith_t *pArith_re_diff, +void ivas_arith_decode_cmplx_cell_array( + ivas_arith_t *pArith_re, + ivas_arith_t *pArith_re_diff, Decoder_State *st0, - ivas_cell_dim_t *pCell_dims, - int16_t *pDo_diff, const int16_t nB, + ivas_cell_dim_t *pCell_dims, + int16_t *pDo_diff, const int16_t nB, int16_t *pSymbol_re, - int16_t *pSymbol_re_old + int16_t *pSymbol_re_old ); -void ivas_ari_start_decoding_14bits_ext_1_lfe( +void ivas_ari_start_decoding_14bits_ext_1_lfe( Decoder_State *st, - Tastat *s, - int16_t *extra_bits_read + Tastat *s, + int16_t *extra_bits_read ); -uint16_t ivas_ari_decode_14bits_bit_ext_1_lfe( - Decoder_State *st, Tastat *s, - const uint16_t *cum_freq, - int16_t *extra_bits_read +uint16_t ivas_ari_decode_14bits_bit_ext_1_lfe( + Decoder_State *st, Tastat *s, + const uint16_t *cum_freq, + int16_t *extra_bits_read ); -void ivas_ari_done_decoding_14bits_ext_1_lfe( - Decoder_State *st, - const int16_t extra_bits_read +void ivas_ari_done_decoding_14bits_ext_1_lfe( + Decoder_State *st, + const int16_t extra_bits_read ); -void ivas_ari_done_encoding_14bits( - BSTR_ENC_HANDLE hBstr, Tastat *s +void ivas_ari_done_encoding_14bits( + BSTR_ENC_HANDLE hBstr, Tastat *s ); -void ivas_ari_encode_14bits_ext( - BSTR_ENC_HANDLE hBstr, - Tastat *s, - int32_t symbol, - const uint16_t *cum_freq +void ivas_ari_encode_14bits_ext( + BSTR_ENC_HANDLE hBstr, + Tastat *s, + int32_t symbol, + const uint16_t *cum_freq ); -void ivas_wrap_arround( - int16_t *pArr, +void ivas_wrap_arround( + int16_t *pArr, const int16_t min_val, - const int16_t max_val, - const int16_t length + const int16_t max_val, + const int16_t length ); -void ivas_get_cum_freq_model( - const int16_t *pFreq_model, - const int16_t length, - int16_t *pCum_freq_model +void ivas_get_cum_freq_model( + const int16_t *pFreq_model, + const int16_t length, + int16_t *pCum_freq_model ); -int16_t ivas_map_num_pred_r_to_idx( - const int16_t num_quant_points_pred_r, - const int16_t active_w_flag +int16_t ivas_map_num_pred_r_to_idx( + const int16_t num_quant_points_pred_r, + const int16_t active_w_flag ); -int16_t ivas_map_num_drct_r_to_idx( - const int16_t num_quant_points_drct_r +int16_t ivas_map_num_drct_r_to_idx( + const int16_t num_quant_points_drct_r ); -int16_t ivas_map_num_decd_r_to_idx( - const int16_t num_quant_points_decd_r +int16_t ivas_map_num_decd_r_to_idx( + const int16_t num_quant_points_decd_r ); /* Quantization utilities */ @@ -5160,6 +5160,10 @@ void ivas_binaural_cldfb_sf( void ivas_binRenderer( BINAURAL_RENDERER_HANDLE hBinRenderer, /* i/o: fastconv binaural renderer handle */ HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i/o: head track handle */ +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined head and external orientation handle */ + int16_t subframe_idx, /* i : subframe index */ +#endif const int16_t numTimeSlots, /* i: : number of time slots to process */ float Cldfb_RealBuffer_Binaural[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* o : Binaural signals */ float Cldfb_ImagBuffer_Binaural[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* o : Binaural signals */ diff --git a/lib_com/options.h b/lib_com/options.h index 555c98b76064c134cd7e1e9d8f2802275cf6ca49..5e87b2e031e6ca889d6e8901a8724b02c469b27c 100755 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -168,6 +168,7 @@ #define FIX_511_OPTIMIZE_PARAMBIN_GAIN_FETCH /* Nokia: Issue 511, significant optimization of parametric binauralizer gain fetching. */ #define FIX_531_BWS_ISM_BFI /* VA: issue 531: fix MemorySanitizer: use-of-uninitialized-value in ISM2 rate switching with frame errors */ +#define EXTERNAL_ORIENTATIONS /* Nokia: Contribution 41: (external) orientation information handling */ /* ################## End DEVELOPMENT switches ######################### */ /* clang-format on */ diff --git a/lib_dec/ivas_binRenderer_internal.c b/lib_dec/ivas_binRenderer_internal.c index 2e0c4f782925cee27c75aebefb444e789066c918..074a7c3cdbfc9fcd868ce7ea9292c244f17d9d01 100644 --- a/lib_dec/ivas_binRenderer_internal.c +++ b/lib_dec/ivas_binRenderer_internal.c @@ -805,7 +805,11 @@ ivas_error ivas_binRenderer_open( ivas_dirac_dec_get_response( (int16_t) ls_azimuth_CICP19[k], (int16_t) ls_elevation_CICP19[k], hBinRenderer->hReverb->foa_enc[k], 1 ); } } +#ifdef EXTERNAL_ORIENTATIONS + else if ( st_ivas->ivas_format == MC_FORMAT && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#else else if ( st_ivas->ivas_format == MC_FORMAT && st_ivas->hDecoderConfig->Opt_Headrotation ) +#endif { if ( ( error = efap_init_data( &( st_ivas->hEFAPdata ), st_ivas->hIntSetup.ls_azimuth, st_ivas->hIntSetup.ls_elevation, st_ivas->hIntSetup.nchan_out_woLFE, EFAP_MODE_EFAP ) ) != IVAS_ERR_OK ) { @@ -1036,7 +1040,12 @@ void ivas_binaural_cldfb( } /* Implement binaural rendering */ +#ifdef EXTERNAL_ORIENTATIONS + ivas_binRenderer( st_ivas->hBinRenderer, st_ivas->hHeadTrackData, st_ivas->hCombinedOrientationData, subframeIdx, JBM_CLDFB_SLOTS_IN_SUBFRAME, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, Cldfb_RealBuffer, Cldfb_ImagBuffer ); +#else ivas_binRenderer( st_ivas->hBinRenderer, st_ivas->hHeadTrackData, JBM_CLDFB_SLOTS_IN_SUBFRAME, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, Cldfb_RealBuffer, Cldfb_ImagBuffer ); +#endif + /* Implement CLDFB synthesis */ for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) { @@ -1127,7 +1136,11 @@ void ivas_binaural_cldfb_sf( } /* Implement binaural rendering */ +#ifdef EXTERNAL_ORIENTATIONS + ivas_binRenderer( st_ivas->hBinRenderer, st_ivas->hHeadTrackData, st_ivas->hCombinedOrientationData, subframeIdx, st_ivas->hTcBuffer->subframe_nbslots[subframeIdx], Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, Cldfb_RealBuffer, Cldfb_ImagBuffer ); +#else ivas_binRenderer( st_ivas->hBinRenderer, st_ivas->hHeadTrackData, st_ivas->hTcBuffer->subframe_nbslots[subframeIdx], Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, Cldfb_RealBuffer, Cldfb_ImagBuffer ); +#endif /* Implement CLDFB synthesis */ for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) @@ -1161,8 +1174,12 @@ void ivas_binaural_cldfb_sf( *-------------------------------------------------------------------------*/ void ivas_binRenderer( - BINAURAL_RENDERER_HANDLE hBinRenderer, /* i/o: binaural renderer handle */ - HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i/o: head track handle */ + BINAURAL_RENDERER_HANDLE hBinRenderer, /* i/o: binaural renderer handle */ + HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i/o: head track handle */ +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined head and external orientation handle */ + int16_t subframe_idx, /* i : subframe index */ +#endif const int16_t numTimeSlots, /* i : number of time slots to render*/ float Cldfb_RealBuffer_Binaural[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* o : Binaural signals */ float Cldfb_ImagBuffer_Binaural[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* o : Binaural signals */ @@ -1186,25 +1203,43 @@ void ivas_binRenderer( } /* Head rotation in HOA3 or CICPx */ - if ( hHeadTrackData && hHeadTrackData->num_quaternions >= 0 && hBinRenderer->rotInCldfb ) + if ( hHeadTrackData +#ifdef EXTERNAL_ORIENTATIONS + && hCombinedOrientationData != NULL && hCombinedOrientationData->enableCombinedOrientation[subframe_idx] +#else + && hHeadTrackData->num_quaternions >= 0 +#endif + && hBinRenderer->rotInCldfb ) { if ( hBinRenderer->hInputSetup->is_loudspeaker_setup == 0 ) { /* Rotation in SHD (HOA3) */ if ( hHeadTrackData->shd_rot_max_order == -1 ) { +#ifdef EXTERNAL_ORIENTATIONS + rotateFrame_shd_cldfb( RealBuffer, ImagBuffer, hCombinedOrientationData->Rmat[subframe_idx], hBinRenderer->hInputSetup->nchan_out_woLFE, numTimeSlots, 3 ); +#else QuatToRotMat( hHeadTrackData->Quaternions[hHeadTrackData->num_quaternions++], hHeadTrackData->Rmat ); rotateFrame_shd_cldfb( RealBuffer, ImagBuffer, hHeadTrackData->Rmat, hBinRenderer->hInputSetup->nchan_out_woLFE, numTimeSlots, 3 ); +#endif } else if ( hHeadTrackData->shd_rot_max_order > 0 ) { +#ifdef EXTERNAL_ORIENTATIONS + rotateFrame_shd_cldfb( RealBuffer, ImagBuffer, hCombinedOrientationData->Rmat[subframe_idx], hBinRenderer->hInputSetup->nchan_out_woLFE, numTimeSlots, hHeadTrackData->shd_rot_max_order ); +#else rotateFrame_shd_cldfb( RealBuffer, ImagBuffer, hHeadTrackData->Rmat, hBinRenderer->hInputSetup->nchan_out_woLFE, numTimeSlots, hHeadTrackData->shd_rot_max_order ); +#endif } } else { /* Rotation in SD (CICPx) */ +#ifdef EXTERNAL_ORIENTATIONS + rotateFrame_sd_cldfb( hCombinedOrientationData->Rmat[subframe_idx], RealBuffer, ImagBuffer, hBinRenderer->hInputSetup, hBinRenderer->hEFAPdata, numTimeSlots, hBinRenderer->conv_band ); +#else rotateFrame_sd_cldfb( hHeadTrackData, RealBuffer, ImagBuffer, hBinRenderer->hInputSetup, hBinRenderer->hEFAPdata, numTimeSlots, hBinRenderer->conv_band ); +#endif } } diff --git a/lib_dec/ivas_dec.c b/lib_dec/ivas_dec.c index fb1b367767832901b890a4eba39116f58a86f1f8..aef3d177f9782210f47075c989f1e610a472f409 100644 --- a/lib_dec/ivas_dec.c +++ b/lib_dec/ivas_dec.c @@ -104,6 +104,18 @@ ivas_error ivas_dec( p_output[n] = &output[n][0]; } +#ifdef EXTERNAL_ORIENTATIONS + /*----------------------------------------------------------------* + * Combine orientations + *----------------------------------------------------------------*/ + + if ( ( error = combine_external_and_head_orientations_dec( st_ivas->hHeadTrackData, st_ivas->hExtOrientationData, + st_ivas->hCombinedOrientationData ) ) != IVAS_ERR_OK ) + { + return error; + } +#endif + /*----------------------------------------------------------------* * Decoding + Rendering *----------------------------------------------------------------*/ @@ -187,7 +199,11 @@ ivas_error ivas_dec( { ivas_param_ism_params_to_masa_param_mapping( st_ivas ); +#ifdef EXTERNAL_ORIENTATIONS + ivas_dirac_dec_binaural( st_ivas, st_ivas->hCombinedOrientationData, output, st_ivas->nchan_transport ); +#else ivas_dirac_dec_binaural( st_ivas, output, st_ivas->nchan_transport ); +#endif } else if ( st_ivas->renderer_type == RENDERER_MONO_DOWNMIX ) { @@ -407,7 +423,11 @@ ivas_error ivas_dec( /* Loudspeakers, Ambisonics or Binaural rendering */ if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC ) { +#ifdef EXTERNAL_ORIENTATIONS + ivas_dirac_dec_binaural( st_ivas, st_ivas->hCombinedOrientationData, output, nchan_remapped ); +#else ivas_dirac_dec_binaural( st_ivas, output, nchan_remapped ); +#endif } else if ( st_ivas->ivas_format == MASA_FORMAT ) { @@ -465,9 +485,12 @@ ivas_error ivas_dec( if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { if ( ( error = ivas_rend_crendProcess( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, - st_ivas->hHeadTrackData, &st_ivas->hIntSetup, st_ivas->hEFAPdata, - p_output, - output_Fs ) ) != IVAS_ERR_OK ) +#ifdef EXTERNAL_ORIENTATIONS + st_ivas->hCombinedOrientationData, +#else + st_ivas->hHeadTrackData, +#endif + &st_ivas->hIntSetup, st_ivas->hEFAPdata, p_output, output_Fs ) ) != IVAS_ERR_OK ) { return error; } @@ -524,7 +547,13 @@ ivas_error ivas_dec( /* Rendering */ if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { - if ( ( error = ivas_rend_crendProcess( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, st_ivas->hHeadTrackData, &st_ivas->hIntSetup, st_ivas->hEFAPdata, p_output, output_Fs ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_rend_crendProcess( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, +#ifdef EXTERNAL_ORIENTATIONS + st_ivas->hCombinedOrientationData, +#else + st_ivas->hHeadTrackData, +#endif + &st_ivas->hIntSetup, st_ivas->hEFAPdata, p_output, output_Fs ) ) != IVAS_ERR_OK ) { return error; } @@ -667,7 +696,11 @@ ivas_error ivas_dec( /* Rendering */ if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC ) { +#ifdef EXTERNAL_ORIENTATIONS + ivas_dirac_dec_binaural( st_ivas, st_ivas->hCombinedOrientationData, output, st_ivas->nchan_transport ); +#else ivas_dirac_dec_binaural( st_ivas, output, st_ivas->nchan_transport ); +#endif } else if ( st_ivas->renderer_type == RENDERER_DIRAC || st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) /* rendering to CICPxx and Ambisonics */ { diff --git a/lib_dec/ivas_dirac_dec.c b/lib_dec/ivas_dirac_dec.c index feb61ab063dfb9ab27918340a0282a76c68b6a23..5877dc4738b0eaf5b30eca684f4494924b698334 100644 --- a/lib_dec/ivas_dirac_dec.c +++ b/lib_dec/ivas_dirac_dec.c @@ -2626,11 +2626,19 @@ void ivas_dirac_dec_render_sf( set_zero( onset_filter_subframe, hDirAC->num_freq_bands ); } +#ifdef EXTERNAL_ORIENTATIONS + if ( st_ivas->hHeadTrackData && st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] ) +#else if ( st_ivas->hHeadTrackData ) +#endif { +#ifdef EXTERNAL_ORIENTATIONS + p_Rmat = &st_ivas->hCombinedOrientationData->Rmat[subframe_idx][0][0]; +#else QuatToRotMat( st_ivas->hHeadTrackData->Quaternions[st_ivas->hHeadTrackData->num_quaternions++], st_ivas->hHeadTrackData->Rmat ); p_Rmat = &st_ivas->hHeadTrackData->Rmat[0][0]; +#endif if ( st_ivas->hHeadTrackData->shd_rot_max_order == 0 ) { @@ -2705,8 +2713,11 @@ void ivas_dirac_dec_render_sf( set_zero( surCohRatio, hDirAC->num_freq_bands ); } } - +#ifdef EXTERNAL_ORIENTATIONS + if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] && st_ivas->hHeadTrackData->shd_rot_max_order == 1 ) +#else if ( st_ivas->hDecoderConfig->Opt_Headrotation && st_ivas->hHeadTrackData->shd_rot_max_order == 1 ) +#endif { ivas_dirac_dec_compute_directional_responses( hDirAC, st_ivas->hVBAPdata, @@ -2809,7 +2820,11 @@ void ivas_dirac_dec_render_sf( if ( hDirAC->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD ) { +#ifdef EXTERNAL_ORIENTATIONS + if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] && st_ivas->hHeadTrackData->shd_rot_max_order == 0 ) +#else if ( st_ivas->hDecoderConfig->Opt_Headrotation && st_ivas->hHeadTrackData->shd_rot_max_order == 0 ) +#endif { protoSignalComputation_shd( Cldfb_RealBuffer, Cldfb_ImagBuffer, hDirAC->h_output_synthesis_psd_state.proto_direct_buffer_f, @@ -3056,7 +3071,11 @@ void ivas_dirac_dec_render_sf( } /*Compute PSDs*/ +#ifdef EXTERNAL_ORIENTATIONS + if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] && st_ivas->hHeadTrackData->shd_rot_max_order > 0 ) +#else if ( st_ivas->hDecoderConfig->Opt_Headrotation && st_ivas->hHeadTrackData->shd_rot_max_order > 0 ) +#endif { ivas_dirac_dec_output_synthesis_process_slot( reference_power, p_onset_filter, @@ -3223,6 +3242,10 @@ void ivas_dirac_dec_render_sf( /* Perform binaural rendering */ ivas_binRenderer( st_ivas->hBinRenderer, st_ivas->hHeadTrackData, +#ifdef EXTERNAL_ORIENTATIONS + st_ivas->hCombinedOrientationData, + subframe_idx, +#endif hDirAC->subframe_nbslots[subframe_idx], Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index 4bb061b572c63b0ad6daa655e65276e35202466d..9d5ad35d5195dd8c905183aded389c71b9b03625 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -589,6 +589,32 @@ ivas_error ivas_init_decoder_front( } } +#ifdef EXTERNAL_ORIENTATIONS + /*-------------------------------------------------------------------* + * Allocate and initialize external orientation handle + *--------------------------------------------------------------------*/ + + if ( st_ivas->hDecoderConfig->Opt_ExternalOrientation ) + { + if ( ( error = ivas_external_orientation_open( &( st_ivas->hExtOrientationData ) ) ) != IVAS_ERR_OK ) + { + return error; + } + } + + /*-------------------------------------------------------------------* + * Allocate and initialize combined orientation handle + *--------------------------------------------------------------------*/ + + if ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) + { + if ( ( error = ivas_combined_orientation_open( &( st_ivas->hCombinedOrientationData ) ) ) != IVAS_ERR_OK ) + { + return error; + } + } +#endif + /*-------------------------------------------------------------------* * Allocate HRTF binary handle *--------------------------------------------------------------------*/ @@ -1266,7 +1292,11 @@ ivas_error ivas_init_decoder( } else if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { +#ifdef EXTERNAL_ORIENTATIONS + if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM && st_ivas->ivas_format == MC_FORMAT && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#else if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM && st_ivas->ivas_format == MC_FORMAT && st_ivas->hDecoderConfig->Opt_Headrotation ) +#endif { if ( ( error = efap_init_data( &( st_ivas->hEFAPdata ), st_ivas->hIntSetup.ls_azimuth, st_ivas->hIntSetup.ls_elevation, st_ivas->hIntSetup.nchan_out_woLFE, EFAP_MODE_EFAP ) ) != IVAS_ERR_OK ) { @@ -1627,6 +1657,10 @@ void ivas_initialize_handles_dec( st_ivas->hHrtfTD = NULL; st_ivas->hLsSetupCustom = NULL; st_ivas->hRenderConfig = NULL; +#ifdef EXTERNAL_ORIENTATIONS + st_ivas->hExtOrientationData = NULL; + st_ivas->hCombinedOrientationData = NULL; +#endif st_ivas->hTcBuffer = NULL; @@ -1788,6 +1822,14 @@ void ivas_destroy_dec( /* Head track data handle */ ivas_headTrack_close( &st_ivas->hHeadTrackData ); +#ifdef EXTERNAL_ORIENTATIONS + /* External orientation data handle */ + ivas_external_orientation_close( &st_ivas->hExtOrientationData ); + + /* Combined orientation data handle */ + ivas_combined_orientation_close( &st_ivas->hCombinedOrientationData ); +#endif + /* Time Domain binaural renderer handle */ if ( st_ivas->hBinRendererTd != NULL ) { @@ -2087,6 +2129,16 @@ static ivas_error doSanityChecks_IVAS( } } +#ifdef EXTERNAL_ORIENTATIONS + if ( st_ivas->hDecoderConfig->Opt_ExternalOrientation ) + { + if ( !( output_config == AUDIO_CONFIG_BINAURAL || output_config == AUDIO_CONFIG_BINAURAL_ROOM ) ) + { + return IVAS_ERROR( IVAS_ERR_EXT_ORIENTATION_NOT_SUPPORTED, "Wrong set-up: External orientation not supported in this configuration" ); + } + } +#endif + #ifdef DEBUGGING if ( ( st_ivas->hDecoderConfig->force_rend == FORCE_TD_RENDERER ) && ( ( st_ivas->ivas_format != MC_FORMAT && st_ivas->ivas_format != ISM_FORMAT ) || output_config != AUDIO_CONFIG_BINAURAL || ( st_ivas->ivas_format == ISM_FORMAT && st_ivas->ism_mode == ISM_MODE_PARAM ) || ( st_ivas->ivas_format == MC_FORMAT && ( st_ivas->mc_mode != MC_MODE_MCT && st_ivas->mc_mode != MC_MODE_PARAMUPMIX ) ) ) ) { diff --git a/lib_dec/ivas_ism_renderer.c b/lib_dec/ivas_ism_renderer.c index c6ca4b3b7bc66f71ea415faadc294c09935a5ba2..2362979ff6c795fdf640e1f638b80351467d12dc 100644 --- a/lib_dec/ivas_ism_renderer.c +++ b/lib_dec/ivas_ism_renderer.c @@ -121,7 +121,9 @@ void ivas_ism_render( float g1, g2; int16_t nchan_ism, nchan_out_woLFE, lfe_index; int16_t azimuth, elevation; +#ifndef EXTERNAL_ORIENTATIONS float Rmat[3][3]; +#endif nchan_ism = st_ivas->nchan_ism; nchan_out_woLFE = st_ivas->hIntSetup.nchan_out_woLFE; @@ -143,11 +145,13 @@ void ivas_ism_render( set_f( output_f[i], 0.0f, output_frame ); } +#ifndef EXTERNAL_ORIENTATIONS if ( st_ivas->hHeadTrackData != NULL && st_ivas->hHeadTrackData->num_quaternions >= 0 ) { /* Calculate rotation matrix from the quaternion */ QuatToRotMat( st_ivas->hHeadTrackData->Quaternions[st_ivas->hHeadTrackData->num_quaternions++], Rmat ); } +#endif for ( i = 0; i < nchan_ism; i++ ) { @@ -160,10 +164,17 @@ void ivas_ism_render( } else { +#ifdef EXTERNAL_ORIENTATIONS + /* Combined rotation: rotate the object positions depending the head and external orientations */ + if ( st_ivas->hCombinedOrientationData != NULL && st_ivas->hCombinedOrientationData->enableCombinedOrientation[0] == 1 ) + { + rotateAziEle( st_ivas->hIsmMetaData[i]->azimuth, st_ivas->hIsmMetaData[i]->elevation, &azimuth, &elevation, st_ivas->hCombinedOrientationData->Rmat[0], st_ivas->hIntSetup.is_planar_setup ); +#else /* Head rotation: rotate the object positions depending the head's orientation */ if ( st_ivas->hHeadTrackData != NULL && st_ivas->hHeadTrackData->num_quaternions >= 0 && !st_ivas->hIsmMetaData[i]->non_diegetic_flag ) { rotateAziEle( st_ivas->hIsmMetaData[i]->azimuth, st_ivas->hIsmMetaData[i]->elevation, &azimuth, &elevation, Rmat, st_ivas->hIntSetup.is_planar_setup ); +#endif } else { diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index fd0375e7bef1a85e736a9e937af9997ec235f12e..7cc96cd14fb389a6cd94062d7da83121747335d5 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -783,7 +783,12 @@ ivas_error ivas_jbm_dec_render( /* Rendering */ if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { - if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, st_ivas->hHeadTrackData, + if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, +#ifdef EXTERNAL_ORIENTATIONS + st_ivas->hCombinedOrientationData, +#else + st_ivas->hHeadTrackData, +#endif &st_ivas->hIntSetup, st_ivas->hEFAPdata, st_ivas->hTcBuffer, p_tc, p_output, *nSamplesRendered, output_Fs ) ) != IVAS_ERR_OK ) { return error; @@ -1005,8 +1010,13 @@ ivas_error ivas_jbm_dec_flush_renderer( { if ( renderer_type_old == RENDERER_BINAURAL_MIXER_CONV || renderer_type_old == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { - if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, intern_config_old, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, st_ivas->hHeadTrackData, hIntSetupOld, - st_ivas->hEFAPdata, st_ivas->hTcBuffer, hTcBuffer->tc, p_output, hTcBuffer->n_samples_granularity, st_ivas->hDecoderConfig->output_Fs ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, intern_config_old, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, +#ifdef EXTERNAL_ORIENTATIONS + st_ivas->hCombinedOrientationData, +#else + st_ivas->hHeadTrackData, +#endif + hIntSetupOld, st_ivas->hEFAPdata, st_ivas->hTcBuffer, hTcBuffer->tc, p_output, hTcBuffer->n_samples_granularity, st_ivas->hDecoderConfig->output_Fs ) ) != IVAS_ERR_OK ) { return error; } diff --git a/lib_dec/ivas_mc_param_dec.c b/lib_dec/ivas_mc_param_dec.c index 2745481402f25ba335f53f86157335e1ecfff714..78cdbfadc9e5d454b6c261b8a94c9c9ea90f01c0 100644 --- a/lib_dec/ivas_mc_param_dec.c +++ b/lib_dec/ivas_mc_param_dec.c @@ -424,8 +424,14 @@ ivas_error ivas_param_mc_dec_open( ivas_param_mc_dec_compute_interpolator( 0, 0, DEFAULT_JBM_CLDFB_TIMESLOTS, hParamMC->h_output_synthesis_params.interpolator ); + +#ifdef EXTERNAL_ORIENTATIONS + /* Head or external rotation */ + if ( ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) +#else /* Head rotation */ if ( ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) && st_ivas->hDecoderConfig->Opt_Headrotation ) +#endif { if ( ( hParamMC->hoa_encoder = (float *) malloc( st_ivas->hTransSetup.nchan_out_woLFE * MAX_INTERN_CHANNELS * sizeof( float ) ) ) == NULL ) { @@ -1748,7 +1754,11 @@ void ivas_param_mc_dec_render( if ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) { - ivas_binRenderer( st_ivas->hBinRenderer, st_ivas->hHeadTrackData, hParamMC->subframe_nbslots[subframe_idx], + ivas_binRenderer( st_ivas->hBinRenderer, st_ivas->hHeadTrackData, +#ifdef EXTERNAL_ORIENTATIONS + st_ivas->hCombinedOrientationData, subframe_idx, +#endif + hParamMC->subframe_nbslots[subframe_idx], Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, Cldfb_RealBuffer, Cldfb_ImagBuffer ); } else if ( hParamMC->synthesis_conf == PARAM_MC_SYNTH_LS_CONV_CLDFB ) diff --git a/lib_dec/ivas_objectRenderer_internal.c b/lib_dec/ivas_objectRenderer_internal.c index df210f2f8a4e6e37b8c2f8a3a58499370c7e6c97..9ba6351f638d2ee0ad88003328f615a705ff278d 100644 --- a/lib_dec/ivas_objectRenderer_internal.c +++ b/lib_dec/ivas_objectRenderer_internal.c @@ -85,7 +85,13 @@ ivas_error ivas_td_binaural_renderer( st_ivas->hReverb, st_ivas->transport_config, st_ivas->hBinRendererTd, st_ivas->nchan_transport, LFE_CHANNEL, st_ivas->ivas_format, - st_ivas->hIsmMetaData, st_ivas->hDecoderConfig->Opt_Headrotation, ( st_ivas->hHeadTrackData != NULL ) ? st_ivas->hHeadTrackData->Quaternions : NULL, + st_ivas->hIsmMetaData, +#ifdef EXTERNAL_ORIENTATIONS + ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->enableCombinedOrientation : NULL, + ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->Quaternions : NULL, +#else + st_ivas->hDecoderConfig->Opt_Headrotation, ( st_ivas->hHeadTrackData != NULL ) ? st_ivas->hHeadTrackData->Quaternions : NULL, +#endif ( st_ivas->hHeadTrackData != NULL ) ? st_ivas->hHeadTrackData->Pos : NULL, ism_md_subframe_update, output, output_frame ); } @@ -175,8 +181,14 @@ ivas_error ivas_td_binaural_renderer_sf( } /* Update the listener's location/orientation */ - TDREND_Update_listener_orientation( st_ivas->hBinRendererTd, st_ivas->hDecoderConfig->Opt_Headrotation, + TDREND_Update_listener_orientation( st_ivas->hBinRendererTd, +#ifdef EXTERNAL_ORIENTATIONS + ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] : 0, + ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->Quaternions : NULL, +#else + st_ivas->hDecoderConfig->Opt_Headrotation, ( st_ivas->hHeadTrackData != NULL ) ? &st_ivas->hHeadTrackData->Quaternions[0] : NULL, +#endif ( st_ivas->hHeadTrackData != NULL ) ? st_ivas->hHeadTrackData->Pos : NULL ); if ( ( st_ivas->hRenderConfig != NULL ) && ( st_ivas->hRenderConfig->roomAcoustics.late_reverb_on ) ) diff --git a/lib_dec/ivas_output_config.c b/lib_dec/ivas_output_config.c index e4c389e2f33d75921e997a480b04c88b7e71af7b..07beb889968be231c6a0d091f43bccb43fc6aea9 100644 --- a/lib_dec/ivas_output_config.c +++ b/lib_dec/ivas_output_config.c @@ -191,9 +191,17 @@ void ivas_renderer_select( if ( output_config == AUDIO_CONFIG_BINAURAL ) { #ifdef DEBUGGING +#ifdef EXTERNAL_ORIENTATIONS + if ( ( ( ( st_ivas->transport_config == AUDIO_CONFIG_5_1 || st_ivas->transport_config == AUDIO_CONFIG_7_1 ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) ) || ( st_ivas->hDecoderConfig->force_rend == FORCE_TD_RENDERER ) ) && ( st_ivas->mc_mode == MC_MODE_MCT || st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) && !( st_ivas->hDecoderConfig->force_rend == FORCE_CLDFB_RENDERER ) ) +#else if ( ( ( ( st_ivas->transport_config == AUDIO_CONFIG_5_1 || st_ivas->transport_config == AUDIO_CONFIG_7_1 ) && st_ivas->hDecoderConfig->Opt_Headrotation ) || ( st_ivas->hDecoderConfig->force_rend == FORCE_TD_RENDERER ) ) && ( st_ivas->mc_mode == MC_MODE_MCT || st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) && !( st_ivas->hDecoderConfig->force_rend == FORCE_CLDFB_RENDERER ) ) +#endif +#else +#ifdef EXTERNAL_ORIENTATIONS + if ( ( st_ivas->transport_config == AUDIO_CONFIG_5_1 || st_ivas->transport_config == AUDIO_CONFIG_7_1 ) && ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) && ( st_ivas->mc_mode == MC_MODE_MCT || st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) ) #else if ( ( st_ivas->transport_config == AUDIO_CONFIG_5_1 || st_ivas->transport_config == AUDIO_CONFIG_7_1 ) && st_ivas->hDecoderConfig->Opt_Headrotation && ( st_ivas->mc_mode == MC_MODE_MCT || st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) ) +#endif #endif { *renderer_type = RENDERER_BINAURAL_OBJECTS_TD; @@ -219,7 +227,11 @@ void ivas_renderer_select( *renderer_type = RENDERER_BINAURAL_FASTCONV; } #endif +#ifdef EXTERNAL_ORIENTATIONS + if ( st_ivas->hDecoderConfig->Opt_Headrotation || st_ivas->hDecoderConfig->Opt_ExternalOrientation ) +#else if ( st_ivas->hDecoderConfig->Opt_Headrotation ) +#endif { /* force HOA3 domain for rotation*/ *internal_config = AUDIO_CONFIG_HOA3; diff --git a/lib_dec/ivas_stat_dec.h b/lib_dec/ivas_stat_dec.h index ba8f573364026477612a08411093bb1cc819fca5..e63f6c3e43b9cbb38d0dad857509c47040c9132d 100644 --- a/lib_dec/ivas_stat_dec.h +++ b/lib_dec/ivas_stat_dec.h @@ -1187,6 +1187,9 @@ typedef struct decoder_config_structure int16_t Opt_non_diegetic_pan; /* indicates diegetic or not */ float non_diegetic_pan_gain; /* non diegetic panning gain*/ int16_t Opt_AMR_WB; /* flag indicating AMR-WB IO mode */ +#ifdef EXTERNAL_ORIENTATIONS + int16_t Opt_ExternalOrientation; /* indiates whether external orientations are used */ +#endif /* temp. development parameters */ #ifdef DEBUGGING @@ -1305,6 +1308,10 @@ typedef struct Decoder_Struct HEAD_TRACK_DATA_HANDLE hHeadTrackData; /* Head tracking data structure */ RENDER_CONFIG_DATA *hRenderConfig; /* Renderer config pointer */ int32_t binaural_latency_ns; /* Binauralization latency in ns */ +#ifdef EXTERNAL_ORIENTATIONS + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData; /* External orientation data structure */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData; /* Combined external and head orientation data structure */ +#endif /* JBM module */ DECODER_TC_BUFFER_HANDLE hTcBuffer; /* JBM structure */ diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 3b4618b6a29011fef488c547e9ec71457e4213dd..e01c59b77942f19c06f000da803c265122eb3a41 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -243,6 +243,10 @@ static void init_decoder_config( hDecoderConfig->Opt_delay_comp = 0; +#ifdef EXTERNAL_ORIENTATIONS + hDecoderConfig->Opt_ExternalOrientation = 0; +#endif + return; } @@ -398,12 +402,15 @@ static IVAS_DEC_BS_FORMAT mapIvasFormat( *---------------------------------------------------------------------*/ ivas_error IVAS_DEC_Configure( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - const uint32_t sampleRate, /* i : output sampling frequency */ - const IVAS_DEC_AUDIO_CONFIG outputFormat, /* i : output format */ - const int16_t customLsOutputEnabled, /* i : enable custom loudspeaker setup handle */ - const int16_t hrtfReaderEnabled, /* i : enable HRTF binary file input */ - const int16_t enableHeadRotation, /* i : enable head rotation for binaural output */ + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + const uint32_t sampleRate, /* i : output sampling frequency */ + const IVAS_DEC_AUDIO_CONFIG outputFormat, /* i : output format */ + const int16_t customLsOutputEnabled, /* i : enable custom loudspeaker setup handle */ + const int16_t hrtfReaderEnabled, /* i : enable HRTF binary file input */ + const int16_t enableHeadRotation, /* i : enable head rotation for binaural output */ +#ifdef EXTERNAL_ORIENTATIONS + const int16_t enableExternalOrientation, /* i : enable external orientations */ +#endif const HEAD_ORIENT_TRK_T orientation_tracking, /* i : head orientation tracking type */ const int16_t renderConfigEnabled, /* i : enable Renderer config. file for binaural output */ const int16_t Opt_non_diegetic_pan, /* i : diegetic or not */ @@ -463,6 +470,9 @@ ivas_error IVAS_DEC_Configure( hDecoderConfig->Opt_non_diegetic_pan = Opt_non_diegetic_pan; hDecoderConfig->non_diegetic_pan_gain = non_diegetic_pan_gain; hDecoderConfig->Opt_delay_comp = delayCompensationEnabled; +#ifdef EXTERNAL_ORIENTATIONS + hDecoderConfig->Opt_ExternalOrientation = enableExternalOrientation; +#endif /* Set decoder parameters to initial values */ if ( ( error = ivas_init_decoder_front( st_ivas ) ) != IVAS_ERR_OK ) @@ -1220,6 +1230,52 @@ ivas_error IVAS_DEC_FeedRefVectorData( return ivas_orient_trk_SetReferenceVector( pOtr, listenerPos, refPos ); } +#ifdef EXTERNAL_ORIENTATIONS +/*---------------------------------------------------------------------* + * IVAS_DEC_FeedExternalOrientationData( ) + * + * Feed the decoder with the external orientation data + *---------------------------------------------------------------------*/ + +ivas_error IVAS_DEC_FeedExternalOrientationData( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + IVAS_QUATERNION *orientation, /* i : external orientation data */ + int8_t *enableHeadRotation, /* i : flag to enable head rotation for this frame */ + int8_t *enableExternalOrientation, /* i : flag to enable external orientation for this frame */ + int8_t *enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ + int16_t *numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +) +{ + EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData; + int16_t i; + + if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL || orientation == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + hExternalOrientationData = hIvasDec->st_ivas->hExtOrientationData; + + if ( hExternalOrientationData == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + /* Move external orientation data to the decoder handle (invert orientations) */ + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + QuaternionInverse( orientation[i], &hExternalOrientationData->Quaternions[i] ); + + hExternalOrientationData->enableHeadRotation[i] = enableHeadRotation[i]; + hExternalOrientationData->enableExternalOrientation[i] = enableExternalOrientation[i]; + hExternalOrientationData->enableRotationInterpolation[i] = enableRotationInterpolation[i]; + hExternalOrientationData->numFramesToTargetOrientation[i] = numFramesToTargetOrientation[i]; + } + + return IVAS_ERR_OK; +} +#endif + /*---------------------------------------------------------------------* * IVAS_DEC_FeedCustomLsData( ) * @@ -2509,6 +2565,13 @@ static ivas_error printConfigInfo_dec( fprintf( stdout, "Head rotation: ON\n" ); } +#ifdef EXTERNAL_ORIENTATIONS + if ( st_ivas->hDecoderConfig->Opt_ExternalOrientation ) + { + fprintf( stdout, "External orientation: ON\n" ); + } +#endif + if ( st_ivas->hDecoderConfig->orientation_tracking != HEAD_ORIENT_TRK_NONE ) { switch ( st_ivas->hDecoderConfig->orientation_tracking ) diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index 0572ace82e3f7de7cd5bfec8c1f4f3890439434a..c5eb095bb12b5e478b0172b84adc3e63aabe74e2 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -143,10 +143,13 @@ ivas_error IVAS_DEC_Configure( const int16_t customLsOutputEnabled, /* i : enable custom loudspeaker setup handle */ const int16_t hrtfReaderEnabled, /* i : enable HRTF binary file input */ const int16_t enableHeadRotation, /* i : enable head rotation for binaural output */ +#ifdef EXTERNAL_ORIENTATIONS + const int16_t enableExternalOrientation, /* i : enable external orientations */ +#endif const HEAD_ORIENT_TRK_T orientation_tracking, /* i : head orientation tracking type */ const int16_t renderConfigEnabled, /* i : enable Renderer config. file for binaural output */ const int16_t Opt_non_diegetic_pan, /* i : diegetic or not */ - const float non_diegetic_pan_gain, /* i : non diegetic panning gain */ + const float non_diegetic_pan_gain, /* i : non diegetic panning gain */ const int16_t delayCompensationEnabled /* i : enable delay compensation */ ); @@ -205,6 +208,18 @@ ivas_error IVAS_DEC_FeedRefVectorData( const IVAS_VECTOR3 refPos /* i : Reference position */ ); +#ifdef EXTERNAL_ORIENTATIONS +/*! r: error code */ +ivas_error IVAS_DEC_FeedExternalOrientationData( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + IVAS_QUATERNION *orientation, /* i : external orientation data */ + int8_t *enableHeadRotation, /* i : flag to enable head rotation for this frame */ + int8_t *enableExternalOrientation, /* i : flag to enable external orientation for this frame */ + int8_t *enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ + int16_t *numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +); +#endif + /*! r: error code */ ivas_error IVAS_DEC_VoIP_FeedFrame( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ diff --git a/lib_rend/ivas_crend.c b/lib_rend/ivas_crend.c index 10f8743b230cce1a26c0255a5792acd6adfcd3a0..2b61fa7ef4aad927a010afcf6932224a9e41b960 100644 --- a/lib_rend/ivas_crend.c +++ b/lib_rend/ivas_crend.c @@ -1463,7 +1463,11 @@ ivas_error ivas_rend_crendProcess( const AUDIO_CONFIG inConfig, const AUDIO_CONFIG outConfig, DECODER_CONFIG_HANDLE hDecoderConfig, +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, +#else HEAD_TRACK_DATA_HANDLE hHeadTrackData, +#endif IVAS_OUTPUT_SETUP_HANDLE hIntSetup, EFAP_HANDLE hEFAPdata, float *output[], /* i/o: input/output audio channels */ @@ -1478,6 +1482,22 @@ ivas_error ivas_rend_crendProcess( ivas_error error; IVAS_REND_AudioConfig inRendConfig; IVAS_REND_AudioConfig outRendConfig; +#ifdef EXTERNAL_ORIENTATIONS + int8_t combinedOrientationEnabled; + + combinedOrientationEnabled = 0; + if ( hCombinedOrientationData != NULL ) + { + for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) + { + if ( hCombinedOrientationData->enableCombinedOrientation[subframe_idx] != 0 ) + { + combinedOrientationEnabled = 1; + break; + } + } + } +#endif push_wmops( "ivas_rend_crendProcess" ); @@ -1503,7 +1523,11 @@ ivas_error ivas_rend_crendProcess( for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) { +#ifdef EXTERNAL_ORIENTATIONS + if ( hDecoderConfig && combinedOrientationEnabled ) +#else if ( hDecoderConfig && hDecoderConfig->Opt_Headrotation && hHeadTrackData && hHeadTrackData->num_quaternions >= 0 ) +#endif { /* Orientation tracking */ @@ -1513,12 +1537,20 @@ ivas_error ivas_rend_crendProcess( */ if ( in_config == AUDIO_CONFIG_FOA || in_config == AUDIO_CONFIG_HOA2 || in_config == AUDIO_CONFIG_HOA3 ) { +#ifdef EXTERNAL_ORIENTATIONS + rotateFrame_shd( hCombinedOrientationData, output, subframe_len, *hIntSetup, subframe_idx ); +#else rotateFrame_shd( hHeadTrackData, output, subframe_len, *hIntSetup, subframe_idx ); +#endif } /* Rotation in SD for MC -> BINAURAL_ROOM */ else if ( ( hIntSetup != NULL ) && hIntSetup->is_loudspeaker_setup ) { +#ifdef EXTERNAL_ORIENTATIONS + rotateFrame_sd( hCombinedOrientationData, output, subframe_len, *hIntSetup, hEFAPdata, subframe_idx ); +#else rotateFrame_sd( hHeadTrackData, output, subframe_len, *hIntSetup, hEFAPdata, subframe_idx ); +#endif } } @@ -1562,18 +1594,22 @@ ivas_error ivas_rend_crendProcess( *-----------------------------------------------------------------------------------------*/ ivas_error ivas_rend_crendProcessSubframe( - const CREND_WRAPPER *pCrend, /* i/o: Crend wrapper handle */ - const AUDIO_CONFIG inConfig, /* i : input audio configuration */ - const AUDIO_CONFIG outConfig, /* i : output audio configuration */ - const DECODER_CONFIG_HANDLE hDecoderConfig, /* i : decoder config. structure */ + const CREND_WRAPPER *pCrend, /* i/o: Crend wrapper handle */ + const AUDIO_CONFIG inConfig, /* i : input audio configuration */ + const AUDIO_CONFIG outConfig, /* i : output audio configuration */ + const DECODER_CONFIG_HANDLE hDecoderConfig, /* i : decoder config. structure */ +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined orientation handle */ +#else const HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : Head tracking data structure */ - const IVAS_OUTPUT_SETUP_HANDLE hIntSetup, /* i : internal setup handle */ - const EFAP_HANDLE hEFAPdata, /* i : EFAP handle */ - DECODER_TC_BUFFER_HANDLE hTcBuffer, /* i/o: JBM handle */ - float *input_f[], /* i : transport channels */ - float *output[], /* i/o: input/output audio channels */ - const int16_t n_samples_to_render, /* i : output frame length per channel */ - const int32_t output_Fs /* i : output sampling rate */ +#endif + const IVAS_OUTPUT_SETUP_HANDLE hIntSetup, /* i : internal setup handle */ + const EFAP_HANDLE hEFAPdata, /* i : EFAP handle */ + DECODER_TC_BUFFER_HANDLE hTcBuffer, /* i/o: JBM handle */ + float *input_f[], /* i : transport channels */ + float *output[], /* i/o: input/output audio channels */ + const int16_t n_samples_to_render, /* i : output frame length per channel */ + const int32_t output_Fs /* i : output sampling rate */ ) { int16_t subframe_idx, subframe_len; @@ -1586,6 +1622,22 @@ ivas_error ivas_rend_crendProcessSubframe( ivas_error error; IVAS_REND_AudioConfig inRendConfig; IVAS_REND_AudioConfig outRendConfig; +#ifdef EXTERNAL_ORIENTATIONS + int8_t combinedOrientationEnabled; + + combinedOrientationEnabled = 0; + if ( hCombinedOrientationData != NULL ) + { + for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) + { + if ( hCombinedOrientationData->enableCombinedOrientation[subframe_idx] != 0 ) + { + combinedOrientationEnabled = 1; + break; + } + } + } +#endif push_wmops( "ivas_rend_crendProcessSubframe" ); @@ -1633,7 +1685,11 @@ ivas_error ivas_rend_crendProcessSubframe( { subframe_len = hTcBuffer->subframe_nbslots[subframe_idx] * hTcBuffer->n_samples_granularity; +#ifdef EXTERNAL_ORIENTATIONS + if ( hDecoderConfig && combinedOrientationEnabled ) +#else if ( hDecoderConfig && hDecoderConfig->Opt_Headrotation && hHeadTrackData && hHeadTrackData->num_quaternions >= 0 ) +#endif { /* Rotation in SHD for: MC with elevation (5_1_2 / 5_1_4 / 7_1_4) -> BINAURAL @@ -1641,12 +1697,24 @@ ivas_error ivas_rend_crendProcessSubframe( */ if ( in_config == AUDIO_CONFIG_FOA || in_config == AUDIO_CONFIG_HOA2 || in_config == AUDIO_CONFIG_HOA3 ) { - rotateFrame_shd( hHeadTrackData, tc_local, subframe_len, *hIntSetup, 0 ); + rotateFrame_shd( +#ifdef EXTERNAL_ORIENTATIONS + hCombinedOrientationData, +#else + hHeadTrackData, +#endif + tc_local, subframe_len, *hIntSetup, 0 ); } /* Rotation in SD for MC -> BINAURAL_ROOM */ else if ( ( hIntSetup != NULL ) && hIntSetup->is_loudspeaker_setup ) { - rotateFrame_sd( hHeadTrackData, tc_local, subframe_len, *hIntSetup, hEFAPdata, 0 ); + rotateFrame_sd( +#ifdef EXTERNAL_ORIENTATIONS + hCombinedOrientationData, +#else + hHeadTrackData, +#endif + tc_local, subframe_len, *hIntSetup, hEFAPdata, 0 ); } } diff --git a/lib_rend/ivas_dirac_dec_binaural_functions.c b/lib_rend/ivas_dirac_dec_binaural_functions.c index 2e4dbbabcb0238b9ff88a298e8fdc6ce0145a3ef..2eefb0e1d388c07bc52d166bd2e03592cab3719a 100644 --- a/lib_rend/ivas_dirac_dec_binaural_functions.c +++ b/lib_rend/ivas_dirac_dec_binaural_functions.c @@ -81,7 +81,14 @@ typedef struct hrtfGainCache * Local function prototypes *------------------------------------------------------------------------*/ -static void ivas_dirac_dec_binaural_internal( Decoder_Struct *st_ivas, float *output_f[], const int16_t nchan_transport, const int16_t subframe ); +static void ivas_dirac_dec_binaural_internal( Decoder_Struct *st_ivas, +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, +#endif + float *output_f[], + const int16_t nchan_transport, + const int16_t subframe ); + static void ivas_dirac_dec_decorrelate_slot( DIRAC_DEC_HANDLE hDirAC, const int16_t slot, float inRe[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], float inIm[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], float decRe[][CLDFB_NO_CHANNELS_MAX], float decIm[][CLDFB_NO_CHANNELS_MAX] ); #ifdef FIX_511_OPTIMIZE_PARAMBIN_GAIN_FETCH @@ -96,9 +103,29 @@ static void ivas_dirac_dec_binaural_determine_processing_matrices( Decoder_Struc static void ivas_dirac_dec_binaural_process_output( Decoder_Struct *st_ivas, float *output_f[], float inRe[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], float inIm[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], const int16_t max_band_decorr, const int16_t numInChannels, const int16_t subframe ); -static void adaptTransportSignalsHeadtracked( HEAD_TRACK_DATA_HANDLE hHeadTrackData, float inRe[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], float inIm[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], const int16_t nBins, const int16_t nSlots, float Rmat[3][3] ); +static void adaptTransportSignalsHeadtracked( +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hHeadTrackData, +#else + HEAD_TRACK_DATA_HANDLE hHeadTrackData, +#endif + float inRe[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], + float inIm[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], + const int16_t nBins, + const int16_t nSlots, + float Rmat[3][3] ); -static void ivas_dirac_dec_binaural_check_and_switch_transports_headtracked( HEAD_TRACK_DATA_HANDLE hHeadTrackData, float inRe[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], float inIm[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], const int16_t nBins, const int16_t nSlots, float Rmat[3][3] ); +static void ivas_dirac_dec_binaural_check_and_switch_transports_headtracked( +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hHeadTrackData, +#else + HEAD_TRACK_DATA_HANDLE hHeadTrackData, +#endif + float inRe[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], + float inIm[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], + const int16_t nBins, + const int16_t nSlots, + float Rmat[3][3] ); static void formulate2x2MixingMatrix( float Ein1, float Ein2, float CinRe, float CinIm, float Eout1, float Eout2, float CoutRe, float CoutIm, float Q[BINAURAL_CHANNELS][BINAURAL_CHANNELS], float Mre[BINAURAL_CHANNELS][BINAURAL_CHANNELS], float Mim[BINAURAL_CHANNELS][BINAURAL_CHANNELS], const float regularizationFactor ); #ifdef FIX_511_OPTIMIZE_PARAMBIN_GAIN_FETCH @@ -387,7 +414,7 @@ void ivas_dirac_dec_binaural_render( for ( subframe_idx = first_sf; subframe_idx < last_sf; subframe_idx++ ) { int16_t n_samples_sf = slot_size * hDirAC->subframe_nbslots[subframe_idx]; - ivas_dirac_dec_binaural_internal( st_ivas, output_f_local, nchan_transport, subframe_idx ); + ivas_dirac_dec_binaural_internal( st_ivas, st_ivas->hCombinedOrientationData, output_f_local, nchan_transport, subframe_idx ); for ( ch = 0; ch < nchan_out; ch++ ) { output_f_local[ch] += n_samples_sf; @@ -412,7 +439,10 @@ void ivas_dirac_dec_binaural_render( *------------------------------------------------------------------------*/ void ivas_dirac_dec_binaural( - Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined orientation handle */ +#endif float output_f[][L_FRAME48k], /* i/o: synthesized core-coder transport channels/DirAC output */ const int16_t nchan_transport /* i : number of transport channels */ ) @@ -471,7 +501,11 @@ void ivas_dirac_dec_binaural( { int16_t n_samples_sf = slot_size * st_ivas->hDirAC->subframe_nbslots[subframe]; +#ifdef EXTERNAL_ORIENTATIONS + ivas_dirac_dec_binaural_internal( st_ivas, hCombinedOrientationData, p_output, nchan_transport, subframe ); +#else ivas_dirac_dec_binaural_internal( st_ivas, p_output, nchan_transport, subframe ); +#endif for ( ch = 0; ch < 2 * BINAURAL_CHANNELS; ch++ ) { @@ -496,6 +530,9 @@ void ivas_dirac_dec_binaural( static void ivas_dirac_dec_binaural_internal( Decoder_Struct *st_ivas, +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, +#endif float *output_f[], const int16_t nchan_transport, const int16_t subframe ) @@ -508,6 +545,9 @@ static void ivas_dirac_dec_binaural_internal( int16_t max_band_decorr; DIFFUSE_DISTRIBUTION_DATA diffuseDistData; int16_t nBins, offsetSamples; +#ifdef EXTERNAL_ORIENTATIONS + int16_t i, j; +#endif hDirAC = st_ivas->hDirAC; nBins = hDirAC->num_freq_bands; @@ -640,6 +680,24 @@ static void ivas_dirac_dec_binaural_internal( ivas_sba_prototype_renderer( st_ivas, Cldfb_RealBuffer_in, Cldfb_ImagBuffer_in, subframe ); } +#ifdef EXTERNAL_ORIENTATIONS + if ( hCombinedOrientationData ) + { + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + Rmat[i][j] = hCombinedOrientationData->Rmat[subframe][i][j]; + } + } + + if ( nchan_transport == 2 ) + { + adaptTransportSignalsHeadtracked( hCombinedOrientationData, Cldfb_RealBuffer_in, Cldfb_ImagBuffer_in, nBins, hDirAC->subframe_nbslots[subframe], Rmat ); + + ivas_dirac_dec_binaural_check_and_switch_transports_headtracked( hCombinedOrientationData, Cldfb_RealBuffer_in, Cldfb_ImagBuffer_in, nBins, hDirAC->subframe_nbslots[subframe], Rmat ); + } +#else if ( st_ivas->hHeadTrackData && st_ivas->hHeadTrackData->num_quaternions >= 0 ) { QuatToRotMat( st_ivas->hHeadTrackData->Quaternions[subframe], Rmat ); @@ -650,6 +708,7 @@ static void ivas_dirac_dec_binaural_internal( ivas_dirac_dec_binaural_check_and_switch_transports_headtracked( st_ivas->hHeadTrackData, Cldfb_RealBuffer_in, Cldfb_ImagBuffer_in, nBins, hDirAC->subframe_nbslots[subframe], Rmat ); } +#endif } #ifdef FIX_511_OPTIMIZE_PARAMBIN_GAIN_FETCH @@ -1476,7 +1535,11 @@ static void ivas_dirac_dec_binaural_process_output( static void adaptTransportSignalsHeadtracked( +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hHeadTrackData, +#else HEAD_TRACK_DATA_HANDLE hHeadTrackData, +#endif float inRe[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], float inIm[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], const int16_t nBins, @@ -1591,7 +1654,11 @@ static void adaptTransportSignalsHeadtracked( } static void ivas_dirac_dec_binaural_check_and_switch_transports_headtracked( +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hHeadTrackData, +#else HEAD_TRACK_DATA_HANDLE hHeadTrackData, +#endif float inRe[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], float inIm[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], const int16_t nBins, diff --git a/lib_rend/ivas_objectRenderer.c b/lib_rend/ivas_objectRenderer.c index 4d324e60f36c5526f52f50dd90310cdbbc1b7ece..c0eeb1ef74723006adc2045373e3108991b69340 100644 --- a/lib_rend/ivas_objectRenderer.c +++ b/lib_rend/ivas_objectRenderer.c @@ -260,12 +260,16 @@ ivas_error ivas_td_binaural_renderer_unwrap( const int16_t lfe_idx, /* i : LFE channel index */ const IVAS_FORMAT ivas_format, /* i : IVAS format */ ISM_METADATA_HANDLE *hIsmMetaData, /* i : ISM metadata handle */ - const int16_t Opt_Headrotation, /* i : Head rotation flag */ - const IVAS_QUATERNION *Quaternions, /* i : Head tracking data per subframe */ - const IVAS_VECTOR3 *Pos, /* i : Listener position data per subframe */ - const int16_t ism_md_subframe_update, /* i: Number of subframes to delay ism metadata to sync with audio */ - float *output[], /* i/o: SCE channels / Binaural synthesis */ - const int16_t output_frame /* i : output frame length */ +#ifdef EXTERNAL_ORIENTATIONS + const int16_t *enableCombinedOrientation, /* i : Combined orientation flag */ +#else + const int16_t Opt_Headrotation, /* i : Head rotation flag */ +#endif + const IVAS_QUATERNION *Quaternions, /* i : Head tracking data per subframe */ + const IVAS_VECTOR3 *Pos, /* i : Listener position data per subframe */ + const int16_t ism_md_subframe_update, /* i: Number of subframes to delay ism metadata to sync with audio */ + float *output[], /* i/o: SCE channels / Binaural synthesis */ + const int16_t output_frame /* i : output frame length */ ) { int16_t subframe_length; @@ -302,7 +306,11 @@ ivas_error ivas_td_binaural_renderer_unwrap( TDREND_Update_object_positions( hBinRendererTd, num_src, ivas_format, hIsmMetaData ); } /* Update the listener's location/orientation */ +#ifdef EXTERNAL_ORIENTATIONS + TDREND_Update_listener_orientation( hBinRendererTd, ( enableCombinedOrientation != NULL ) ? enableCombinedOrientation[subframe_idx] : 0, ( Quaternions != NULL ) ? &Quaternions[subframe_idx] : NULL, ( Pos != NULL ) ? &Pos[subframe_idx] : NULL ); +#else TDREND_Update_listener_orientation( hBinRendererTd, Opt_Headrotation, ( Quaternions != NULL ) ? &Quaternions[subframe_idx] : NULL, ( Pos != NULL ) ? &Pos[subframe_idx] : NULL ); +#endif if ( hReverb != NULL && hReverb->pConfig.roomAcoustics.late_reverb_on ) { @@ -517,10 +525,27 @@ void TDREND_Update_listener_orientation( UpVec[0] = Rmat[2][0]; UpVec[1] = Rmat[2][1]; UpVec[2] = Rmat[2][2]; +#ifdef EXTERNAL_ORIENTATIONS + if ( Pos != NULL ) + { + /* Input position */ + Pos_p[0] = ( *Pos ).x; + Pos_p[1] = ( *Pos ).y; + Pos_p[2] = ( *Pos ).z; + } + else + { + /* Listener at the origin */ + Pos_p[0] = 0.0f; + Pos_p[1] = 0.0f; + Pos_p[2] = 0.0f; + } +#else /* Input position */ Pos_p[0] = ( *Pos ).x; Pos_p[1] = ( *Pos ).y; Pos_p[2] = ( *Pos ).z; +#endif } else { @@ -600,10 +625,13 @@ ivas_error ivas_td_binaural_open_ext( *---------------------------------------------------------------------*/ ivas_error ivas_td_binaural_renderer_ext( - const TDREND_WRAPPER *pTDRend, /* i : TD Renderer wrapper structure */ - const IVAS_REND_AudioConfig inConfig, /* i : Input audio configuration */ - const LSSETUP_CUSTOM_STRUCT *customLsInput, /* i : Input custom loudspeaker layout */ - const IVAS_REND_HeadRotData *headRotData, /* i : Input head positions */ + const TDREND_WRAPPER *pTDRend, /* i : TD Renderer wrapper structure */ + const IVAS_REND_AudioConfig inConfig, /* i : Input audio configuration */ + const LSSETUP_CUSTOM_STRUCT *customLsInput, /* i : Input custom loudspeaker layout */ + const IVAS_REND_HeadRotData *headRotData, /* i : Input head positions */ +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */ +#endif const IVAS_REND_AudioObjectPosition *currentPos, /* i : Object position */ const REVERB_HANDLE hReverb, /* i : Reverberator handle */ const int16_t output_frame, /* i : output frame length */ @@ -665,8 +693,14 @@ ivas_error ivas_td_binaural_renderer_ext( hIsmMetaData[0]->non_diegetic_flag = currentPos->non_diegetic_flag; } - if ( ( error = ivas_td_binaural_renderer_unwrap( hReverb, transport_config, pTDRend->hBinRendererTd, num_src, lfe_idx, ivas_format, hIsmMetaData, headRotData->headRotEnabled, + if ( ( error = ivas_td_binaural_renderer_unwrap( hReverb, transport_config, pTDRend->hBinRendererTd, num_src, lfe_idx, ivas_format, hIsmMetaData, +#ifdef EXTERNAL_ORIENTATIONS + ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->enableCombinedOrientation : NULL, + ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->Quaternions : NULL, +#else + headRotData->headRotEnabled, ( headRotData != NULL ) ? headRotData->headPositions : NULL, +#endif ( headRotData != NULL ) ? headRotData->Pos : NULL, ism_md_subframe_update_ext, p_output, output_frame ) ) != IVAS_ERR_OK ) { return error; diff --git a/lib_rend/ivas_orient_trk.c b/lib_rend/ivas_orient_trk.c index e05c8061dd406a900bcb5836f8386e3080f6c2cb..3843c48fc32097235e1ed3a6ea2496f5462ccdfe 100644 --- a/lib_rend/ivas_orient_trk.c +++ b/lib_rend/ivas_orient_trk.c @@ -81,7 +81,11 @@ static IVAS_QUATERNION IdentityQuaternion( * Quaternion product *------------------------------------------------------------------------------------------*/ +#ifdef EXTERNAL_ORIENTATIONS +void QuaternionProduct( +#else static void QuaternionProduct( +#endif const IVAS_QUATERNION q1, const IVAS_QUATERNION q2, IVAS_QUATERNION *const r ) @@ -153,7 +157,11 @@ static void QuaternionNormalize( * Computes a spherical linear interpolation between two quaternions *------------------------------------------------------------------------------------------*/ +#ifdef EXTERNAL_ORIENTATIONS +void QuaternionSlerp( +#else static void QuaternionSlerp( +#endif const IVAS_QUATERNION q1, const IVAS_QUATERNION q2, const float t, @@ -231,7 +239,11 @@ static float QuaternionAngle( * Computes an inverse quaternion *------------------------------------------------------------------------------------------*/ +#ifdef EXTERNAL_ORIENTATIONS +void QuaternionInverse( +#else static void QuaternionInverse( +#endif const IVAS_QUATERNION q, IVAS_QUATERNION *const r ) { diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index e1328ca9d39c67b55bc21140c93dd854e95a3f1c..f34cee66d013cccf1e80f059c106d49829c7fa97 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -151,6 +151,9 @@ ivas_error ivas_sba_get_hoa_dec_matrix( void ivas_dirac_dec_binaural( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined orientation handle */ +#endif float output_f[][L_FRAME48k], /* i/o: synthesized core-coder transport channels/DirAC output */ const int16_t nchan_transport /* i : number of transport channels */ ); @@ -227,7 +230,11 @@ ivas_error ivas_td_binaural_renderer_unwrap( const int16_t lfe_idx, /* i : LFE channel index */ const IVAS_FORMAT ivas_format, /* i : IVAS format */ ISM_METADATA_HANDLE *hIsmMetaData, /* i : ISM metadata handle */ +#ifdef EXTERNAL_ORIENTATIONS + const int16_t *enableCombinedOrientation, /* i : Combined orientation flag */ +#else const int16_t Opt_Headrotation, /* i : Head rotation flag */ +#endif const IVAS_QUATERNION *Quaternions, /* i : Head tracking data per subframe */ const IVAS_VECTOR3 *Pos, /* i : Listener position data per subframe */ const int16_t ism_md_subframe_update, @@ -240,6 +247,9 @@ ivas_error ivas_td_binaural_renderer_ext( const IVAS_REND_AudioConfig inConfig, /* i : Input audio configuration */ const LSSETUP_CUSTOM_STRUCT *customLsInput, /* i : Input custom loudspeaker layout */ const IVAS_REND_HeadRotData *headRotData, /* i : Input head positions */ +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */ +#endif const IVAS_REND_AudioObjectPosition *currentPos, /* i : Object position */ const REVERB_HANDLE hReverb, /* i : Reverberator handle */ const int16_t output_frame, /* i : output frame length */ @@ -492,7 +502,7 @@ void ivas_rend_closeCrend( CREND_WRAPPER_HANDLE *pCrend ); ivas_error ivas_rend_initCrendWrapper( - CREND_WRAPPER_HANDLE *pCrend + CREND_WRAPPER_HANDLE *pCrend ); ivas_error ivas_rend_crendProcess( @@ -500,11 +510,15 @@ ivas_error ivas_rend_crendProcess( const AUDIO_CONFIG inConfig, const AUDIO_CONFIG outConfig, DECODER_CONFIG_HANDLE hDecoderConfig, +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, +#else HEAD_TRACK_DATA_HANDLE hHeadTrackData, +#endif IVAS_OUTPUT_SETUP_HANDLE hIntSetup, EFAP_HANDLE hEFAPdata, float *output[], /* i/o: input/output audio channels */ - const int32_t output_Fs + const int32_t output_Fs ); ivas_error ivas_rend_crendProcessSubframe( @@ -512,7 +526,11 @@ ivas_error ivas_rend_crendProcessSubframe( const AUDIO_CONFIG inConfig, /* i : input audio configuration */ const AUDIO_CONFIG outConfig, /* i : output audio configuration */ const DECODER_CONFIG_HANDLE hDecoderConfig, /* i : decoder config. structure */ +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined orientation handle */ +#else const HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : Head tracking data structure */ +#endif const IVAS_OUTPUT_SETUP_HANDLE hIntSetup, /* i : internal setup handle */ const EFAP_HANDLE hEFAPdata, /* i : EFAP handle */ DECODER_TC_BUFFER_HANDLE hTcBuffer, /* i/o: JBM handle */ @@ -792,7 +810,11 @@ void SHrotmatgen( ); void rotateFrame_shd( +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : head and external orientation combined handle */ +#else HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */ +#endif float *output[], /* i/o: unrotated HOA3 signal buffer in TD */ const int16_t subframe_len, /* i : subframe length per channel */ const IVAS_OUTPUT_SETUP hTransSetup, /* i : format for rotation */ @@ -800,7 +822,11 @@ void rotateFrame_shd( ); void rotateFrame_sd( +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : head and external orientation combined handle */ +#else HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */ +#endif float *output[], /* i/o: unrotated SD signal buffer in TD */ const int16_t subframe_len, /* i : subframe length per channel */ const IVAS_OUTPUT_SETUP hTransSetup, /* i : format for rotation */ @@ -818,7 +844,11 @@ void rotateFrame_shd_cldfb( ); void rotateFrame_sd_cldfb( +#ifdef EXTERNAL_ORIENTATIONS + float Rmat[3][3], /* i : real-space rotation matrix */ +#else HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */ +#endif float Cldfb_RealBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain real part */ float Cldfb_ImagBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain imag part */ const IVAS_OUTPUT_SETUP_HANDLE hOutputSetup, /* i : output format setup number of channels */ @@ -827,6 +857,54 @@ void rotateFrame_sd_cldfb( const int16_t nb_band /* i : number of CLDFB bands to process */ ); +#ifdef EXTERNAL_ORIENTATIONS +ivas_error ivas_external_orientation_open( + EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* o : external orientation handle */ +); + +void ivas_external_orientation_close( + EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* i/o: external orientation handle */ +); + +ivas_error ivas_combined_orientation_open( + COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData /* o : combined orientation handle */ +); + +void ivas_combined_orientation_close( + COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData /* i/o: combined orientation handle */ +); + +ivas_error combine_external_and_head_orientations_dec( + HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */ + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ +); + +ivas_error combine_external_and_head_orientations_rend( + IVAS_REND_HeadRotData *hHeadTrackData, /* i : head track handle */ + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ +); + +ivas_error combine_external_and_head_orientations( + IVAS_QUATERNION *headRotQuaternions, /* i : quaternions for head rotation */ + int16_t numHeadRotQuaternions, /* i : number of head rotation quaternions */ + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ +); + +void external_target_interpolation( + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ + const int16_t i +); + +bool are_orientations_same( + const IVAS_QUATERNION *orientation1, + const IVAS_QUATERNION *orientation2 +); +#endif + /*----------------------------------------------------------------------------------* * Renderer configuration @@ -846,6 +924,31 @@ ivas_error ivas_render_config_init_from_rom( ); +#ifdef EXTERNAL_ORIENTATIONS +/*----------------------------------------------------------------------------------* + * Quaternion operations + *----------------------------------------------------------------------------------*/ + +void QuaternionProduct( + const IVAS_QUATERNION q1, + const IVAS_QUATERNION q2, + IVAS_QUATERNION *const r +); + +void QuaternionInverse( + const IVAS_QUATERNION q, + IVAS_QUATERNION *const r +); + +void QuaternionSlerp( + const IVAS_QUATERNION q1, + const IVAS_QUATERNION q2, + const float t, + IVAS_QUATERNION *const r +); +#endif + + /*----------------------------------------------------------------------------------* * Orientation tracking *----------------------------------------------------------------------------------*/ diff --git a/lib_rend/ivas_rotation.c b/lib_rend/ivas_rotation.c index 2ae0347fd38164b50f0c5f917c2fc0d7db86a7f1..7ab33cec891bf979719f71f987270f3b4b217dc5 100644 --- a/lib_rend/ivas_rotation.c +++ b/lib_rend/ivas_rotation.c @@ -249,11 +249,15 @@ void rotateAziEle( *------------------------------------------------------------------------*/ void rotateFrame_shd( +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : head and external orientation combined handle */ +#else HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */ - float *output[], /* i/o: unrotated HOA3 signal buffer in TD */ - const int16_t subframe_len, /* i : subframe length per channel */ - const IVAS_OUTPUT_SETUP hTransSetup, /* i : format for rotation */ - const int16_t subframe_idx /* i : subframe index */ +#endif + float *output[], /* i/o: unrotated HOA3 signal buffer in TD */ + const int16_t subframe_len, /* i : subframe length per channel */ + const IVAS_OUTPUT_SETUP hTransSetup, /* i : format for rotation */ + const int16_t subframe_idx /* i : subframe index */ ) { int16_t i, l, n, m; @@ -281,12 +285,19 @@ void rotateFrame_shd( set_zero( SHrotmat[i], HEADROT_SHMAT_DIM ); } +#ifndef EXTERNAL_ORIENTATIONS /* get next quaternion */ QuatToRotMat( hHeadTrackData->Quaternions[hHeadTrackData->num_quaternions++], hHeadTrackData->Rmat ); +#endif /* calculate ambisonics rotation matrices for the previous and current frames */ +#ifdef EXTERNAL_ORIENTATIONS + SHrotmatgen( SHrotmat_prev, hCombinedOrientationData->Rmat_prev, shd_rot_max_order ); + SHrotmatgen( SHrotmat, hCombinedOrientationData->Rmat[subframe_idx], shd_rot_max_order ); +#else SHrotmatgen( SHrotmat_prev, hHeadTrackData->Rmat_prev, shd_rot_max_order ); SHrotmatgen( SHrotmat, hHeadTrackData->Rmat, shd_rot_max_order ); +#endif for ( i = 0; i < subframe_len; i++ ) { @@ -338,7 +349,11 @@ void rotateFrame_shd( /* move Rmat to Rmat_prev */ for ( i = 0; i < 3; i++ ) { +#ifdef EXTERNAL_ORIENTATIONS + mvr2r( hCombinedOrientationData->Rmat[subframe_idx][i], hCombinedOrientationData->Rmat_prev[i], 3 ); +#else mvr2r( hHeadTrackData->Rmat[i], hHeadTrackData->Rmat_prev[i], 3 ); +#endif } return; @@ -352,12 +367,16 @@ void rotateFrame_shd( *------------------------------------------------------------------------*/ void rotateFrame_sd( +#ifdef EXTERNAL_ORIENTATIONS + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : head and external orientation combined handle */ +#else HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */ - float *output[], /* i/o: unrotated SD signal buffer in TD */ - const int16_t subframe_len, /* i : subframe length per channel */ - const IVAS_OUTPUT_SETUP hTransSetup, /* i : format for rotation */ - const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */ - const int16_t subframe_idx /* i : subframe index */ +#endif + float *output[], /* i/o: unrotated SD signal buffer in TD */ + const int16_t subframe_len, /* i : subframe length per channel */ + const IVAS_OUTPUT_SETUP hTransSetup, /* i : format for rotation */ + const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */ + const int16_t subframe_idx /* i : subframe index */ ) { int16_t i, j; @@ -383,8 +402,10 @@ void rotateFrame_sd( cross_fade[i] = i * tmp; } +#ifndef EXTERNAL_ORIENTATIONS /* Get next quaternion and calculate rotation matrix */ QuatToRotMat( hHeadTrackData->Quaternions[hHeadTrackData->num_quaternions++], hHeadTrackData->Rmat ); +#endif for ( ch_in = 0; ch_in < nchan; ch_in++ ) { @@ -407,7 +428,11 @@ void rotateFrame_sd( ch_in_woLFE = ( ch_in >= index_lfe ) ? ch_in - 1 : ch_in; /* gains for previous subframe rotation */ +#ifdef EXTERNAL_ORIENTATIONS + rotateAziEle( hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], &azimuth, &elevation, hCombinedOrientationData->Rmat_prev, hTransSetup.is_planar_setup ); +#else rotateAziEle( hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], &azimuth, &elevation, hHeadTrackData->Rmat_prev, hTransSetup.is_planar_setup ); +#endif if ( hEFAPdata != NULL && ( hTransSetup.ls_azimuth[ch_in_woLFE] != azimuth || hTransSetup.ls_elevation[ch_in_woLFE] != elevation ) ) { efap_determine_gains( hEFAPdata, tmp_gains, azimuth, elevation, EFAP_MODE_EFAP ); @@ -428,7 +453,11 @@ void rotateFrame_sd( /* gains for current subframe rotation */ +#ifdef EXTERNAL_ORIENTATIONS + rotateAziEle( hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], &azimuth, &elevation, hCombinedOrientationData->Rmat[subframe_idx], hTransSetup.is_planar_setup ); +#else rotateAziEle( hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], &azimuth, &elevation, hHeadTrackData->Rmat, hTransSetup.is_planar_setup ); +#endif if ( hEFAPdata != NULL && ( hTransSetup.ls_azimuth[ch_in_woLFE] != azimuth || hTransSetup.ls_elevation[ch_in_woLFE] != elevation ) ) { efap_determine_gains( hEFAPdata, tmp_gains, azimuth, elevation, EFAP_MODE_EFAP ); @@ -465,7 +494,11 @@ void rotateFrame_sd( /* move Rmat to Rmat_prev */ for ( i = 0; i < 3; i++ ) { +#ifdef EXTERNAL_ORIENTATIONS + mvr2r( hCombinedOrientationData->Rmat[subframe_idx][i], hCombinedOrientationData->Rmat_prev[i], 3 ); +#else mvr2r( hHeadTrackData->Rmat[i], hHeadTrackData->Rmat_prev[i], 3 ); +#endif } /* copy to output */ @@ -581,7 +614,11 @@ void rotateFrame_shd_cldfb( *------------------------------------------------------------------------*/ void rotateFrame_sd_cldfb( - HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */ +#ifdef EXTERNAL_ORIENTATIONS + float Rmat[3][3], /* i : real-space rotation matrix */ +#else + HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */ +#endif float Cldfb_RealBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain real part */ float Cldfb_ImagBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain imag part */ const IVAS_OUTPUT_SETUP_HANDLE hOutputSetup, /* i : output format setup number of channels */ @@ -593,7 +630,9 @@ void rotateFrame_sd_cldfb( int16_t iBlock, iBand, m, n; float gains[MAX_CICP_CHANNELS - 1][MAX_CICP_CHANNELS - 1]; int16_t azimuth, elevation; +#ifndef EXTERNAL_ORIENTATIONS float Rmat[3][3]; +#endif 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]; @@ -615,8 +654,10 @@ void rotateFrame_sd_cldfb( } } +#ifndef EXTERNAL_ORIENTATIONS /* Get next quaternion and calculate rotation matrix */ QuatToRotMat( hHeadTrackData->Quaternions[hHeadTrackData->num_quaternions++], Rmat ); +#endif /* rotation of Euler angles */ for ( n = 0; n < nInChannels; n++ ) @@ -686,6 +727,542 @@ void rotateFrame_sd_cldfb( return; } + +#ifdef EXTERNAL_ORIENTATIONS +/*-----------------------------------------------------------------------* + * ivas_external_orientation_open() + * + * Allocate and initialize external orientation handle + *-----------------------------------------------------------------------*/ + +ivas_error ivas_external_orientation_open( + EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* o : external orientation handle */ +) +{ + int16_t i; + IVAS_QUATERNION identity; + + identity.w = 1.0f; + identity.x = identity.y = identity.z = 0.0f; + + /* Allocate handle */ + if ( ( *hExtOrientationData = (EXTERNAL_ORIENTATION_HANDLE) malloc( sizeof( EXTERNAL_ORIENTATION_DATA ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for external orientation memory\n" ) ); + } + + /* Enable head rotation and disable external orientation as default */ + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + ( *hExtOrientationData )->enableHeadRotation[i] = 1; + ( *hExtOrientationData )->enableExternalOrientation[i] = 0; + ( *hExtOrientationData )->enableRotationInterpolation[i] = 0; + ( *hExtOrientationData )->numFramesToTargetOrientation[i] = 0; + ( *hExtOrientationData )->Quaternions[i] = identity; + } + + return IVAS_ERR_OK; +} + + +/*-----------------------------------------------------------------------* + * ivas_external_orientation_close() + * + * Deallocate external orientation handle + *-----------------------------------------------------------------------*/ + +void ivas_external_orientation_close( + EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* i/o: external orientation handle */ +) +{ + if ( hExtOrientationData == NULL || *hExtOrientationData == NULL ) + { + return; + } + + free( ( *hExtOrientationData ) ); + *hExtOrientationData = NULL; + + return; +} + + +/*-----------------------------------------------------------------------* + * ivas_combined_orientation_open() + * + * Allocate and initialize combined orientation handle + *-----------------------------------------------------------------------*/ + +ivas_error ivas_combined_orientation_open( + COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData /* o : combined orientation handle */ +) +{ + int16_t i, j; + IVAS_QUATERNION identity; + + identity.w = 1.0f; + identity.x = identity.y = identity.z = 0.0f; + + /* Allocate handle */ + if ( ( *hCombinedOrientationData = (COMBINED_ORIENTATION_HANDLE) malloc( sizeof( COMBINED_ORIENTATION_DATA ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for combined orientation memory\n" ) ); + } + + /* Initialization */ + ( *hCombinedOrientationData )->interpolationCoefficient = 1.0f; + ( *hCombinedOrientationData )->interpolationIncrement = 1.0f; + ( *hCombinedOrientationData )->maximumFramesToTargetOrientation = 500; + ( *hCombinedOrientationData )->lrSwitchedNext = 0; + ( *hCombinedOrientationData )->lrSwitchedCurrent = 0; + ( *hCombinedOrientationData )->lrSwitchInterpVal = 0.0f; + ( *hCombinedOrientationData )->isInterpolationOngoing = FALSE; + ( *hCombinedOrientationData )->Quaternions_ext_interpolation_start = identity; + ( *hCombinedOrientationData )->Quaternions_ext_interpolation_target = identity; + + /* Initialise orientations to identity */ + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + ( *hCombinedOrientationData )->enableCombinedOrientation[i] = 0; + ( *hCombinedOrientationData )->Quaternions[i] = identity; + ( *hCombinedOrientationData )->Quaternions_prev_headRot[i] = identity; + ( *hCombinedOrientationData )->Quaternions_prev_extOrientation[i] = identity; + + for ( j = 0; j < 3; j++ ) + { + set_zero( ( *hCombinedOrientationData )->Rmat[i][j], 3 ); + ( *hCombinedOrientationData )->Rmat[i][j][j] = 1.0f; + } + } + + for ( j = 0; j < 3; j++ ) + { + set_zero( ( *hCombinedOrientationData )->Rmat_prev[j], 3 ); + ( *hCombinedOrientationData )->Rmat_prev[j][j] = 1.0f; + } + + set_zero( ( *hCombinedOrientationData )->chEneIIR[0], MASA_FREQUENCY_BANDS ); + set_zero( ( *hCombinedOrientationData )->chEneIIR[1], MASA_FREQUENCY_BANDS ); + set_zero( ( *hCombinedOrientationData )->procChEneIIR[0], MASA_FREQUENCY_BANDS ); + set_zero( ( *hCombinedOrientationData )->procChEneIIR[1], MASA_FREQUENCY_BANDS ); + + return IVAS_ERR_OK; +} + + +/*-----------------------------------------------------------------------* + * ivas_combined_orientation_close() + * + * Deallocate combined orientation handle + *-----------------------------------------------------------------------*/ + +void ivas_combined_orientation_close( + COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData /* i/o: combined orientation handle */ +) +{ + if ( hCombinedOrientationData == NULL || *hCombinedOrientationData == NULL ) + { + return; + } + + free( ( *hCombinedOrientationData ) ); + *hCombinedOrientationData = NULL; + + return; +} + + +/*------------------------------------------------------------------------- + * combine_external_and_head_orientations_dec() + * + * + *------------------------------------------------------------------------*/ + +ivas_error combine_external_and_head_orientations_dec( + HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */ + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ +) +{ + IVAS_QUATERNION *headRotQuaternions = NULL; + int16_t numHeadRotQuaternions = 0; + + if ( hHeadTrackData != NULL ) + { + numHeadRotQuaternions = hHeadTrackData->num_quaternions; + if ( hHeadTrackData->num_quaternions >= 0 ) + { + headRotQuaternions = hHeadTrackData->Quaternions; + } + } + + return combine_external_and_head_orientations( headRotQuaternions, numHeadRotQuaternions, hExtOrientationData, hCombinedOrientationData ); +} + + +/*------------------------------------------------------------------------- + * combine_external_and_head_orientations_rend() + * + * + *------------------------------------------------------------------------*/ + +ivas_error combine_external_and_head_orientations_rend( + IVAS_REND_HeadRotData *hHeadTrackData, /* i : head track handle */ + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ +) +{ + IVAS_QUATERNION *headRotQuaternions = NULL; + int16_t numHeadRotQuaternions = 0; + int16_t i; + + if ( hHeadTrackData != NULL ) + { + if ( hHeadTrackData->headRotEnabled ) + { + headRotQuaternions = hHeadTrackData->headPositions; + } + } + else if ( hExtOrientationData != NULL ) + { + /* Head rotation data not available, use the freezed value or disable */ + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + if ( hExtOrientationData->enableHeadRotation[i] != 2 ) + { + hExtOrientationData->enableHeadRotation[i] = 0; + } + } + } + + return combine_external_and_head_orientations( headRotQuaternions, numHeadRotQuaternions, hExtOrientationData, hCombinedOrientationData ); +} + + +/*------------------------------------------------------------------------- + * combine_external_and_head_orientations() + * + * Combine the external orientations and the head orientation. + * NOTE that the external orientations are inversed. + *------------------------------------------------------------------------*/ + +ivas_error combine_external_and_head_orientations( + IVAS_QUATERNION *headRotQuaternions, /* i : quaternions for head rotation */ + int16_t numHeadRotQuaternions, /* i : number of head rotation quaternions */ + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ +) +{ + int16_t i, j; + IVAS_QUATERNION identity; + + identity.w = 1.0f; + identity.x = identity.y = identity.z = 0.0f; + + /* Form combined orientations or return if no data available */ + if ( hCombinedOrientationData == NULL ) + { + if ( headRotQuaternions != NULL || hExtOrientationData != NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + else + { + return IVAS_ERR_OK; + } + } + else if ( headRotQuaternions == NULL && hExtOrientationData == NULL ) + { + /* Reset the combined orientations and rotations */ + hCombinedOrientationData->isInterpolationOngoing = FALSE; + hCombinedOrientationData->interpolationCoefficient = 1.0f; + hCombinedOrientationData->interpolationIncrement = 1.0f; + hCombinedOrientationData->Quaternions_ext_interpolation_start = identity; + hCombinedOrientationData->Quaternions_ext_interpolation_target = identity; + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + hCombinedOrientationData->enableCombinedOrientation[i] = 0; + hCombinedOrientationData->Quaternions[i] = identity; + + for ( j = 0; j < 3; j++ ) + { + set_zero( hCombinedOrientationData->Rmat[i][j], 3 ); + hCombinedOrientationData->Rmat[i][j][j] = 1.0f; + } + } + } + else if ( hExtOrientationData == NULL && headRotQuaternions != NULL ) + { + /* Head rotation only */ + if ( numHeadRotQuaternions >= 0 ) + { + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; + } + } + } + + if ( hExtOrientationData != NULL ) + { + /* External orientations */ + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + if ( hExtOrientationData->enableRotationInterpolation[i] == 1 && hExtOrientationData->enableExternalOrientation[i] > 0 ) + { + if ( hCombinedOrientationData->isInterpolationOngoing == TRUE && hCombinedOrientationData->interpolationCoefficient <= 1.0f && are_orientations_same( &hCombinedOrientationData->Quaternions_ext_interpolation_target, &hExtOrientationData->Quaternions[i] ) == true ) + { + /* Continue interpolation */ + QuaternionSlerp( hCombinedOrientationData->Quaternions_ext_interpolation_start, hCombinedOrientationData->Quaternions_ext_interpolation_target, hCombinedOrientationData->interpolationCoefficient, &hCombinedOrientationData->Quaternions[i] ); + hCombinedOrientationData->interpolationCoefficient += hCombinedOrientationData->interpolationIncrement; + } + else + { + /* Stop interpolation or check for new interpolation */ + hCombinedOrientationData->isInterpolationOngoing = FALSE; + hCombinedOrientationData->interpolationCoefficient = 1.0f; + hCombinedOrientationData->interpolationIncrement = 1.0f; + external_target_interpolation( hExtOrientationData, hCombinedOrientationData, i ); + } + } + else + { + /* Interpolation disabled, use the current orientation values */ + + /* Use the most recent external orientation */ + if ( hExtOrientationData->enableExternalOrientation[i] == 1 ) + { + hCombinedOrientationData->Quaternions[i] = hExtOrientationData->Quaternions[i]; + } + /* Use the freezed external orientation */ + else if ( hExtOrientationData->enableExternalOrientation[i] == 2 ) + { + hCombinedOrientationData->Quaternions[i] = hCombinedOrientationData->Quaternions_prev_extOrientation[i]; + } + } + } + } + + if ( hExtOrientationData != NULL && headRotQuaternions != NULL ) + { + /* Combine head and external orientations */ + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + /* Use the most recent head rotation */ + if ( hExtOrientationData->enableHeadRotation[i] == 1 && numHeadRotQuaternions >= 0 ) + { + if ( hExtOrientationData->enableExternalOrientation[i] > 0 ) + { + QuaternionProduct( hCombinedOrientationData->Quaternions[i], headRotQuaternions[i], &hCombinedOrientationData->Quaternions[i] ); + } + else + { + hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; + } + } + /* Use the freezed head rotation */ + else if ( hExtOrientationData->enableHeadRotation[i] == 2 && numHeadRotQuaternions >= 0 ) + { + if ( hExtOrientationData->enableExternalOrientation[i] > 0 ) + { + QuaternionProduct( hCombinedOrientationData->Quaternions[i], hCombinedOrientationData->Quaternions_prev_headRot[i], &hCombinedOrientationData->Quaternions[i] ); + } + else + { + hCombinedOrientationData->Quaternions[i] = hCombinedOrientationData->Quaternions_prev_headRot[i]; + } + } + + /* Reset the combined orientations to identity */ + if ( hExtOrientationData->enableHeadRotation[i] == 0 && hExtOrientationData->enableExternalOrientation[i] == 0 ) + { + hCombinedOrientationData->Quaternions[i] = identity; + } + } + } + + if ( headRotQuaternions != NULL || hExtOrientationData != NULL ) + { + /* Calculate the combined rotation matrix */ + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + QuatToRotMat( hCombinedOrientationData->Quaternions[i], hCombinedOrientationData->Rmat[i] ); + } + } + + /* Save the current orientations */ + if ( hExtOrientationData != NULL ) + { + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + if ( hExtOrientationData->enableExternalOrientation[i] > 0 ) + { + hCombinedOrientationData->Quaternions_prev_extOrientation[i] = hCombinedOrientationData->Quaternions[i]; + } + else + { + hCombinedOrientationData->Quaternions_prev_extOrientation[i] = identity; + } + } + } + if ( headRotQuaternions != NULL ) + { + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + if ( hExtOrientationData != NULL ) + { + if ( hExtOrientationData->enableHeadRotation[i] > 0 && numHeadRotQuaternions >= 0 ) + { + hCombinedOrientationData->Quaternions_prev_headRot[i] = headRotQuaternions[i]; + } + else + { + hCombinedOrientationData->Quaternions_prev_headRot[i] = identity; + } + } + else + { + if ( numHeadRotQuaternions >= 0 ) + { + hCombinedOrientationData->Quaternions_prev_headRot[i] = headRotQuaternions[i]; + } + else + { + hCombinedOrientationData->Quaternions_prev_headRot[i] = identity; + } + } + } + } + + /* Check if combined orientation is enabled */ + if ( headRotQuaternions != NULL && hExtOrientationData == NULL ) + { + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + if ( numHeadRotQuaternions >= 0 ) + { + hCombinedOrientationData->enableCombinedOrientation[i] = 1; + } + else + { + hCombinedOrientationData->enableCombinedOrientation[i] = 0; + } + } + } + else if ( headRotQuaternions == NULL && hExtOrientationData != NULL ) + { + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + if ( hExtOrientationData->enableExternalOrientation[i] > 0 ) + { + hCombinedOrientationData->enableCombinedOrientation[i] = 1; + } + else + { + hCombinedOrientationData->enableCombinedOrientation[i] = 0; + } + } + } + else if ( headRotQuaternions != NULL && hExtOrientationData != NULL ) + { + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + if ( hExtOrientationData->enableExternalOrientation[i] > 0 || ( hExtOrientationData->enableHeadRotation[i] > 0 && numHeadRotQuaternions >= 0 ) ) + { + hCombinedOrientationData->enableCombinedOrientation[i] = 1; + } + else + { + hCombinedOrientationData->enableCombinedOrientation[i] = 0; + } + } + } + else + { + for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + hCombinedOrientationData->enableCombinedOrientation[i] = 0; + } + } + + return IVAS_ERR_OK; +} + + +/*------------------------------------------------------------------------- + * external_target_interpolation() + * + * + *------------------------------------------------------------------------*/ + +void external_target_interpolation( + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ + const int16_t i ) +{ + /* Sanity check for number of frames */ + hExtOrientationData->numFramesToTargetOrientation[i] = min( hExtOrientationData->numFramesToTargetOrientation[i], hCombinedOrientationData->maximumFramesToTargetOrientation ); + hExtOrientationData->numFramesToTargetOrientation[i] = max( hExtOrientationData->numFramesToTargetOrientation[i], 0 ); + + /* Interpolate from the current orientation to the target orientation */ + if ( hExtOrientationData->numFramesToTargetOrientation[i] > 0 ) + { + if ( are_orientations_same( &hCombinedOrientationData->Quaternions_ext_interpolation_target, &hExtOrientationData->Quaternions[i] ) == false ) + { + /* Target orientation is different from the previous target, update the values */ + + /* Set the received orientation as the target */ + hCombinedOrientationData->Quaternions_ext_interpolation_target = hExtOrientationData->Quaternions[i]; + + /* Use the most recent external orientation as the starting orientation */ + hCombinedOrientationData->Quaternions_ext_interpolation_start = hCombinedOrientationData->Quaternions_prev_extOrientation[i]; + + /* Calculate the interpolation increment and coefficient */ + hCombinedOrientationData->interpolationIncrement = 1.0f / ( (float) hExtOrientationData->numFramesToTargetOrientation[i] * (float) MAX_PARAM_SPATIAL_SUBFRAMES ); + hCombinedOrientationData->interpolationCoefficient = hCombinedOrientationData->interpolationIncrement; + } + + /* Interpolate */ + hCombinedOrientationData->isInterpolationOngoing = TRUE; + QuaternionSlerp( hCombinedOrientationData->Quaternions_ext_interpolation_start, hCombinedOrientationData->Quaternions_ext_interpolation_target, hCombinedOrientationData->interpolationCoefficient, &hCombinedOrientationData->Quaternions[i] ); + hCombinedOrientationData->interpolationCoefficient += hCombinedOrientationData->interpolationIncrement; + } + else + { + /* Use the target orientation immediately */ + hCombinedOrientationData->isInterpolationOngoing = FALSE; + hCombinedOrientationData->interpolationCoefficient = 1.0f; + hCombinedOrientationData->interpolationIncrement = 1.0f; + hCombinedOrientationData->Quaternions[i] = hExtOrientationData->Quaternions[i]; + } +} + + +/*------------------------------------------------------------------------- + * are_orientations_same() + * + * + *------------------------------------------------------------------------*/ + +bool are_orientations_same( + const IVAS_QUATERNION *orientation1, + const IVAS_QUATERNION *orientation2 ) +{ + bool orientationsAreSame = true; + float error_margin = 0.05f; + if ( fabsf( orientation1->w - orientation2->w ) > error_margin || + fabsf( orientation1->x - orientation2->x ) > error_margin || + fabsf( orientation1->y - orientation2->y ) > error_margin || + fabsf( orientation1->z - orientation2->z ) > error_margin ) + { + orientationsAreSame = false; + } + + return orientationsAreSame; +} + +#endif // EXTERNAL_ORIENTATIONS + /*-----------------------------------------------------------------------* * Local Function definitions *-----------------------------------------------------------------------*/ diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index b90b7b55077d08ba60f68c495c4e0b1fdc02d823..2d6419ed8c4957c41d07cb2947cd7881de758e9b 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -274,6 +274,48 @@ typedef struct ivas_binaural_head_track_struct } HEAD_TRACK_DATA, *HEAD_TRACK_DATA_HANDLE; +#ifdef EXTERNAL_ORIENTATIONS +/*----------------------------------------------------------------------------------* + * External orientation data structure + *----------------------------------------------------------------------------------*/ + +typedef struct ivas_external_orientation_struct +{ + int8_t enableHeadRotation[MAX_PARAM_SPATIAL_SUBFRAMES]; /* 0 - disable, 1 - enable, 2 - freeze to previous rotation */ + int8_t enableExternalOrientation[MAX_PARAM_SPATIAL_SUBFRAMES]; /* 0 - disable, 1 - enable, 2 - freeze to previous orientation */ + int8_t enableRotationInterpolation[MAX_PARAM_SPATIAL_SUBFRAMES]; /* 0 - disable, 1 - enable */ + int16_t numFramesToTargetOrientation[MAX_PARAM_SPATIAL_SUBFRAMES]; /* Number of frames until target orientation is reached */ + IVAS_QUATERNION Quaternions[MAX_PARAM_SPATIAL_SUBFRAMES]; /* External orientation in quaternions */ + +} EXTERNAL_ORIENTATION_DATA, *EXTERNAL_ORIENTATION_HANDLE; + +/*----------------------------------------------------------------------------------* + * Combined orientation data structure for the external orienations and head orientation + *----------------------------------------------------------------------------------*/ + +typedef struct ivas_combined_orientation_struct +{ + int16_t enableCombinedOrientation[MAX_PARAM_SPATIAL_SUBFRAMES]; + float interpolationCoefficient; + float interpolationIncrement; + int16_t maximumFramesToTargetOrientation; + uint8_t lrSwitchedNext; + uint8_t lrSwitchedCurrent; + float lrSwitchInterpVal; + bool isInterpolationOngoing; + IVAS_QUATERNION Quaternions[MAX_PARAM_SPATIAL_SUBFRAMES]; + IVAS_QUATERNION Quaternions_prev_headRot[MAX_PARAM_SPATIAL_SUBFRAMES]; + IVAS_QUATERNION Quaternions_prev_extOrientation[MAX_PARAM_SPATIAL_SUBFRAMES]; + IVAS_QUATERNION Quaternions_ext_interpolation_start; + IVAS_QUATERNION Quaternions_ext_interpolation_target; + float Rmat[MAX_PARAM_SPATIAL_SUBFRAMES][3][3]; + float Rmat_prev[3][3]; + float chEneIIR[2][MASA_FREQUENCY_BANDS]; /* independent of the format. MASA bands are suitable for the task and readily available in ROM. */ + float procChEneIIR[2][MASA_FREQUENCY_BANDS]; + +} COMBINED_ORIENTATION_DATA, *COMBINED_ORIENTATION_HANDLE; +#endif + /*----------------------------------------------------------------------------------* * Reverberator structure *----------------------------------------------------------------------------------*/ diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index b4a0950c5fbce72577bab6f78ef74c5ddf6a181e..f4a51d44c9e8b3c4f93ceb9975dd767453d4f335 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -95,6 +95,9 @@ typedef struct * multiple rendering configurations unless one global one can be used. If this is not relevant, * feel free to remove this TODO. */ +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *pCombinedOrientationData; +#endif } rendering_context; /* Common base for input structs */ @@ -193,6 +196,11 @@ struct IVAS_REND IVAS_REND_HeadRotData headRotData; +#ifdef EXTERNAL_ORIENTATIONS + EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData; + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData; +#endif + int8_t rendererConfigEnabled; RENDER_CONFIG_DATA *hRendererConfig; /* Renderer config pointer */ }; @@ -953,6 +961,7 @@ static void closeHeadRotation( return; } + static void initRotMatrix( rotation_matrix rot_mat ) { @@ -1032,6 +1041,9 @@ static rendering_context getRendCtx( ctx.pCustomLsOut = &hIvasRend->customLsOut; ctx.pEfapOutWrapper = &hIvasRend->efapOutWrapper; ctx.pHeadRotData = &hIvasRend->headRotData; +#ifdef EXTERNAL_ORIENTATIONS + ctx.pCombinedOrientationData = &hIvasRend->hCombinedOrientationData; +#endif return ctx; } @@ -2510,10 +2522,28 @@ static DecoderDummy *initDecoderDummy( decDummy->hHeadTrackData->lrSwitchedNext = 0; decDummy->hHeadTrackData->OrientationTracker = (ivas_orient_trk_state_t *) malloc( sizeof( ivas_orient_trk_state_t ) ); ivas_orient_trk_Init( decDummy->hHeadTrackData->OrientationTracker ); + +#ifdef EXTERNAL_ORIENTATIONS + /* External orientations */ + if ( ( error = ivas_external_orientation_open( &( decDummy->hExtOrientationData ) ) ) != IVAS_ERR_OK ) + { + assert( error == IVAS_ERR_OK ); + } + + /* Combined orientations */ + if ( ( error = ivas_combined_orientation_open( &( decDummy->hCombinedOrientationData ) ) ) != IVAS_ERR_OK ) + { + assert( error == IVAS_ERR_OK ); + } +#endif } else { decDummy->hHeadTrackData = NULL; +#ifdef EXTERNAL_ORIENTATIONS + decDummy->hExtOrientationData = NULL; + decDummy->hCombinedOrientationData = NULL; +#endif } if ( enableRenderConfig ) @@ -2599,6 +2629,17 @@ static void freeDecoderDummy( } free( pDecDummy->hHeadTrackData ); } +#ifdef EXTERNAL_ORIENTATIONS + if ( pDecDummy->hExtOrientationData != NULL ) + { + free( pDecDummy->hExtOrientationData ); + } + if ( pDecDummy->hCombinedOrientationData != NULL ) + { + free( pDecDummy->hCombinedOrientationData ); + } +#endif + ivas_render_config_close( &pDecDummy->hRenderConfig ); /* CLDFB handles */ @@ -2721,6 +2762,20 @@ ivas_error IVAS_REND_Open( return error; } +#ifdef EXTERNAL_ORIENTATIONS + /* Initialize external orientation data */ + if ( ( error = ivas_external_orientation_open( &( hIvasRend->hExternalOrientationData ) ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* Initilize combined orientation data */ + if ( ( error = ivas_combined_orientation_open( &( hIvasRend->hCombinedOrientationData ) ) ) != IVAS_ERR_OK ) + { + return error; + } +#endif + /* Initialize EFAP */ if ( ( error = initEfap( &hIvasRend->efapOutWrapper, outConfig, &hIvasRend->customLsOut ) ) != IVAS_ERR_OK ) { @@ -4002,6 +4057,104 @@ ivas_error IVAS_REND_SetReferenceVector( } +#ifdef EXTERNAL_ORIENTATIONS +/*---------------------------------------------------------------------* + * IVAS_REND_SetExternalOrientation() + * + * + *---------------------------------------------------------------------*/ + +ivas_error IVAS_REND_SetExternalOrientation( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_QUATERNION *orientation, /* i : external orientation data */ + int8_t *enableHeadRotation, /* i : flag to enable head rotation for this frame */ + int8_t *enableExternalOrientation, /* i : flag to enable external orientation for this frame */ + int8_t *enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ + int16_t *numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +) +{ + int16_t i; + + /* Validate function arguments */ + if ( hIvasRend == NULL || hIvasRend->hExternalOrientationData == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + if ( orientation == NULL ) + { + for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; ++i ) + { + hIvasRend->hExternalOrientationData->enableExternalOrientation[i] = 0; + } + } + else + { + for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; ++i ) + { + QuaternionInverse( orientation[i], &hIvasRend->hExternalOrientationData->Quaternions[i] ); + + hIvasRend->hExternalOrientationData->enableHeadRotation[i] = enableHeadRotation[i]; + hIvasRend->hExternalOrientationData->enableExternalOrientation[i] = enableExternalOrientation[i]; + hIvasRend->hExternalOrientationData->enableRotationInterpolation[i] = enableRotationInterpolation[i]; + hIvasRend->hExternalOrientationData->numFramesToTargetOrientation[i] = numFramesToTargetOrientation[i]; + } + } + + return IVAS_ERR_OK; +} + + +/*---------------------------------------------------------------------* + * IVAS_REND_CombineHeadAndExternalOrientation() + * + * + *---------------------------------------------------------------------*/ + +ivas_error IVAS_REND_CombineHeadAndExternalOrientation( + IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */ +) +{ + if ( hIvasRend == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + return combine_external_and_head_orientations_rend( &hIvasRend->headRotData, hIvasRend->hExternalOrientationData, hIvasRend->hCombinedOrientationData ); +} + + +/*---------------------------------------------------------------------* + * IVAS_REND_GetCombinedOrientation() + * + * + *---------------------------------------------------------------------*/ + +ivas_error IVAS_REND_GetCombinedOrientation( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_QUATERNION *pOrientation /* i/o: Quaternion pointer processed orientation */ +) +{ + int16_t i; + + if ( hIvasRend == NULL || pOrientation == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + if ( hIvasRend->hCombinedOrientationData != NULL ) + { + for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; ++i ) + { + pOrientation[i] = hIvasRend->hCombinedOrientationData->Quaternions[i]; + } + } + + return IVAS_ERR_OK; +} +#endif + + /*-------------------------------------------------------------------* * Local functions *-------------------------------------------------------------------*/ @@ -4097,12 +4250,18 @@ static ivas_error rotateFrameMc( IVAS_REND_AudioConfig inConfig, /* i : Input Audio config */ LSSETUP_CUSTOM_STRUCT inCustomLs, /* i : Input Custom LS setup */ const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */ - rotation_gains gains_prev, /* i/o: Previous frame rotation gains */ - const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */ - IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */ +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */ +#endif + rotation_gains gains_prev, /* i/o: Previous frame rotation gains */ + const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */ + IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */ ) { int16_t i; +#ifdef EXTERNAL_ORIENTATIONS + int16_t j; +#endif int16_t subframe_idx, subframe_len; int16_t azimuth, elevation; int16_t is_planar_setup, lfe_idx; @@ -4146,8 +4305,27 @@ static ivas_error rotateFrameMc( subframe_len = inAudio.config.numSamplesPerChannel / RENDERER_HEAD_POSITIONS_PER_FRAME; for ( subframe_idx = 0; subframe_idx < RENDERER_HEAD_POSITIONS_PER_FRAME; subframe_idx++ ) { +#ifdef EXTERNAL_ORIENTATIONS + for ( i = 0; i < 3; i++ ) + { + if ( hCombinedOrientationData != NULL ) + { + for ( j = 0; j < 3; j++ ) + { + Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][j]; + } + } + else + { + /* Set to identity */ + set_zero( Rmat[i], 3 ); + Rmat[i][i] = 1.0f; + } + } +#else /* Get next quaternion and calculate rotation matrix */ QuatToRotMat( headRotData->headPositions[subframe_idx], Rmat ); +#endif for ( ch_in = 0; ch_in < nchan; ch_in++ ) { @@ -4217,8 +4395,11 @@ static ivas_error rotateFrameSba( IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */ IVAS_REND_AudioConfig inConfig, /* i : Input Audio config */ const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */ - rotation_gains gains_prev, /* i/o: Previous frame rotation gains */ - IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */ +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */ +#endif + rotation_gains gains_prev, /* i/o: Previous frame rotation gains */ + IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */ ) { int16_t i, l, n, m; @@ -4248,8 +4429,27 @@ static ivas_error rotateFrameSba( set_zero( gains[i], HEADROT_SHMAT_DIM ); } +#ifdef EXTERNAL_ORIENTATIONS + for ( i = 0; i < 3; i++ ) + { + if ( hCombinedOrientationData != NULL ) + { + for ( l = 0; l < 3; l++ ) + { + Rmat[i][l] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][l]; + } + } + else + { + /* Set to identity */ + set_zero( Rmat[i], 3 ); + Rmat[i][i] = 1.0f; + } + } +#else /* Get next quaternion and calculate rotation matrix */ QuatToRotMat( headRotData->headPositions[subframe_idx], Rmat ); +#endif /* calculate ambisonics rotation matrices for the previous and current frames */ SHrotmatgen( gains, Rmat, shd_rot_max_order ); @@ -4330,6 +4530,9 @@ static ivas_error renderIsmToBinaural( ismInput->base.inConfig, NULL, ismInput->base.ctx.pHeadRotData, +#ifdef EXTERNAL_ORIENTATIONS + ismInput->base.ctx.pCombinedOrientationData, +#endif &ismInput->currentPos, ismInput->hReverb, outAudio.config.numSamplesPerChannel, @@ -4355,13 +4558,19 @@ static ivas_error renderIsmToBinauralRoom( int16_t tmp; rotation_matrix Rmat; float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; - IVAS_QUATERNION quat; ivas_error error; pan_vector currentPanGains; pan_vector previousPanGains; IVAS_REND_AudioBuffer tmpMcBuffer; IVAS_REND_AudioObjectPosition rotatedPos; +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; + int8_t combinedOrientationEnabled; + int16_t j; +#else + IVAS_QUATERNION quat; const IVAS_REND_HeadRotData *headRotData; +#endif float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS]; for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) @@ -4371,10 +4580,32 @@ static ivas_error renderIsmToBinauralRoom( push_wmops( "renderIsmToBinauralRoom" ); - headRotData = ismInput->base.ctx.pHeadRotData; rotatedPos = defaultObjectPosition(); - if ( ismInput->hReverb != NULL && ismInput->hReverb->pConfig.roomAcoustics.use_brir == 0 && ismInput->hReverb->pConfig.roomAcoustics.late_reverb_on == 1 && headRotData->headRotEnabled ) +#ifdef EXTERNAL_ORIENTATIONS + hCombinedOrientationData = ismInput->base.ctx.pCombinedOrientationData; + combinedOrientationEnabled = 0; + if ( hCombinedOrientationData != NULL ) + { + for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) + { + if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + { + combinedOrientationEnabled = 1; + break; + } + } + } +#else + headRotData = ismInput->base.ctx.pHeadRotData; +#endif + + if ( ismInput->hReverb != NULL && ismInput->hReverb->pConfig.roomAcoustics.use_brir == 0 && ismInput->hReverb->pConfig.roomAcoustics.late_reverb_on == 1 && +#ifdef EXTERNAL_ORIENTATIONS + combinedOrientationEnabled ) +#else + headRotData->headRotEnabled ) +#endif { copyBufferTo2dArray( ismInput->base.inputBuffer, tmpRendBuffer ); @@ -4382,6 +4613,9 @@ static ivas_error renderIsmToBinauralRoom( ismInput->base.inConfig, NULL, ismInput->base.ctx.pHeadRotData, +#ifdef EXTERNAL_ORIENTATIONS + ismInput->base.ctx.pCombinedOrientationData, +#endif &ismInput->currentPos, ismInput->hReverb, outAudio.config.numSamplesPerChannel, @@ -4393,19 +4627,41 @@ static ivas_error renderIsmToBinauralRoom( } else { - +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( headRotData->headRotEnabled ) +#endif { subframe_len = ismInput->base.inputBuffer.config.numSamplesPerChannel / RENDERER_HEAD_POSITIONS_PER_FRAME; // for ( subframe_idx = 0; subframe_idx < RENDERER_HEAD_POSITIONS_PER_FRAME; subframe_idx++ ) for ( subframe_idx = 0; subframe_idx < 1; subframe_idx++ ) { +#ifdef EXTERNAL_ORIENTATIONS + for ( i = 0; i < 3; i++ ) + { + if ( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] ) + { + for ( j = 0; j < 3; j++ ) + { + Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][j]; + } + } + else + { + /* Set to identity */ + set_zero( Rmat[i], 3 ); + Rmat[i][i] = 1.0f; + } + } +#else quat.w = headRotData->headPositions[subframe_idx].w; quat.x = headRotData->headPositions[subframe_idx].x; quat.y = headRotData->headPositions[subframe_idx].y; quat.z = headRotData->headPositions[subframe_idx].z; QuatToRotMat( quat, Rmat ); +#endif } (void) subframe_len; // avoid warning } @@ -4414,7 +4670,11 @@ static ivas_error renderIsmToBinauralRoom( /* Possible optimization: less processing needed if position didn't change * needs a lot of cleanup, we could also add rot_gains_prev to ismInput and use that */ /* previous position gains */ +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( headRotData->headRotEnabled ) +#endif { rotateAziEle( ismInput->previousPos.azimuth, ismInput->previousPos.elevation, &azi_rot, &ele_rot, ismInput->rot_mat_prev, 0 ); rotatedPos.azimuth = (float) azi_rot; @@ -4422,15 +4682,24 @@ static ivas_error renderIsmToBinauralRoom( } if ( ( error = getEfapGains( *ismInput->base.ctx.pEfapOutWrapper, +#ifdef EXTERNAL_ORIENTATIONS + ( combinedOrientationEnabled ) ? rotatedPos.azimuth : ismInput->previousPos.azimuth, + ( combinedOrientationEnabled ) ? rotatedPos.elevation : ismInput->previousPos.elevation, +#else ( headRotData->headRotEnabled ) ? rotatedPos.azimuth : ismInput->previousPos.azimuth, ( headRotData->headRotEnabled ) ? rotatedPos.elevation : ismInput->previousPos.elevation, +#endif previousPanGains ) ) != IVAS_ERR_OK ) { return error; } /* current position gains */ +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( headRotData->headRotEnabled ) +#endif { rotateAziEle( ismInput->currentPos.azimuth, ismInput->currentPos.elevation, &azi_rot, &ele_rot, Rmat, 0 ); rotatedPos.azimuth = (float) azi_rot; @@ -4438,8 +4707,13 @@ static ivas_error renderIsmToBinauralRoom( } if ( ( error = getEfapGains( *ismInput->base.ctx.pEfapOutWrapper, +#ifdef EXTERNAL_ORIENTATIONS + ( combinedOrientationEnabled ) ? rotatedPos.azimuth : ismInput->currentPos.azimuth, + ( combinedOrientationEnabled ) ? rotatedPos.elevation : ismInput->currentPos.elevation, +#else ( headRotData->headRotEnabled ) ? rotatedPos.azimuth : ismInput->currentPos.azimuth, ( headRotData->headRotEnabled ) ? rotatedPos.elevation : ismInput->currentPos.elevation, +#endif currentPanGains ) ) != IVAS_ERR_OK ) { return error; @@ -4730,11 +5004,17 @@ static ivas_error renderMcToBinaural( const IVAS_REND_AudioConfig outConfig, IVAS_REND_AudioBuffer outAudio ) { - int8_t headRotEnabled; float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; IVAS_REND_AudioConfig inConfig; ivas_error error; IVAS_REND_AudioBuffer tmpRotBuffer; +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; + int8_t combinedOrientationEnabled; + int16_t subframe_idx; +#else + int8_t headRotEnabled; +#endif float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS]; int16_t i; @@ -4745,14 +5025,42 @@ static ivas_error renderMcToBinaural( push_wmops( "renderMcToBinaural" ); - headRotEnabled = mcInput->base.ctx.pHeadRotData->headRotEnabled; inConfig = mcInput->base.inConfig; - if ( ( inConfig == IVAS_REND_AUDIO_CONFIG_LS_CUSTOM ) || ( headRotEnabled && ( inConfig == IVAS_REND_AUDIO_CONFIG_5_1 || inConfig == IVAS_REND_AUDIO_CONFIG_7_1 ) ) ) +#ifdef EXTERNAL_ORIENTATIONS + hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData; + combinedOrientationEnabled = 0; + if ( hCombinedOrientationData != NULL ) + { + for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) + { + if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + { + combinedOrientationEnabled = 1; + break; + } + } + } +#else + headRotEnabled = mcInput->base.ctx.pHeadRotData->headRotEnabled; +#endif + + if ( ( inConfig == IVAS_REND_AUDIO_CONFIG_LS_CUSTOM ) || ( +#ifdef EXTERNAL_ORIENTATIONS + combinedOrientationEnabled +#else + headRotEnabled +#endif + + && ( inConfig == IVAS_REND_AUDIO_CONFIG_5_1 || inConfig == IVAS_REND_AUDIO_CONFIG_7_1 ) ) ) { copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer ); - if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, NULL, + if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, +#ifdef EXTERNAL_ORIENTATIONS + mcInput->base.ctx.pCombinedOrientationData, +#endif + NULL, mcInput->hReverb, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK ) { return error; @@ -4761,13 +5069,20 @@ static ivas_error renderMcToBinaural( else { /* apply rotation */ +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( headRotEnabled ) +#endif { tmpRotBuffer = mcInput->base.inputBuffer; tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, +#ifdef EXTERNAL_ORIENTATIONS + mcInput->base.ctx.pCombinedOrientationData, +#endif mcInput->rot_gains_prev, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) { return error; @@ -4806,13 +5121,19 @@ static ivas_error renderMcToBinauralRoom( const IVAS_REND_AudioConfig outConfig, IVAS_REND_AudioBuffer outAudio ) { - int8_t headRotEnabled; float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; IVAS_REND_AudioConfig inConfig; ivas_error error; IVAS_REND_AudioBuffer tmpRotBuffer; float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS]; int16_t i; +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; + int8_t combinedOrientationEnabled; + int16_t subframe_idx; +#else + int8_t headRotEnabled; +#endif for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) { @@ -4821,14 +5142,40 @@ static ivas_error renderMcToBinauralRoom( push_wmops( "renderMcToBinauralRoom" ); - headRotEnabled = mcInput->base.ctx.pHeadRotData->headRotEnabled; inConfig = mcInput->base.inConfig; - if ( ( mcInput->hReverb != NULL && mcInput->hReverb->pConfig.roomAcoustics.use_brir == 0 && mcInput->hReverb->pConfig.roomAcoustics.late_reverb_on == 1 ) && ( ( inConfig == IVAS_REND_AUDIO_CONFIG_LS_CUSTOM ) || ( headRotEnabled && ( inConfig == IVAS_REND_AUDIO_CONFIG_5_1 || inConfig == IVAS_REND_AUDIO_CONFIG_7_1 ) ) ) ) +#ifdef EXTERNAL_ORIENTATIONS + hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData; + combinedOrientationEnabled = 0; + if ( hCombinedOrientationData != NULL ) + { + for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) + { + if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + { + combinedOrientationEnabled = 1; + break; + } + } + } +#else + headRotEnabled = mcInput->base.ctx.pHeadRotData->headRotEnabled; +#endif + + if ( ( mcInput->hReverb != NULL && mcInput->hReverb->pConfig.roomAcoustics.use_brir == 0 && mcInput->hReverb->pConfig.roomAcoustics.late_reverb_on == 1 ) && ( ( inConfig == IVAS_REND_AUDIO_CONFIG_LS_CUSTOM ) || ( +#ifdef EXTERNAL_ORIENTATIONS + combinedOrientationEnabled +#else + headRotEnabled +#endif + && ( inConfig == IVAS_REND_AUDIO_CONFIG_5_1 || inConfig == IVAS_REND_AUDIO_CONFIG_7_1 ) ) ) ) { copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer ); if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, +#ifdef EXTERNAL_ORIENTATIONS + mcInput->base.ctx.pCombinedOrientationData, +#endif NULL, mcInput->hReverb, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK ) { return error; @@ -4837,13 +5184,20 @@ static ivas_error renderMcToBinauralRoom( else { /* apply rotation */ +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( headRotEnabled ) +#endif { tmpRotBuffer = mcInput->base.inputBuffer; tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, +#ifdef EXTERNAL_ORIENTATIONS + mcInput->base.ctx.pCombinedOrientationData, +#endif mcInput->rot_gains_prev, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) { return error; @@ -4882,7 +5236,6 @@ static ivas_error renderMcCustomLsToBinauralRoom( const IVAS_REND_AudioConfig outConfig, IVAS_REND_AudioBuffer outAudio ) { - int8_t headRotEnabled; int16_t i; int16_t tmp; float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; @@ -4891,26 +5244,57 @@ static ivas_error renderMcCustomLsToBinauralRoom( IVAS_REND_AudioBuffer tmpMcBuffer; IVAS_REND_AudioBuffer *tmpBufPtr; float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS]; +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; + int8_t combinedOrientationEnabled; + int16_t subframe_idx; +#else + int8_t headRotEnabled; +#endif push_wmops( "renderMcCustomLsToBinauralRoom" ); tmpRotBuffer = outAudio; /* avoid compilation warning */ - headRotEnabled = mcInput->base.ctx.pHeadRotData->headRotEnabled; - for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) { p_tmpCrendBuffer[i] = tmpCrendBuffer[i]; } +#ifdef EXTERNAL_ORIENTATIONS + hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData; + combinedOrientationEnabled = 0; + if ( hCombinedOrientationData != NULL ) + { + for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) + { + if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + { + combinedOrientationEnabled = 1; + break; + } + } + } +#else + headRotEnabled = mcInput->base.ctx.pHeadRotData->headRotEnabled; +#endif + /* apply rotation */ +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( headRotEnabled ) +#endif { tmpRotBuffer = mcInput->base.inputBuffer; tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); - if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->rot_gains_prev, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, +#ifdef EXTERNAL_ORIENTATIONS + mcInput->base.ctx.pCombinedOrientationData, +#endif + mcInput->rot_gains_prev, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) { return error; } @@ -4928,7 +5312,11 @@ static ivas_error renderMcCustomLsToBinauralRoom( tmpMcBuffer.data = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( float ) ); set_zero( tmpMcBuffer.data, tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels ); +#ifdef EXTERNAL_ORIENTATIONS + tmpBufPtr = ( combinedOrientationEnabled ) ? &tmpRotBuffer : &mcInput->base.inputBuffer; +#else tmpBufPtr = ( headRotEnabled ) ? &tmpRotBuffer : &mcInput->base.inputBuffer; +#endif for ( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ ) { renderBufferChannel( *tmpBufPtr, i, mcInput->panGains[i], tmpMcBuffer ); @@ -4949,7 +5337,11 @@ static ivas_error renderMcCustomLsToBinauralRoom( return error; } +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( headRotEnabled ) +#endif { free( tmpRotBuffer.data ); } @@ -5139,6 +5531,11 @@ static ivas_error renderSbaToBinaural( IVAS_REND_AudioBuffer tmpRotBuffer; float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS]; int16_t i; +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; + int8_t combinedOrientationEnabled; + int16_t subframe_idx; +#endif push_wmops( "renderSbaToBinaural" ); @@ -5147,8 +5544,28 @@ static ivas_error renderSbaToBinaural( p_tmpCrendBuffer[i] = tmpCrendBuffer[i]; } +#ifdef EXTERNAL_ORIENTATIONS + hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData; + combinedOrientationEnabled = 0; + if ( hCombinedOrientationData != NULL ) + { + for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) + { + if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + { + combinedOrientationEnabled = 1; + break; + } + } + } +#endif + /* apply rotation */ +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( sbaInput->base.ctx.pHeadRotData->headRotEnabled ) +#endif { tmpRotBuffer = sbaInput->base.inputBuffer; tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); @@ -5156,7 +5573,11 @@ static ivas_error renderSbaToBinaural( /* 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->rot_gains_prev, tmpRotBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, +#ifdef EXTERNAL_ORIENTATIONS + sbaInput->base.ctx.pCombinedOrientationData, +#endif + sbaInput->rot_gains_prev, tmpRotBuffer ) ) != IVAS_ERR_OK ) { return error; } @@ -5188,7 +5609,6 @@ static ivas_error renderSbaToBinauralRoom( const IVAS_REND_AudioConfig outConfig, IVAS_REND_AudioBuffer outAudio ) { - int8_t headRotEnabled; int16_t i; int16_t tmp; float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; @@ -5197,6 +5617,13 @@ static ivas_error renderSbaToBinauralRoom( IVAS_REND_AudioBuffer tmpMcBuffer; IVAS_REND_AudioBuffer *tmpBufPtr; float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS]; +#ifdef EXTERNAL_ORIENTATIONS + const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; + int8_t combinedOrientationEnabled; + int16_t subframe_idx; +#else + int8_t headRotEnabled; +#endif tmpRotBuffer = outAudio; /* avoid compilation warning */ @@ -5207,10 +5634,30 @@ static ivas_error renderSbaToBinauralRoom( p_tmpCrendBuffer[i] = tmpCrendBuffer[i]; } +#ifdef EXTERNAL_ORIENTATIONS + hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData; + combinedOrientationEnabled = 0; + if ( hCombinedOrientationData != NULL ) + { + for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) + { + if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) + { + combinedOrientationEnabled = 1; + break; + } + } + } +#else headRotEnabled = sbaInput->base.ctx.pHeadRotData->headRotEnabled; +#endif /* apply rotation */ +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( headRotEnabled ) +#endif { tmpRotBuffer = sbaInput->base.inputBuffer; tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); @@ -5218,7 +5665,11 @@ static ivas_error renderSbaToBinauralRoom( /* 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->rot_gains_prev, tmpRotBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, +#ifdef EXTERNAL_ORIENTATIONS + sbaInput->base.ctx.pCombinedOrientationData, +#endif + sbaInput->rot_gains_prev, tmpRotBuffer ) ) != IVAS_ERR_OK ) { return error; } @@ -5236,7 +5687,11 @@ static ivas_error renderSbaToBinauralRoom( tmpMcBuffer.data = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( float ) ); set_zero( tmpMcBuffer.data, tmpMcBuffer.config.numChannels * tmpMcBuffer.config.numSamplesPerChannel ); +#ifdef EXTERNAL_ORIENTATIONS + tmpBufPtr = ( combinedOrientationEnabled ) ? &tmpRotBuffer : &sbaInput->base.inputBuffer; +#else tmpBufPtr = ( headRotEnabled ) ? &tmpRotBuffer : &sbaInput->base.inputBuffer; +#endif for ( i = 0; i < sbaInput->base.inputBuffer.config.numChannels; i++ ) { renderBufferChannel( *tmpBufPtr, i, sbaInput->hoaDecMtx[i], tmpMcBuffer ); @@ -5253,7 +5708,11 @@ static ivas_error renderSbaToBinauralRoom( accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio ); +#ifdef EXTERNAL_ORIENTATIONS + if ( combinedOrientationEnabled ) +#else if ( headRotEnabled ) +#endif { free( tmpRotBuffer.data ); } @@ -5394,7 +5853,11 @@ static void renderMasaToMc( if ( masaInput->decDummy->renderer_type == RENDERER_STEREO_PARAMETRIC ) { +#ifdef EXTERNAL_ORIENTATIONS + ivas_dirac_dec_binaural( masaInput->decDummy, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer, masaInput->base.inputBuffer.config.numChannels ); +#else ivas_dirac_dec_binaural( masaInput->decDummy, tmpBuffer, masaInput->base.inputBuffer.config.numChannels ); +#endif } else { @@ -5431,7 +5894,11 @@ static void renderMasaToBinaural( copyBufferTo2dArray( masaInput->base.inputBuffer, tmpBuffer ); copyMasaMetadataToDiracRenderer( &masaInput->masaMetadata, masaInput->decDummy->hDirAC ); +#ifdef EXTERNAL_ORIENTATIONS + ivas_dirac_dec_binaural( masaInput->decDummy, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer, masaInput->base.inputBuffer.config.numChannels ); +#else ivas_dirac_dec_binaural( masaInput->decDummy, tmpBuffer, masaInput->base.inputBuffer.config.numChannels ); +#endif accumulate2dArrayToBuffer( tmpBuffer, &outAudio ); @@ -5649,6 +6116,11 @@ void IVAS_REND_Close( closeHeadRotation( hIvasRend ); +#ifdef EXTERNAL_ORIENTATIONS + ivas_external_orientation_close( &hIvasRend->hExternalOrientationData ); + ivas_combined_orientation_close( &hIvasRend->hCombinedOrientationData ); +#endif + free( hIvasRend ); *phIvasRend = NULL; diff --git a/lib_rend/lib_rend.h b/lib_rend/lib_rend.h index cf0db7e4b5139552032bb021664a55124354c1ac..406fa83e8744c59875aa19743944c0d6172ede27 100644 --- a/lib_rend/lib_rend.h +++ b/lib_rend/lib_rend.h @@ -275,6 +275,26 @@ ivas_error IVAS_REND_SetReferenceVector( const IVAS_VECTOR3 refPos /* i : Reference position */ ); +#ifdef EXTERNAL_ORIENTATIONS +ivas_error IVAS_REND_SetExternalOrientation( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_QUATERNION *orientation, /* i : external orientation data */ + int8_t *enableHeadRotation, /* i : flag to enable head rotation for this frame */ + int8_t *enableExternalOrientation, /* i : flag to enable external orientation for this frame */ + int8_t *enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ + int16_t *numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +); + +ivas_error IVAS_REND_CombineHeadAndExternalOrientation( + IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */ +); + +ivas_error IVAS_REND_GetCombinedOrientation( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_QUATERNION *pRotation /* i/o: Quaternion pointer processed orientation */ +); +#endif + ivas_error IVAS_REND_GetSamples( IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ diff --git a/lib_util/head_rotation_file_reader.c b/lib_util/head_rotation_file_reader.c index 0283c292334daec7e88a2ffa6f54eb790f455257..3fd6e4f4395bbe1ebdac6d97c8d33570f82729d6 100644 --- a/lib_util/head_rotation_file_reader.c +++ b/lib_util/head_rotation_file_reader.c @@ -36,6 +36,8 @@ #include #include "prot.h" +#ifndef EXTERNAL_ORIENTATIONS + struct HeadRotFileReader { FILE *trajFile; @@ -175,3 +177,5 @@ const char *HeadRotationFileReader_getFilePath( return headRotReader->file_path; } + +#endif /* EXTERNAL_ORIENTATIONS */ diff --git a/lib_util/head_rotation_file_reader.h b/lib_util/head_rotation_file_reader.h index 52b97ae1c3db0417fb308b47b484bb0b11feea61..3c82f06403d25a5d5382e96261d832ec310328ff 100644 --- a/lib_util/head_rotation_file_reader.h +++ b/lib_util/head_rotation_file_reader.h @@ -35,6 +35,7 @@ #include "common_api_types.h" +#ifndef EXTERNAL_ORIENTATIONS #define IVAS_MAX_PARAM_SPATIAL_SUBFRAMES 4 @@ -84,4 +85,5 @@ const char *HeadRotationFileReader_getFilePath( ); +#endif /* EXTERNAL_ORIENTATIONS */ #endif /* IVAS_HR_FILE_READER_H */ diff --git a/lib_util/rotation_file_reader.c b/lib_util/rotation_file_reader.c new file mode 100644 index 0000000000000000000000000000000000000000..42bd6a3ed5910dc9f2671aff8d6d260211ea6406 --- /dev/null +++ b/lib_util/rotation_file_reader.c @@ -0,0 +1,235 @@ +/****************************************************************************************************** + + (C) 2022-2023 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 "rotation_file_reader.h" +#include +#include +#include +#include "prot.h" + +#ifdef EXTERNAL_ORIENTATIONS + +struct RotFileReader +{ + FILE *trajFile; + int32_t frameCounter; + char *file_path; + bool fileRewind; +}; + + +/*-----------------------------------------------------------------------* + * RotationFileReader_open() + * + * Allocate and initialize rotation reader + *-----------------------------------------------------------------------*/ + +ivas_error RotationFileReader_open( + char *trajFilePath, /* i : rotation trajectory file name */ + RotFileReader **rotReader /* o : RotFileReader handle */ +) +{ + RotFileReader *self; + FILE *trajFile; + + /* Open trajectory file */ + if ( strlen( trajFilePath ) < 1 ) + { + return IVAS_ERR_FAILED_FILE_OPEN; + } + + trajFile = fopen( trajFilePath, "r" ); + + if ( !trajFile ) + { + return IVAS_ERR_FAILED_FILE_OPEN; + } + + self = calloc( sizeof( RotFileReader ), 1 ); + self->trajFile = trajFile; + self->frameCounter = 0; + self->file_path = calloc( sizeof( char ), strlen( trajFilePath ) + 1 ); + strcpy( self->file_path, trajFilePath ); + self->fileRewind = false; + + *rotReader = self; + + return IVAS_ERR_OK; +} + + +/*-----------------------------------------------------------------------* + * HeadRotationFileReading() + * + * Read values from the trajectory file + *-----------------------------------------------------------------------*/ + +ivas_error HeadRotationFileReading( + RotFileReader *headRotReader, /* i/o: HeadRotFileReader handle */ + IVAS_QUATERNION *pQuaternion, /* o : head-tracking data */ + IVAS_VECTOR3 *pPos /* o : listener position */ +) +{ + float w, x, y, z; + float posx, posy, posz; + int32_t read_values; + + posx = 0.0f; + posy = 0.0f; + posz = 0.0f; + + read_values = fscanf( headRotReader->trajFile, "%f,%f,%f,%f,%f,%f,%f", &w, &x, &y, &z, &posx, &posy, &posz ); + if ( ( read_values != 4 ) && ( read_values != 7 ) ) /* Allow either orientation (4) or orientation+position (4+3) */ + { + if ( feof( headRotReader->trajFile ) ) + { + rewind( headRotReader->trajFile ); + headRotReader->fileRewind = true; + return HeadRotationFileReading( headRotReader, pQuaternion, pPos ); + } + return IVAS_ERR_FAILED_FILE_PARSE; + } + + ( headRotReader->frameCounter )++; + + pQuaternion->w = w; + pQuaternion->x = x; + pQuaternion->y = y; + pQuaternion->z = z; + if ( pPos != NULL ) + { + pPos->x = posx; + pPos->y = posy; + pPos->z = posz; + } + + return IVAS_ERR_OK; +} + +/*-----------------------------------------------------------------------* + * ExternalOrientationFileReading() + * + * Read values from the trajectory file + *-----------------------------------------------------------------------*/ + +ivas_error ExternalOrientationFileReading( + RotFileReader *externalOrientationReader, /* i/o: ExternalOrientationReader handle */ + IVAS_QUATERNION *pQuaternion, /* o : external orientation data */ + int8_t *enableHeadRotation, /* o : flag to enable head rotation for this frame */ + int8_t *enableExternalOrientation, /* o : flag to enable external orientation for this frame */ + int8_t *enableRotationInterpolation, /* o : flag to enable interpolation between the current and target orientations */ + int16_t *numFramesToTargetOrientation /* o : number of frames until target orientation is reached */ +) +{ + float w, x, y, z; + float headRotFlag; + float extOrientationFlag; + float rotInterpolationFlag; + float nFramesToTarget; + int32_t read_values; + + /* Initial values, if they are not read from the file */ + headRotFlag = 1; + extOrientationFlag = 1; + rotInterpolationFlag = 0; + nFramesToTarget = 0; + + read_values = fscanf( externalOrientationReader->trajFile, "%f,%f,%f,%f,%f,%f,%f,%f", &w, &x, &y, &z, &headRotFlag, &extOrientationFlag, &rotInterpolationFlag, &nFramesToTarget ); + if ( ( read_values != 4 ) && ( read_values != 5 ) && ( read_values != 6 ) && ( read_values != 7 ) && ( read_values != 8 ) ) /* Allow either orientation (4) OR orientation + headRotationFlag (5) OR orientation + headRotationFlag + extOrientationFlag (6) OR orientation + headRotationFlag + extOrientationFlag + rotInterpolationFlag (7) OR orientation + headRotationFlag + extOrientationFlag + rotInterpolationFlag + number of frames to target (8) */ + { + if ( feof( externalOrientationReader->trajFile ) ) + { + rewind( externalOrientationReader->trajFile ); + externalOrientationReader->fileRewind = true; + return ExternalOrientationFileReading( externalOrientationReader, pQuaternion, enableHeadRotation, enableExternalOrientation, enableRotationInterpolation, numFramesToTargetOrientation ); + } + return IVAS_ERR_FAILED_FILE_PARSE; + } + + ( externalOrientationReader->frameCounter )++; + + pQuaternion->w = w; + pQuaternion->x = x; + pQuaternion->y = y; + pQuaternion->z = z; + *enableHeadRotation = (int8_t) headRotFlag; + *enableExternalOrientation = (int8_t) extOrientationFlag; + *enableRotationInterpolation = (int8_t) rotInterpolationFlag; + *numFramesToTargetOrientation = (int16_t) nFramesToTarget; + + return IVAS_ERR_OK; +} + + +/*-----------------------------------------------------------------------* + * RotationFileReader_close() + * + * Deallocates memory for the rotation reader + *-----------------------------------------------------------------------*/ + +void RotationFileReader_close( + RotFileReader **rotReader /* i/o: RotFileReader handle */ +) +{ + if ( rotReader == NULL || *rotReader == NULL ) + { + return; + } + + fclose( ( *rotReader )->trajFile ); + free( ( *rotReader )->file_path ); + free( *rotReader ); + *rotReader = NULL; + + return; +} + + +/*-----------------------------------------------------------------------* + * HeadRotationFileReader_getFilePath() + * + * + *-----------------------------------------------------------------------*/ + +const char *RotationFileReader_getFilePath( + RotFileReader *rotReader /* i/o: RotFileReader handle */ +) +{ + if ( rotReader == NULL ) + { + return NULL; + } + + return rotReader->file_path; +} + +#endif /* EXTERNAL_ORIENTATIONS */ diff --git a/lib_util/rotation_file_reader.h b/lib_util/rotation_file_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..5f32f4ca0974c4caf4f40e524bde71b2faf59cd2 --- /dev/null +++ b/lib_util/rotation_file_reader.h @@ -0,0 +1,104 @@ +/****************************************************************************************************** + + (C) 2022-2023 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. + +*******************************************************************************************************/ + +#ifndef IVAS_ROTATION_FILE_READER_H +#define IVAS_ROTATION_FILE_READER_H + +#include "common_api_types.h" + +#ifdef EXTERNAL_ORIENTATIONS + +#define IVAS_MAX_PARAM_SPATIAL_SUBFRAMES 4 + +typedef struct RotFileReader RotFileReader; + +/*-----------------------------------------------------------------------* + * RotationFileReader_open() + * + * Allocate and initialize rotation handle + *-----------------------------------------------------------------------*/ + +ivas_error RotationFileReader_open( + char *trajFilePath, /* i : rotation trajectory file name */ + RotFileReader **rotReader /* o : RotFileReader handle */ +); + +/*-----------------------------------------------------------------------* + * RotationFileReading() + * + * Read values from the trajectory file + *-----------------------------------------------------------------------*/ + +ivas_error HeadRotationFileReading( + RotFileReader *headRotReader, /* i/o: RotFileReader handle */ + IVAS_QUATERNION *pQuaternion, /* o : head-tracking data */ + IVAS_VECTOR3 *pPos /* o : listener position */ +); + +/*-----------------------------------------------------------------------* + * ExternalOrientationFileReading() + * + * Read values from the trajectory file + *-----------------------------------------------------------------------*/ + +ivas_error ExternalOrientationFileReading( + RotFileReader *externalOrientationReader, /* i/o: RotFileReader handle */ + IVAS_QUATERNION *pQuaternion, /* o : external orientation data */ + int8_t *enableHeadRotation, /* o : flag to enable head rotation for this frame */ + int8_t *enableExternalOrientation, /* o : flag to enable external orientation for this frame */ + int8_t *enableRotationInterpolation, /* o : flag to enable interpolation between the current and target orientations */ + int16_t *numFramesToTargetOrientation /* o : number of frames until target orientation is achieved */ +); + +/*-----------------------------------------------------------------------* + * RotationFileReader_close() + * + * Deallocates memory for the rotation handle + *-----------------------------------------------------------------------*/ + +void RotationFileReader_close( + RotFileReader **rotReader /* i/o: RotFileReader handle */ +); + +/*-----------------------------------------------------------------------* + * RotationFileReader_getFilePath() + * + * + *-----------------------------------------------------------------------*/ + +const char *RotationFileReader_getFilePath( + RotFileReader *rotReader /* i/o: RotFileReader handle */ +); + + +#endif /* EXTERNAL_ORIENTATIONS */ +#endif /* IVAS_ROTATION_FILE_READER_H */