diff --git a/Workspace_msvc/lib_com.vcxproj b/Workspace_msvc/lib_com.vcxproj index 223f837a2e1685afeedb952a5137dab7b902b3a6..c28b36a1454bdb9bd3245a0ce9050d258602a13a 100644 --- a/Workspace_msvc/lib_com.vcxproj +++ b/Workspace_msvc/lib_com.vcxproj @@ -223,7 +223,7 @@ - + diff --git a/Workspace_msvc/lib_lc3plus.vcxproj b/Workspace_msvc/lib_lc3plus.vcxproj index 55a291fa9c768769f213dac4423688e2db81f8e3..3f1527357ad6c96d8629a85f7ab3937e82fb3bb0 100644 --- a/Workspace_msvc/lib_lc3plus.vcxproj +++ b/Workspace_msvc/lib_lc3plus.vcxproj @@ -106,7 +106,6 @@ - @@ -116,13 +115,13 @@ - - + + - + @@ -133,35 +132,36 @@ + - - - + + + + - - - + + + - @@ -169,14 +169,12 @@ - - - - + + + + - - diff --git a/Workspace_msvc/lib_rend.vcxproj b/Workspace_msvc/lib_rend.vcxproj index 27d4a19a693cf86f60b3ce654912c65b4a7cbaa6..854c99a979e4ae274d9c002b2ca6686a96e75870 100644 --- a/Workspace_msvc/lib_rend.vcxproj +++ b/Workspace_msvc/lib_rend.vcxproj @@ -175,6 +175,7 @@ + diff --git a/Workspace_msvc/lib_rend.vcxproj.filters b/Workspace_msvc/lib_rend.vcxproj.filters index 942c63712f66e57821488868f81981d3042c56b0..2d1d7d46c0b86e517f6f5a9a35d3c5a985a4caac 100644 --- a/Workspace_msvc/lib_rend.vcxproj.filters +++ b/Workspace_msvc/lib_rend.vcxproj.filters @@ -32,30 +32,12 @@ rend_c - - rend_c - - - rend_c - - - rend_c - - - rend_c - rend_c rend_c - - rend_c - - - rend_c - rend_c @@ -83,15 +65,6 @@ rend_c - - rend_c - - - rend_c - - - rend_c - rend_c @@ -113,9 +86,6 @@ rend_c - - rend_c - rend_c @@ -134,24 +104,6 @@ rend_c - - rend_c - - - rend_c - - - rend_c - - - rend_c - - - rend_c - - - rend_c - rend_c @@ -161,30 +113,15 @@ rend_c - - rend_c - - - rend_c - - + rend_c - + rend_c - - rend_h - - - rend_h - - - rend_h - rend_h @@ -203,12 +140,6 @@ rend_h - - rend_h - - - rend_h - diff --git a/apps/decoder.c b/apps/decoder.c index 71379c6575451f68f2ee8c76a656db9f46fcd232..4a28b4470b7c26a1673b05209a6c3d834a0882df 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -1617,6 +1617,18 @@ static bool parseCmdlIVAS_dec( return false; } +#ifdef SUPPORT_JBM_TRACEFILE + /* Validate options that depend on other options */ + if ( arg->jbmTraceFilename != NULL && arg->delayCompensationEnabled + /* This decMode check should be removed once timestamp sync issues between JBM trace and audio are fixed in EVS */ + && arg->decMode != IVAS_DEC_MODE_EVS ) + { + fprintf( stderr, "Error: Writing to a JBM trace file requires delay compensation to be disabled with -no_delay_cmp\n\n" ); + usage_dec(); + return false; + } +#endif + return true; } @@ -1653,7 +1665,8 @@ static void usage_dec( void ) fprintf( stdout, " EVS RTP Payload Format. The SDP parameter hf_only is required.\n" ); fprintf( stdout, " Reading RFC4867 AMR/AMR-WB RTP payload format is not supported.\n" ); #ifdef SUPPORT_JBM_TRACEFILE - fprintf( stdout, "-Tracefile TF : VoIP mode: Generate trace file named TF\n" ); + fprintf( stdout, "-Tracefile TF : VoIP mode: Generate trace file named TF. Requires -no_delay_cmp to\n" ); + fprintf( stdout, " be enabled so that trace contents remain in sync with audio output.\n" ); #endif #ifdef DEBUGGING #ifdef VARIABLE_SPEED_DECODING diff --git a/apps/renderer.c b/apps/renderer.c index 8e44fd6cc19cf316afea7a5563e67c357acdf3d6..26c4b349d2b8e436a01db2d5d3dda8a9f86f0d31 100644 --- a/apps/renderer.c +++ b/apps/renderer.c @@ -68,6 +68,8 @@ #define IVAS_MAX16B_FLT 32767.0f #define IVAS_MIN16B_FLT ( -32768.0f ) +#define OMASA_TDREND_MATCHING_GAIN_DB ( -2.0f ) + #if !defined( DEBUGGING ) && !defined( WMOPS ) static #endif @@ -562,12 +564,19 @@ static void setupWithSingleFormatInput( positionProvider->numObjects = args.inConfig.numAudioObjects; for ( int16_t i = 0; i < positionProvider->numObjects; ++i ) { - /* It is allowed on CLI to have no metadata for an ISM input - skip opening if string is empty or contains "NULL" */ + /* Check if path to metadata file was given */ + if ( isEmptyString( args.inMetadataFilePaths[i] ) ) + { + fprintf( stderr, "No metadata file was given for ISM input %d\n", i ); + exit( -1 ); + } + + /* It is allowed on CLI to have no metadata for an ISM input - skip opening if string contains "NULL" */ char charBuf[FILENAME_MAX]; strncpy( charBuf, args.inMetadataFilePaths[i], min( FILENAME_MAX, RENDERER_MAX_CLI_ARG_LENGTH ) - 1 ); charBuf[min( FILENAME_MAX, RENDERER_MAX_CLI_ARG_LENGTH ) - 1] = '\0'; to_upper( charBuf ); - if ( isEmptyString( args.inMetadataFilePaths[i] ) || strncmp( charBuf, "NULL", 4 ) == 0 ) + if ( strncmp( charBuf, "NULL", 4 ) == 0 ) { continue; } @@ -698,6 +707,7 @@ int main( SplitFileReadWrite *hSplitRendFileReadWrite; int16_t delayNumSamples_temp; int32_t delayTimeScale_temp; + bool flushRendererLastFrame = false; int16_t numSamplesRead; int16_t delayNumSamples = -1; int16_t delayNumSamples_orig = 0; @@ -742,8 +752,11 @@ int main( CmdlnArgs args = parseCmdlnArgs( argc, argv ); - if ( args.nonDiegeticPan && !( ( args.inConfig.numAudioObjects == 0 && args.inConfig.multiChannelBuses[0].audioConfig == IVAS_AUDIO_CONFIG_MONO ) || - ( args.inConfig.numAudioObjects > 0 && args.inConfig.audioObjects[0].audioConfig == IVAS_AUDIO_CONFIG_OBA && args.inConfig.numAudioObjects == 1 ) ) ) + if ( args.nonDiegeticPan && + !( ( args.inConfig.numAudioObjects == 0 && + args.inConfig.multiChannelBuses[0].audioConfig == IVAS_AUDIO_CONFIG_MONO ) || + ( args.inConfig.numAudioObjects > 0 && + args.inConfig.audioObjects[0].audioConfig == IVAS_AUDIO_CONFIG_OBA && args.inConfig.numAudioObjects == 1 ) ) ) { fprintf( stderr, "\ninvalid configuration - non-diegetic panning requires mono or ISM1 input\n" ); goto cleanup; @@ -1064,7 +1077,10 @@ int main( { /* sanity check */ - if ( ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL ) && ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) && ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && !is_split_pre_rend_mode( &args ) ) + if ( ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL ) && + ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) && + ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && + !is_split_pre_rend_mode( &args ) ) { fprintf( stderr, "\nExternal Renderer Config is supported only when binaural output configurations is used as output OR when Split pre-rendering mode is enabled. Exiting. \n" ); goto cleanup; @@ -1153,20 +1169,30 @@ int main( } } - /* Set the total number of objects */ if ( args.inConfig.numAudioObjects > 0 ) { + /* Set the total number of objects */ if ( ( error = IVAS_REND_SetTotalNumberOfObjects( hIvasRend, args.inConfig.numAudioObjects ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_SetTotalNumberOfObjects(): %s\n", ivas_error_to_string( error ) ); goto cleanup; } + /* Set the metadata delay for objects */ if ( ( error = IVAS_REND_SetIsmMetadataDelay( hIvasRend, args.syncMdDelay ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_SetIsmMetadataDelay(): %s\n", ivas_error_to_string( error ) ); goto cleanup; } + + /* For OMASA input and BINAURAL output, apply a gain to objects to match the loudness with MASA part */ + if ( args.inConfig.numMasaBuses > 0 && args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL ) + { + for ( i = 0; i < args.inConfig.numAudioObjects; ++i ) + { + args.inConfig.audioObjects[i].gain_dB += OMASA_TDREND_MATCHING_GAIN_DB; + } + } } IVAS_REND_LfePanMtx lfePanMatrix; @@ -1351,7 +1377,7 @@ int main( } int16_t numOutChannels; - if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_NumOutChannels(): %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1366,8 +1392,16 @@ int main( } } - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { + char *outFile = args.outMetadataFilePath; + + if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + { + outFile = args.outputFilePath; + audioWriter = NULL; + } + if ( ( error = IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms, &bitsBuffer.config.isar_frame_size_ms ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_REND_GetSplitRendBitstreamHeader()!\n" ); @@ -1380,36 +1414,15 @@ int main( goto cleanup; } - if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outputFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) + if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, outFile, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nCould not open split rend metadata file %s\n", args.outputFilePath ); + fprintf( stderr, "\nCould not open split rend metadata file %s\n", outFile ); goto cleanup; } - audioWriter = NULL; } - else - { - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) - { - if ( ( error = IVAS_REND_GetSplitRendBitstreamHeader( hIvasRend, &bitsBuffer.config.codec, &bitsBuffer.config.poseCorrection, &bitsBuffer.config.codec_frame_size_ms, &bitsBuffer.config.isar_frame_size_ms ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError in IVAS_REND_GetSplitRendBitstreamHeader()!\n" ); - goto cleanup; - } - - if ( IVAS_REND_GetDelay( hIvasRend, &delayNumSamples_temp, &delayTimeScale_temp ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nUnable to get delay of renderer!\n" ); - goto cleanup; - } - - if ( ( error = split_rend_writer_open( &hSplitRendFileReadWrite, args.outMetadataFilePath, delayNumSamples_temp, delayTimeScale_temp, bitsBuffer.config.codec, bitsBuffer.config.poseCorrection, bitsBuffer.config.codec_frame_size_ms, bitsBuffer.config.isar_frame_size_ms, args.sampleRate, bitsBuffer.config.lc3plus_highres ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nCould not open split rend metadata file %s\n", args.outMetadataFilePath ); - goto cleanup; - } - } + if ( args.outConfig.audioConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) + { if ( AudioFileWriter_open( &audioWriter, args.outputFilePath, args.sampleRate, numOutChannels ) != IVAS_ERR_OK ) { fprintf( stderr, "\nFailed to open file: %s\n", args.outputFilePath ); @@ -1535,16 +1548,23 @@ int main( if ( numSamplesRead == 0 ) { /* end of input data */ - break; + flushRendererLastFrame = true; } /* Convert from int to float and from interleaved to packed */ - convertInputBuffer( inpInt16Buffer, numSamplesRead, inBuffer.config.numSamplesPerChannel, num_in_channels, inFloatBuffer, inBuffer.config.is_cldfb, cldfbAna ); + if ( !flushRendererLastFrame ) + { + convertInputBuffer( inpInt16Buffer, numSamplesRead, inBuffer.config.numSamplesPerChannel, num_in_channels, inFloatBuffer, inBuffer.config.is_cldfb, cldfbAna ); + } + else + { + memset( inBuffer.data, 0, inBuffer.config.numChannels * inBuffer.config.numSamplesPerChannel * sizeof( float ) ); + } int16_t num_subframes, sf_idx; num_subframes = (int16_t) args.render_framesize; - if ( isCurrentFrameMultipleOf20ms ) + if ( isCurrentFrameMultipleOf20ms && !flushRendererLastFrame ) { IsmPositionProvider_getNextFrame( positionProvider, &mtdBuffer ); @@ -1656,7 +1676,7 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.multiChannelBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, mcIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, mcIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1671,7 +1691,7 @@ int main( { IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.audioObjects[i].inputChannelIndex, args.inConfig.numAudioObjects ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1688,7 +1708,7 @@ int main( { IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.audioObjects[i].inputChannelIndex, 1 ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, ismIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1711,7 +1731,7 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.ambisonicsBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, sbaIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, sbaIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; @@ -1727,13 +1747,13 @@ int main( } IVAS_REND_ReadOnlyAudioBuffer tmpBuffer = getReadOnlySubBuffer( inBuffer, (int16_t) args.inConfig.masaBuses[i].inputChannelIndex, numChannels ); - if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, masaIds[i], tmpBuffer ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_FeedInputAudio( hIvasRend, masaIds[i], tmpBuffer, flushRendererLastFrame ) ) != IVAS_ERR_OK ) { fprintf( stderr, "IVAS_REND_FeedInputAudio failed: %s\n", ivas_error_to_string( error ) ); goto cleanup; } - if ( isCurrentFrameMultipleOf20ms ) + if ( isCurrentFrameMultipleOf20ms && !flushRendererLastFrame ) { if ( masaReaders[i] != NULL ) { @@ -1796,7 +1816,7 @@ int main( zeroPad = delayNumSamples; } - if ( is_split_pre_rend_mode( &args ) ) + if ( is_split_pre_rend_mode( &args ) && !flushRendererLastFrame ) { if ( split_rend_write_bitstream_to_file( hSplitRendFileReadWrite, bitsBuffer.bits, &bitsBuffer.config.bitsRead, &bitsBuffer.config.bitsWritten ) != IVAS_ERR_OK ) @@ -1806,7 +1826,7 @@ int main( } } - if ( audioWriter != NULL ) + if ( audioWriter != NULL && !flushRendererLastFrame ) { if ( delayNumSamples * num_out_channels < outBufferSize ) { @@ -1827,7 +1847,7 @@ int main( bitsBuffer.config.bitsWritten = 0; /* Write MASA metadata for MASA outputs */ - if ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA1 || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA2 ) + if ( !flushRendererLastFrame && ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA1 || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_MASA2 ) ) { IVAS_REND_AudioConfigType inputType1; IVAS_REND_AudioConfigType inputType2; @@ -1899,7 +1919,8 @@ int main( } } - if ( ( args.inConfig.numAmbisonicsBuses > 0 || args.inConfig.numMultiChannelBuses > 0 || args.inConfig.numMasaBuses > 0 ) && args.inConfig.numAudioObjects > 0 ) + if ( ( args.inConfig.numAmbisonicsBuses > 0 || args.inConfig.numMultiChannelBuses > 0 || args.inConfig.numMasaBuses > 0 ) && + args.inConfig.numAudioObjects > 0 ) { inputType2 = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED; if ( ( error = IVAS_REND_MergeMasaMetadata( hIvasRend, &hMetaOutput, inputType1, inputType2 ) ) != IVAS_ERR_OK ) @@ -1916,6 +1937,13 @@ int main( } } + /* no new input was actually read, only delay buffers were flushed + * therefore this is not a real frame */ + if ( flushRendererLastFrame ) + { + break; + } + frame++; if ( !args.quietModeEnabled ) { @@ -1928,12 +1956,13 @@ int main( #endif } - /* add zeros at the end to have equal length of synthesized signals */ + /* add zeros at the end to have equal length of synthesized signals + * the output buffer will contain either leftover input samples from delay aligned inputs + * or zeros for padding */ if ( audioWriter != NULL ) { for ( zeroPadToWrite = zeroPad; zeroPadToWrite > frameSize_smpls; zeroPadToWrite -= frameSize_smpls ) { - memset( outInt16Buffer, 0, outBufferSize * sizeof( int16_t ) ); if ( ( error = AudioFileWriter_write( audioWriter, outInt16Buffer, outBufferSize ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nOutput audio file writer error\n" ); @@ -1941,7 +1970,6 @@ int main( } } - memset( outInt16Buffer, 0, zeroPadToWrite * outBuffer.config.numChannels * sizeof( int16_t ) ); if ( ( error = AudioFileWriter_write( audioWriter, outInt16Buffer, zeroPadToWrite * outBuffer.config.numChannels ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nOutput audio file writer error\n" ); @@ -1950,9 +1978,10 @@ int main( zeroPadToWrite = 0; } - if ( args.inConfig.numAudioObjects != 0 && ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) + if ( args.inConfig.numAudioObjects != 0 && + ( args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL || args.outConfig.audioConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) { - fprintf( stdout, "\n\nMetadata delayed %d subframes\n\n", (int16_t) round( args.syncMdDelay / ( 1000 / IVAS_NUM_FRAMES_PER_SEC / IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ) ) ); + fprintf( stdout, "\n\nMetadata delayed %d subframes\n\n", (int16_t) round( args.syncMdDelay / ( 1000.f / IVAS_NUM_FRAMES_PER_SEC / IVAS_MAX_PARAM_SPATIAL_SUBFRAMES ) ) ); } if ( !args.quietModeEnabled && args.delayCompensationEnabled ) @@ -2555,6 +2584,7 @@ static CmdlnArgs defaultArgs( const char *executableName ) { CmdlnArgs args; + int16_t i; strncpy( args.executableName, executableName, RENDERER_MAX_CLI_ARG_LENGTH ); clearString( args.inputFilePath ); @@ -2573,7 +2603,7 @@ static CmdlnArgs defaultArgs( args.outConfig.outSetupCustom.num_lfe = 0; args.inConfig.ambisonicsBuses->audioConfig = IVAS_AUDIO_CONFIG_INVALID; - for ( int32_t i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) + for ( i = 0; i < RENDERER_MAX_ISM_INPUTS + RENDERER_MAX_MASA_INPUTS; ++i ) { clearString( args.inMetadataFilePaths[i] ); } @@ -2610,7 +2640,7 @@ static CmdlnArgs defaultArgs( args.render_framesize = IVAS_RENDER_FRAMESIZE_20MS; args.syncMdDelay = 0; - for ( int32_t i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) + for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) { args.directivityPatternId[i] = 65535; } @@ -3282,7 +3312,8 @@ static void parseObjectPosition( *positionDuration = (uint16_t) strtol( line, &endptr, 10 ); readNextMetadataChunk( line, "\n" ); - read_values = (int16_t) sscanf( line, "%f,%f,%f,%f,%f,%f,%f,%f", &meta_prm[0], &meta_prm[1], &meta_prm[2], &meta_prm[3], &meta_prm[4], &meta_prm[5], &meta_prm[6], &meta_prm[7] ); + read_values = (int16_t) sscanf( line, "%f,%f,%f,%f,%f,%f,%f,%f", + &meta_prm[0], &meta_prm[1], &meta_prm[2], &meta_prm[3], &meta_prm[4], &meta_prm[5], &meta_prm[6], &meta_prm[7] ); if ( read_values < 2 ) { @@ -3491,20 +3522,8 @@ static void parseCombinedFormatInput( inConfig->numAmbisonicsBuses = 1; inConfig->ambisonicsBuses[0].audioConfig = audioConfig; inConfig->ambisonicsBuses[0].inputChannelIndex = inConfig->numAudioObjects; -#ifdef NONBE_1352_HARMONIZE_OSBA_LOUDNESS inConfig->ambisonicsBuses[0].gain_dB = 0.f; -#else - inConfig->ambisonicsBuses[0].gain_dB = -6.f; -#endif *configString += 4; - -#ifndef NONBE_1352_HARMONIZE_OSBA_LOUDNESS - /* Modify input gain for objects too */ - for ( int16_t i = 0; i < inConfig->numAudioObjects; ++i ) - { - inConfig->audioObjects[i].gain_dB = -6.f; - } -#endif } else if ( audioConfig == IVAS_AUDIO_CONFIG_MASA1 || audioConfig == IVAS_AUDIO_CONFIG_MASA2 ) { diff --git a/ci/basop-pages/basop_index.html b/ci/basop-pages/basop_index.html index bfa01eed801cf69167e8db6317c176cb87ab74fd..3183acd4deef26072fcacc17a017b95da8f4a4e5 100644 --- a/ci/basop-pages/basop_index.html +++ b/ci/basop-pages/basop_index.html @@ -29,8 +29,7 @@

Test Coverage

diff --git a/ci/remove_unsupported_testcases.py b/ci/remove_unsupported_testcases.py index 66b62b04ef34c216f1ef84c269450af79c39b83d..3d483deca7b21c01d6ef88376c835a60b274dcb0 100644 --- a/ci/remove_unsupported_testcases.py +++ b/ci/remove_unsupported_testcases.py @@ -55,6 +55,7 @@ TESTCASES = [ "OSBA 3OA 4ISM at 256 kbps, 48kHz in, 48kHz out, BINAURAL out, object editing, DISC", "OSBA 2OA 3ISM at 128 kbps, 48kHz in, 48kHz out, FOA out, object editing, JBM Prof 5, DISC", "OSBA 2OA 3ISM at bitrate switching 13.2 to 512 kbps, 48kHz in, 48kHz out, BINAURAL out, object editing", + "OSBA 3OA 4ISM at 256 kbps, 48kHz in, 48kHz out, BINAURAL_ROOM_IR out, object editing, DISC", # self_test_ltv.prm "OMASA 2TC 4ISM at br sw techs 13.2 to 512 kbps start 80 kbps, 48kHz in, 48kHz out, EXT out", "OMASA 2TC 2ISM at 96 kbps, 48kHz in, 48kHz out, FOA out, object editing, JBM Prof 5, DISC", diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index a2f893ed78edd4d5055503e9eb720de1a8d323f4..563b10e39112c34c9c5093d1d50bde1242ca558a 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -134,6 +134,7 @@ typedef enum IVAS_ERR_BITSTREAM_READER_INVALID_FORMAT, IVAS_ERR_NO_FILE_OPEN, IVAS_ERR_SAMPLING_RATE_UNKNOWN, + IVAS_ERR_EXTERNAL_ORIENTATION_INVALID_FORMAT, /*----------------------------------------* * renderer (lib_rend only) * @@ -271,6 +272,8 @@ static inline const char *ivas_error_to_string( ivas_error error_code ) return "Invalid input format"; case IVAS_ERR_INVALID_INDEX: return "Invalid index"; + case IVAS_ERR_EXTERNAL_ORIENTATION_INVALID_FORMAT: + return "Euler angles were detected in the input but only Quaternions are supported"; default: break; } diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 8121030b1cc0ab67501bcbcfef1eb162098942ac..895cb3ac07a1680669d4de9edae8509c1548e7e4 100755 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -308,8 +308,9 @@ ivas_error ivas_init_decoder( ivas_error ivas_output_buff_dec( float *p_output_f[], /* i/o: output audio buffers */ - const int16_t nchan_out_buff_old, /* i : previous frame number of output channels*/ - const int16_t nchan_out_buff /* i : number of output channels */ + const int16_t nchan_out_buff, /* i : number of output channels */ + const int16_t Opt_tsm, /* i : TSM option flag */ + DECODER_TC_BUFFER_HANDLE hTcBuffer /* i : TSM buffer handle */ ); ivas_error stereo_dmx_evs_init_encoder( @@ -5823,8 +5824,7 @@ void ivas_omasa_separate_object_render_jbm( const uint16_t nSamplesRendered, /* i : number of samples rendered */ float input_f[][L_FRAME48k], /* i : separated object signal */ float *output_f[], /* o : rendered time signal */ - const int16_t subframes_rendered, /* i : number of subframes rendered */ - const int16_t slots_rendered /* i : number of CLDFB slots rendered */ + const int16_t subframes_rendered /* i : number of subframes rendered */ ); void ivas_omasa_encode_masa_to_total( diff --git a/lib_com/ivas_tools.c b/lib_com/ivas_tools.c index baa98da6b747e44db3de6083e908ad65c5c7f26f..e7ada0a3432364b499f974d3625af3546d294af6 100644 --- a/lib_com/ivas_tools.c +++ b/lib_com/ivas_tools.c @@ -198,12 +198,18 @@ void ivas_buffer_deinterleaved_to_interleaved( ) { int16_t ch, m; + float buffer[MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS][L_FRAME48k]; /* temp buffer needed when "*audio[]" and "*audio_out[]" are the same */ + + for ( ch = 0; ch < n_channels; ch++ ) + { + mvr2r( audio[ch], buffer[ch], frame_length ); + } for ( ch = 0; ch < n_channels; ch++ ) { for ( m = 0; m < frame_length; m++ ) { - audio_out[m * n_channels + ch] = audio[ch][m]; + audio_out[m * n_channels + ch] = buffer[ch][m]; } } diff --git a/lib_com/options.h b/lib_com/options.h index edd60e4680f719806fef9ec40b0e5f974fa712d7..ee846da36c4aa5ed7a073d09e3096bf3e48aba1c 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -136,6 +136,7 @@ /*#define DEBUG_JBM_CMD_OPTION*/ /* ability for telling the decoder the frontend fetch size and to not delay compensate for bad frames at the beginning */ /*#define VARIABLE_SPEED_DECODING*/ /* variable speed decoding employing the JBM functioniality; move to DEBUGGING after build for disabled is fixed */ /*#define DISABLE_LIMITER*/ /* disable the limiter */ +/*#define DEBUG_APA_SILENCE_NON_SCALED*/ /* Switch APA into mode that replaces contents of non-scaled frames with silence. Useful for identifying scaled regions in the audio output of the decoder */ /*Split Rendering Debug switches*/ /*#define DBG_WAV_WRITER*/ /* add debugging function dbgwrite_wav() */ @@ -162,7 +163,8 @@ /*#define FIX_I4_OL_PITCH*/ /* fix open-loop pitch used for EVS core switching */ #define TMP_FIX_1119_SPLIT_RENDERING_VOIP /* FhG: Add error check for unsupported config: split rendering with VoIP mode */ -/*#define CODE_IMPROVEMENTS*/ /* FhG: Small code improvements that do not change the functionality */ +#define FIX_1995_REVERB_INIT /* issue 1995: Fix use-of-uninitialized-value in ivas_binaural_reverb_init() */ +#define FIX_1372_OSBA_OBJECT_EDITING /* VA: issue 1372: Fix OSBA object-editing in BINAURAL_ROOM_IR */ /* #################### End BE switches ################################## */ @@ -173,9 +175,10 @@ #define NONBE_1244_FIX_SWB_BWE_MEMORY /* VA: issue 1244: fix to SWB BWE memory in case of switching from FB coding - pending a review by Huawei */ #define NONBE_1122_KEEP_EVS_MODE_UNCHANGED /* FhG: Disables fix for issue 1122 in EVS mode to keep BE tests green. This switch should be removed once the 1122 fix is added to EVS via a CR. */ -#define NONBE_FIX_TCX5_INTERLEAVING_FOR_FS_IN_UNEQUAL_FS_OUT /* FhG: apply correct TCX5 grouping/interleaving when input_fs != output_fs */ -#define NONBE_1339_FIXOSBA_EXT_LOUDNESS /* FhG: issue 1339: apply scaling with EXT output in OSBA high-BR mode */ -#define NONBE_1352_HARMONIZE_OSBA_LOUDNESS /* FhG: do not scale OSBA inputs by 0.5 any more */ +#define NONBE_1328_FIX_NON_LINEARITY /* VA: Fix possible issue when computing bwe_exc_extended and previous frame were almost 0 */ +#define NONBE_1321_JBM_ASSERT_BITRATE_SWITCHING /* FhG: Fix assert being hit in JBM code during rate switching */ +#define NONBE_FIX_1376_MDCT_CONCEALMENT /* FhG: fix concealment artifact in MDCT Stereo with DTX, in case transition frame gets lost */ +#define NONBE_1377_REND_DIRATT_CONF /* Eri: Issue 1377: Error in directivity attenuation configuration for both IVAS_dec and IVAS_rend */ /* ##################### End NON-BE switches ########################### */ diff --git a/lib_com/prot.h b/lib_com/prot.h index c1dd64527d4f837abebd075615dac52be7be50b6..efb77f0a3f8067eae9f448e8a7c78e2ec5782e92 100644 --- a/lib_com/prot.h +++ b/lib_com/prot.h @@ -2653,6 +2653,10 @@ void non_linearity( const int16_t coder_type, /* i : Coder Type */ const float *voice_factors, /* i : Voice Factors */ const int16_t L_frame /* i : ACELP frame length */ +#ifdef NONBE_1328_FIX_NON_LINEARITY + , + const int16_t element_mode /* i : element_mode to differentiate EVS and IVAS */ +#endif ); void interp_code_5over2( diff --git a/lib_com/swb_tbe_com.c b/lib_com/swb_tbe_com.c index a8d88c2b0fb5f5bb0386c946d3d18e2a7f3b5f3c..ed06e57636c1bb4fa0f19df5422c1125585b5edb 100644 --- a/lib_com/swb_tbe_com.c +++ b/lib_com/swb_tbe_com.c @@ -1353,6 +1353,10 @@ void non_linearity( const int16_t coder_type, /* i : Coder Type */ const float *voice_factors, /* i : Voice Factors */ const int16_t L_frame /* i : ACELP frame length */ +#ifdef NONBE_1328_FIX_NON_LINEARITY + , + const int16_t element_mode /* i : element_mode to differentiate EVS and IVAS */ +#endif ) { int16_t i, j; @@ -1365,7 +1369,9 @@ void non_linearity( int16_t en_abs = 0; float v_fac = 0, ths; int16_t nframes; - +#ifdef NONBE_1328_FIX_NON_LINEARITY + float sc_factor; +#endif if ( L_frame == L_FRAME16k ) { nframes = 5; @@ -1410,8 +1416,17 @@ void non_linearity( scale = 0.67f; } - +#ifdef NONBE_1328_FIX_NON_LINEARITY + sc_factor = 1024.0f; + if ( element_mode > EVS_MONO ) + { + sc_factor = (float) ( 1 << max( 13 - norm_s( j + 1 ), 0 ) ); /* Adapt the scaling factor allowed depending of max position */ + sc_factor = max( sc_factor, 2.0f ); + } + if ( *prev_scale <= 0.0 || *prev_scale > sc_factor * scale ) +#else if ( *prev_scale <= 0.0 || *prev_scale > 1024.0f * scale ) +#endif { scale_step = 1.0; *prev_scale = scale; @@ -1468,8 +1483,17 @@ void non_linearity( scale = 0.67f; } - +#ifdef NONBE_1328_FIX_NON_LINEARITY + sc_factor = 1024.0f; + if ( element_mode > EVS_MONO ) + { + sc_factor = (float) ( 1 << max( 12 - norm_s( j - length / 2 + 1 ), 0 ) ); /* allowed intra frame jump is smaller */ + sc_factor = max( sc_factor, 2.0f ); + } + if ( *prev_scale <= 0.0 || *prev_scale > sc_factor * scale ) +#else if ( *prev_scale <= 0.0 || *prev_scale > 1024.0f * scale ) +#endif { scale_step = 1.0; *prev_scale = scale; diff --git a/lib_com/tools.c b/lib_com/tools.c index cb1d1216294bbc815b258866a51a99d99d822298..6dca2331ff73320a615f120e5a1cea687704ab9f 100644 --- a/lib_com/tools.c +++ b/lib_com/tools.c @@ -1742,25 +1742,11 @@ double anint( int16_t is_numeric_float( float x ) { -#ifdef CODE_IMPROVEMENTS + int16_t retval; #define WMC_TOOL_SKIP - return (int16_t) ( !isnan( x ) && !isinf( x ) ); + retval = (int16_t) ( !isnan( x ) && !isinf( x ) ); #undef WMC_TOOL_SKIP -#else -#ifndef BASOP_NOGLOB - union float_int -#else /* BASOP_NOGLOB */ - union float_int -#endif /* BASOP_NOGLOB */ - { - float float_val; - int32_t int_val; - } float_int; - - float_int.float_val = x; - - return ( ( float_int.int_val & 0x7f800000 ) != 0x7f800000 ); -#endif + return retval; } /*-------------------------------------------------------------------* diff --git a/lib_dec/acelp_core_dec.c b/lib_dec/acelp_core_dec.c index 8e3a5cff68807a4b5cf4fd71f44a74d75629f54d..d488d4479efb0225490c17226df1ef6c3e79afa9 100644 --- a/lib_dec/acelp_core_dec.c +++ b/lib_dec/acelp_core_dec.c @@ -1414,7 +1414,12 @@ ivas_error acelp_core_dec( if ( !st->ppp_mode_dec && ( st->idchan == 0 || st->element_mode != IVAS_CPE_TD || ( st->idchan == 1 && st->element_mode == IVAS_CPE_TD && st->tdm_LRTD_flag ) ) ) { - non_linearity( bwe_exc, bwe_exc_extended, st->hBWE_TD->old_bwe_exc_extended, L_FRAME32k, &st->hBWE_TD->bwe_non_lin_prev_scale, st->coder_type, voice_factors, st->L_frame ); + non_linearity( bwe_exc, bwe_exc_extended, st->hBWE_TD->old_bwe_exc_extended, L_FRAME32k, &st->hBWE_TD->bwe_non_lin_prev_scale, st->coder_type, voice_factors, st->L_frame +#ifdef NONBE_1328_FIX_NON_LINEARITY + , + st->element_mode +#endif + ); } if ( st->core_brate == FRAME_NO_DATA || st->core_brate == SID_2k40 ) diff --git a/lib_dec/dec_acelp_tcx_main.c b/lib_dec/dec_acelp_tcx_main.c index 4689bdb7950e4df3c69452c5a114fc57a5070053..a591157e44e72a87adab547256f7e80b5326acca 100644 --- a/lib_dec/dec_acelp_tcx_main.c +++ b/lib_dec/dec_acelp_tcx_main.c @@ -425,7 +425,12 @@ void dec_acelp_tcx_frame( if ( st->core == ACELP_CORE && st->igf && st->con_tcx == 0 ) { - non_linearity( ptr_bwe_exc, bwe_exc_extended, st->hBWE_TD->old_bwe_exc_extended, L_FRAME32k, &st->hBWE_TD->bwe_non_lin_prev_scale, st->coder_type, voice_factors, st->L_frame ); + non_linearity( ptr_bwe_exc, bwe_exc_extended, st->hBWE_TD->old_bwe_exc_extended, L_FRAME32k, &st->hBWE_TD->bwe_non_lin_prev_scale, st->coder_type, voice_factors, st->L_frame +#ifdef NONBE_1328_FIX_NON_LINEARITY + , + st->element_mode +#endif + ); /* update the old BWE exe memory */ mvr2r( &old_bwe_exc[L_FRAME32k], st->hBWE_TD->old_bwe_exc, PIT16k_MAX * 2 ); diff --git a/lib_dec/dec_tcx.c b/lib_dec/dec_tcx.c index 0fb28ddb2d27b73558c6944576de9c1cf9112bee..23dd28556d66ffad608b8405ffabbd27ca3d4bb3 100644 --- a/lib_dec/dec_tcx.c +++ b/lib_dec/dec_tcx.c @@ -1506,11 +1506,7 @@ void decoder_tcx_tns( hTcxCfg->tcx_last_overlap_mode = hTcxCfg->tcx_curr_overlap_mode; } -#ifdef NONBE_FIX_TCX5_INTERLEAVING_FOR_FS_IN_UNEQUAL_FS_OUT if ( ( hTcxCfg->fIsTNSAllowed && fUseTns != 0 && bfi != 1 && whitenedDomain ) || ( L_spec > L_frameTCX ) ) -#else - if ( ( hTcxCfg->fIsTNSAllowed && fUseTns != 0 && bfi != 1 ) || ( L_spec > L_frameTCX ) ) -#endif { L = L_spec; } @@ -1552,11 +1548,7 @@ void decoder_tcx_tns( if ( ( L_frame == st->L_frame >> 1 ) && st->tcxonly && isTCX5 ) { -#ifdef NONBE_FIX_TCX5_INTERLEAVING_FOR_FS_IN_UNEQUAL_FS_OUT if ( st->element_mode == EVS_MONO || ( L_spec < L_frameTCX && !whitenedDomain ) ) /* todo: this is temporary to maintain EVS BE, this is a bug and should be fixed also for EVS (see issue 13) */ -#else - if ( st->element_mode == EVS_MONO || L_spec < L_frameTCX ) /* todo: this is temporary to maintain EVS BE, this is a bug and should be fixed also for EVS (see issue 13) */ -#endif { tcx5TnsUngrouping( L_frameTCX >> 1, hTcxCfg->tnsConfig[0][0].iFilterBorders[0] >> 1, x, DEC ); } diff --git a/lib_dec/hq_lr_dec.c b/lib_dec/hq_lr_dec.c index f9ab923be7a3d6631b70d0af15e719b3bd3e9d5f..e50bd127d78b5e29f92f8cf55952344fd5a3f3a1 100644 --- a/lib_dec/hq_lr_dec.c +++ b/lib_dec/hq_lr_dec.c @@ -262,7 +262,11 @@ void hq_lr_dec( frac1 = L_Extract_lc( L_tmp, &exp ); /* Extract exponent of L_tmp */ L_tmp = Pow2( 30, frac1 ); exp = sub( exp, 30 ); - Ep_fx[i] = L_shl( L_tmp, sub( exp, 6 ) ); /* Q -6 */ +#ifdef BASOP_NOGLOB + Ep_fx[i] = L_shl_o( L_tmp, s_max( sub( exp, 6 ), -31 ), &Overflow ); /* Q -6 */ +#else + Ep_fx[i] = L_shl( L_tmp, s_max( sub( exp, 6 ), -31 ) ); /* Q -6 */ +#endif Ep[i] = (float) ( Ep_fx[i] / pow( 2.0, -6 ) ); } diff --git a/lib_dec/ivas_binRenderer_internal.c b/lib_dec/ivas_binRenderer_internal.c index 4b2c4c7d0730f215a9a9e4e5be207181a2f10b0b..8cda55017c4e8c4a8be270e89da91b594acade35 100644 --- a/lib_dec/ivas_binRenderer_internal.c +++ b/lib_dec/ivas_binRenderer_internal.c @@ -999,6 +999,7 @@ ivas_error ivas_binRenderer_open( if ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM || ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV && st_ivas->hOutSetup.output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) { pRoomAcoustics = ( st_ivas->hOutSetup.output_config == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ? &( st_ivas->hRenderConfig->roomAcoustics ) : NULL; + if ( ( error = ivas_binaural_reverb_init( &( hBinRenderer->hReverb ), st_ivas->hHrtfStatistics, hBinRenderer->conv_band, @@ -1007,7 +1008,8 @@ ivas_error ivas_binRenderer_open( st_ivas->hDecoderConfig->output_Fs, st_ivas->hHrtfFastConv->fastconvReverberationTimes, st_ivas->hHrtfFastConv->fastconvReverberationEneCorrections, - hBinRenderer->earlyPartEneCorrection ) ) != IVAS_ERR_OK ) + NULL ) ) != IVAS_ERR_OK ) + { return error; } diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index a303c6d65b0f55de9ebaeb761d3b060081f6b8c0..2c2f814ab88b811d47b6fe7f01dfddf3b901f8de 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -1252,6 +1252,7 @@ ivas_error ivas_init_decoder( int16_t sce_id, cpe_id; int16_t numCldfbAnalyses, numCldfbSyntheses; int16_t granularity, n_channels_transport_jbm; + int16_t nchan_out_buff; int32_t output_Fs, ivas_total_brate; int32_t delay_ns; AUDIO_CONFIG output_config; @@ -2305,7 +2306,15 @@ ivas_error ivas_init_decoder( if ( st_ivas->mc_mode == MC_MODE_MCT || st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) { - delay_ns = st_ivas->binaural_latency_ns; + if ( st_ivas->hIntSetup.index_lfe[0] != -1 ) + { + delay_ns = st_ivas->binaural_latency_ns; + } + else + { + delay_ns = 0; + } + if ( st_ivas->hBinRenderer != NULL ) { if ( st_ivas->hBinRenderer->render_lfe ) @@ -2363,7 +2372,7 @@ ivas_error ivas_init_decoder( } } - if ( ( st_ivas->ivas_format == MASA_FORMAT || st_ivas->ivas_format == MASA_ISM_FORMAT ) && st_ivas->hDecoderConfig->Opt_tsm ) + if ( ( st_ivas->ivas_format == MASA_FORMAT || st_ivas->ivas_format == MASA_ISM_FORMAT ) && hDecoderConfig->Opt_tsm ) { if ( st_ivas->hDecoderConfig->output_config == IVAS_AUDIO_CONFIG_EXTERNAL ) { @@ -2378,23 +2387,13 @@ ivas_error ivas_init_decoder( * Allocate floating-point output audio buffers *-----------------------------------------------------------------*/ - k = ivas_get_nchan_buffers_dec( st_ivas, st_ivas->sba_analysis_order, st_ivas->hDecoderConfig->ivas_total_brate ); - for ( n = 0; n < k; n++ ) + nchan_out_buff = ivas_get_nchan_buffers_dec( st_ivas, st_ivas->sba_analysis_order, ivas_total_brate ); + if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff, hDecoderConfig->Opt_tsm, st_ivas->hTcBuffer ) ) != IVAS_ERR_OK ) { - /* note: these are intra-frame heap memories */ - if ( ( st_ivas->p_output_f[n] = (float *) malloc( ( 48000 / FRAMES_PER_SEC ) * sizeof( float ) ) ) == NULL ) - { - return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for floating-point output audio buffer!\n" ) ); - } - } - - for ( ; n < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; n++ ) - { - st_ivas->p_output_f[n] = NULL; + return error; } - - return error; + return IVAS_ERR_OK; } @@ -2849,12 +2848,14 @@ void ivas_destroy_dec( /* Limiter struct */ ivas_limiter_close( &( st_ivas->hLimiter ) ); + /* Decoder configuration structure */ if ( st_ivas->hDecoderConfig != NULL ) { free( st_ivas->hDecoderConfig ); st_ivas->hDecoderConfig = NULL; } + /* JBM TC buffer structure */ ivas_jbm_dec_tc_buffer_close( &st_ivas->hTcBuffer ); if ( st_ivas->hJbmMetadata != NULL ) @@ -2863,14 +2864,10 @@ void ivas_destroy_dec( st_ivas->hJbmMetadata = NULL; } - /* floating-point output audio buffers */ + /* floating-point output audio buffers */ for ( i = 0; i < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; i++ ) { - if ( st_ivas->p_output_f[i] != NULL ) - { - free( st_ivas->p_output_f[i] ); - st_ivas->p_output_f[i] = NULL; - } + st_ivas->p_output_f[i] = NULL; } /* main IVAS handle */ diff --git a/lib_dec/ivas_ism_dec.c b/lib_dec/ivas_ism_dec.c index a76db363061b54ef55b49b11622d8385fc4c75b6..d89076863af61811128c043d213250c26d8dc4ca 100644 --- a/lib_dec/ivas_ism_dec.c +++ b/lib_dec/ivas_ism_dec.c @@ -60,7 +60,7 @@ static ivas_error ivas_ism_bitrate_switching_dec( int16_t tc_nchan_tc_new; int16_t tc_nchan_allocate_new; int16_t tc_granularity_new; - int16_t nchan_out_buff, nchan_out_buff_old; + int16_t nchan_out_buff; nCPE_old = st_ivas->nCPE; nSCE_old = st_ivas->nSCE; @@ -70,7 +70,6 @@ static ivas_error ivas_ism_bitrate_switching_dec( st_ivas->ism_mode = last_ism_mode; ivas_init_dec_get_num_cldfb_instances( st_ivas, &numCldfbAnalyses_old, &numCldfbSyntheses_old ); st_ivas->ism_mode = ism_mode; - nchan_out_buff_old = ivas_get_nchan_buffers_dec( st_ivas, -1, -1 ); if ( ( error = ivas_ism_config( st_ivas->hDecoderConfig->ivas_total_brate, st_ivas->nchan_transport, st_ivas->nchan_ism, NULL, 0, NULL, NULL, element_brate_tmp, NULL, NULL, 0 ) ) != IVAS_ERR_OK ) { @@ -122,6 +121,25 @@ static ivas_error ivas_ism_bitrate_switching_dec( mvs2s( st_ivas->hSpatParamRendCom->subframe_nbslots, st_ivas->hTcBuffer->subframe_nbslots, MAX_JBM_SUBFRAMES_5MS ); } +#ifdef NONBE_1321_JBM_ASSERT_BITRATE_SWITCHING + /* JBM: when granularity goes down (e.g. Discrete ISM with TD Obj Renderer -> ParamISM with binaural fastconv + render what still fits in the new granularity */ + tc_granularity_new = ivas_jbm_dec_get_render_granularity( st_ivas->renderer_type, RENDERER_DISABLE, st_ivas->hDecoderConfig->output_Fs ); + + if ( tc_granularity_new < st_ivas->hTcBuffer->n_samples_granularity ) + { + /* flush already done in IVAS_DEC_ReadFormat() */ + } + /* JBM: when granularity goes up set samples to discard at the beginning of the frame */ + else if ( tc_granularity_new > st_ivas->hTcBuffer->n_samples_granularity ) + { + if ( ( error = ivas_jbm_dec_set_discard_samples( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } + } + +#endif if ( st_ivas->ism_mode != last_ism_mode ) { /* EFAP handle */ @@ -266,17 +284,6 @@ static ivas_error ivas_ism_bitrate_switching_dec( return error; } - /*-----------------------------------------------------------------* - * floating-point output audio buffers - *-----------------------------------------------------------------*/ - - nchan_out_buff = ivas_get_nchan_buffers_dec( st_ivas, -1, -1 ); - - if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff_old, nchan_out_buff ) ) != IVAS_ERR_OK ) - { - return error; - } - /*-----------------------------------------------------------------* * JBM TC buffers *-----------------------------------------------------------------*/ @@ -289,7 +296,9 @@ static ivas_error ivas_ism_bitrate_switching_dec( tc_nchan_tc_new = ivas_jbm_dec_get_num_tc_channels( st_ivas ); tc_nchan_allocate_new = tc_nchan_tc_new; tc_nchan_full_new = tc_nchan_tc_new; +#ifndef NONBE_1321_JBM_ASSERT_BITRATE_SWITCHING tc_granularity_new = ivas_jbm_dec_get_render_granularity( st_ivas->renderer_type, RENDERER_DISABLE, st_ivas->hDecoderConfig->output_Fs ); +#endif if ( st_ivas->ism_mode == ISM_MODE_PARAM && ( st_ivas->renderer_type != RENDERER_MONO_DOWNMIX && st_ivas->renderer_type != RENDERER_DISABLE && st_ivas->renderer_type != RENDERER_BINAURAL_PARAMETRIC && st_ivas->renderer_type != RENDERER_BINAURAL_PARAMETRIC_ROOM ) ) { @@ -317,6 +326,16 @@ static ivas_error ivas_ism_bitrate_switching_dec( mvs2s( st_ivas->hTcBuffer->subframe_nbslots, st_ivas->hSpatParamRendCom->subframe_nbslots, MAX_JBM_SUBFRAMES_5MS ); } + /*-----------------------------------------------------------------* + * floating-point output audio buffers + *-----------------------------------------------------------------*/ + + nchan_out_buff = ivas_get_nchan_buffers_dec( st_ivas, -1, -1 ); + if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff, st_ivas->hDecoderConfig->Opt_tsm, st_ivas->hTcBuffer ) ) != IVAS_ERR_OK ) + { + return error; + } + return IVAS_ERR_OK; } diff --git a/lib_dec/ivas_ism_renderer.c b/lib_dec/ivas_ism_renderer.c index 3d18fea93b13f45ab00e930f7abe4e60bde6689c..11d797253aa423b253950e3707bf6404e9e97e93 100644 --- a/lib_dec/ivas_ism_renderer.c +++ b/lib_dec/ivas_ism_renderer.c @@ -193,20 +193,10 @@ void ivas_ism_render_sf( ism_md_subframe_update_jbm = st_ivas->hTcBuffer->nb_subframes - 2; } - if ( st_ivas->hDecoderConfig->Opt_tsm ) - { - for ( i = 0; i < num_objects; i++ ) - { - p_tc[i] = &st_ivas->hTcBuffer->tc[i][tc_offset]; - } - } - else + for ( i = 0; i < num_objects; i++ ) { - for ( i = 0; i < num_objects; i++ ) - { - mvr2r( &output_f[i][tc_offset], tc_local[i], n_samples_to_render ); - p_tc[i] = tc_local[i]; - } + mvr2r( &output_f[i][tc_offset], tc_local[i], n_samples_to_render ); + p_tc[i] = tc_local[i]; } for ( i = 0; i < nchan_out_woLFE + st_ivas->hIntSetup.num_lfe; i++ ) @@ -428,12 +418,11 @@ void ivas_omasa_separate_object_renderer_close( *-------------------------------------------------------------------------*/ void ivas_omasa_separate_object_render_jbm( - Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ - const uint16_t nSamplesRendered, /* i : number of samples rendered */ - float input_f_in[][L_FRAME48k], /* i : separated object signal */ - float *output_f[], /* o : rendered time signal */ - const int16_t subframes_rendered, /* i : number of subframes rendered */ - const int16_t slots_rendered /* i : number of CLDFB slots rendered */ + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + const uint16_t nSamplesRendered, /* i : number of samples rendered */ + float input_f_in[][L_FRAME48k], /* i : separated object signal */ + float *output_f[], /* o : rendered time signal */ + const int16_t subframes_rendered /* i : number of subframes rendered */ ) { VBAP_HANDLE hVBAPdata; @@ -474,26 +463,14 @@ void ivas_omasa_separate_object_render_jbm( num_objects = st_ivas->nchan_ism; } - offsetSamples = slots_rendered * hSpatParamRendCom->slot_size; - for ( j = 0; j < nchan_out_woLFE + num_lfe; j++ ) { output_f_local[j] = output_f[j]; } - if ( st_ivas->hDecoderConfig->Opt_tsm ) - { - for ( obj = 0; obj < num_objects; obj++ ) - { - input_f[obj] = &st_ivas->hTcBuffer->tc[obj + 2][offsetSamples]; - } - } - else + for ( obj = 0; obj < num_objects; obj++ ) { - for ( obj = 0; obj < num_objects; obj++ ) - { - input_f[obj] = input_f_in[obj]; - } + input_f[obj] = input_f_in[obj]; } slots_to_render = nSamplesRendered / hSpatParamRendCom->slot_size; diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index 317bb0057df58907fefe001a57e1ada5ddf8343d..e30f5aebebdd90c9d04b763b2d29e55dd752505f 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -763,7 +763,7 @@ void ivas_jbm_dec_feed_tc_to_renderer( float tmp_buf[MAX_JBM_L_FRAME48k]; float *p_data_f[FOA_CHANNELS + MAX_NUM_OBJECTS]; int16_t n, n_render_timeslots, n_ch_cldfb; - int16_t ch; + int16_t ch, offset, len_offset; DECODER_TC_BUFFER_HANDLE hTcBuffer; hTcBuffer = st_ivas->hTcBuffer; @@ -781,6 +781,20 @@ void ivas_jbm_dec_feed_tc_to_renderer( n_ch_full_copy = min( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full ); n_ch_res_copy = hTcBuffer->nchan_transport_jbm - hTcBuffer->nchan_buffer_full; + /* buffers are shared between 'hTcBuffer->tc[]' and 'p_output_f[]': + in case of 'length(hTcBuffer->tc[]) < length(p_output_f[])', reset of TC buffers + pointers is needed after ivas_buffer_interleaved_to_deinterleaved() */ + len_offset = NS2SA( st_ivas->hDecoderConfig->output_Fs, MAX_JBM_L_FRAME_NS ); + if ( len_offset < L_FRAME48k ) + { + offset = 0; + for ( ch = 0; ch < max( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full ); ch++ ) + { + hTcBuffer->tc[ch] = &hTcBuffer->tc_buffer[offset]; + offset += len_offset; + } + } + for ( ch = 0; ch < n_ch_full_copy; ch++ ) { mvr2r( hTcBuffer->tc[ch], tmp_buf, nSamplesForRendering ); @@ -1110,12 +1124,6 @@ ivas_error ivas_jbm_dec_render( { mvr2r( p_tc[n], p_output[n], *nSamplesRendered ); } -#if defined( NONBE_1339_FIXOSBA_EXT_LOUDNESS ) && !defined( NONBE_1352_HARMONIZE_OSBA_LOUDNESS ) - for ( n = 0; n < st_ivas->hDecoderConfig->nchan_out; n++ ) - { - v_multc( p_output[n], 0.5f, p_output[n], *nSamplesRendered ); - } -#endif } else { @@ -1128,12 +1136,10 @@ ivas_error ivas_jbm_dec_render( else if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM ) { ivas_dirac_dec_binaural_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, nchan_remapped, p_output ); -#ifdef NONBE_1352_HARMONIZE_OSBA_LOUDNESS for ( n = 0; n < st_ivas->hDecoderConfig->nchan_out; n++ ) { v_multc( p_output[n], 2.0f, p_output[n], *nSamplesRendered ); } -#endif } else { @@ -1156,12 +1162,10 @@ ivas_error ivas_jbm_dec_render( set_zero( p_output[n], *nSamplesRendered ); } } -#ifdef NONBE_1352_HARMONIZE_OSBA_LOUDNESS for ( n = 0; n < st_ivas->hDecoderConfig->nchan_out; n++ ) { v_multc( p_output[n], 2.0f, p_output[n], *nSamplesRendered ); } -#endif } } else if ( st_ivas->ivas_format == MC_FORMAT ) @@ -2096,6 +2100,7 @@ static ivas_error ivas_jbm_dec_tc_audio_allocate( if ( Opt_tsm ) { n_samp_full = ( NS2SA( output_Fs, MAX_JBM_L_FRAME_NS ) ); + n_samp_full = max( n_samp_full, L_FRAME48k ); /* buffers are shared between 'hTcBuffer->tc[]' and 'p_output_f[]': ensure minimal length */ n_samp_residual = hTcBuffer->n_samples_granularity - 1; } else @@ -2155,6 +2160,8 @@ static ivas_error ivas_jbm_dec_tc_audio_allocate( } } + hTcBuffer->tc_buffer2 = NULL; + return IVAS_ERR_OK; } @@ -2192,6 +2199,12 @@ static void ivas_jbm_dec_tc_audio_deallocate( hTcBuffer->tc_buffer_old[ch_idx] = NULL; } } + + if ( hTcBuffer->tc_buffer2 != NULL ) + { + free( hTcBuffer->tc_buffer2 ); + hTcBuffer->tc_buffer2 = NULL; + } } return; @@ -2388,7 +2401,7 @@ static void ivas_jbm_dec_tc_buffer_playout( for ( ch_idx = 0; ch_idx < st_ivas->hTcBuffer->nchan_transport_jbm; ch_idx++ ) { - mvr2r( st_ivas->hTcBuffer->tc[ch_idx] + st_ivas->hTcBuffer->n_samples_rendered, output[ch_idx], *nSamplesRendered ); + output[ch_idx] = st_ivas->hTcBuffer->tc[ch_idx] + st_ivas->hTcBuffer->n_samples_rendered; } st_ivas->hTcBuffer->subframes_rendered = last_sf; diff --git a/lib_dec/ivas_lfe_dec.c b/lib_dec/ivas_lfe_dec.c index eed016b09f65566a60f4f0e17d3a4d63fbaa1e8f..6dfe76f9652331c0354d052ebe052e20fe4b6b75 100644 --- a/lib_dec/ivas_lfe_dec.c +++ b/lib_dec/ivas_lfe_dec.c @@ -380,7 +380,7 @@ ivas_error ivas_create_lfe_dec( LFE_DEC_HANDLE hLFE; float lfe_addl_delay_s; int16_t i, j; - int16_t add_delay_sa; + float lfe_block_delay_s; low_pass_delay_dec_out = 0; block_offset_s = 0; @@ -418,7 +418,7 @@ ivas_error ivas_create_lfe_dec( hLFE->cum_freq_models[1][3] = &ivas_str_lfe_freq_models.entropy_coder_model_coarse_sg4; /* delay calculation */ - hLFE->lfe_block_delay_s = ( IVAS_LFE_FADE_NS / 1000000000.f ) + ivas_lfe_lpf_delay[IVAS_FILTER_ORDER_4 - 3]; + lfe_block_delay_s = ( IVAS_LFE_FADE_NS / 1000000000.f ) + ivas_lfe_lpf_delay[IVAS_FILTER_ORDER_4 - 3]; block_offset_s = BLOCK_OFFSET_MS * 0.001f; filt_order = 0; @@ -426,21 +426,21 @@ ivas_error ivas_create_lfe_dec( if ( ( delay_ns / 1000000000.f ) > ivas_lfe_lpf_delay[IVAS_FILTER_ORDER_4 - 3] ) { filt_order = 4; - low_pass_delay_dec_out = ivas_lfe_lpf_delay[IVAS_FILTER_ORDER_4 - 3] * 1000000000.f; + low_pass_delay_dec_out = ivas_lfe_lpf_delay[IVAS_FILTER_ORDER_4 - 3]; ivas_create_lfe_lpf_dec( &( hLFE->filter_state ), output_Fs ); } hLFE->filter_state.order = filt_order; - hLFE->lfe_block_delay_s = hLFE->lfe_block_delay_s + low_pass_delay_dec_out; + lfe_block_delay_s = lfe_block_delay_s + low_pass_delay_dec_out; hLFE->lfe_prior_buf_len = NS2SA( output_Fs, IVAS_LFE_FADE_NS ); hLFE->bfi_count = 0; + block_offset_s += delay_ns / 1000000000.f; + lfe_addl_delay_s = block_offset_s - lfe_block_delay_s; - lfe_addl_delay_s = block_offset_s - hLFE->lfe_block_delay_s; lfe_addl_delay_s = max( 0.0f, lfe_addl_delay_s ); - add_delay_sa = (int16_t) roundf( (float) delay_ns * output_Fs / 1000000000.f ); - hLFE->lfe_addl_delay = (int16_t) ( lfe_addl_delay_s * output_Fs ) + add_delay_sa; - hLFE->lfe_block_delay_s += lfe_addl_delay_s + add_delay_sa / output_Fs; + hLFE->lfe_addl_delay = (int16_t) ( lfe_addl_delay_s * output_Fs ); + hLFE->delay_ns = delay_ns; if ( hLFE->lfe_addl_delay > 0 ) { diff --git a/lib_dec/ivas_masa_dec.c b/lib_dec/ivas_masa_dec.c index b698395d75f7b4a5b55d52d6c09e34f86a1f8ad1..f44f872abd1296a83c4987726eac0d78577c7cae 100644 --- a/lib_dec/ivas_masa_dec.c +++ b/lib_dec/ivas_masa_dec.c @@ -1320,7 +1320,7 @@ ivas_error ivas_masa_dec_reconfigure( Decoder_State **sts; int32_t ivas_total_brate, last_ivas_total_brate; int16_t numCldfbAnalyses_old, numCldfbSyntheses_old; - int16_t nchan_out_buff_old, nchan_out_buff; + int16_t nchan_out_buff; ivas_error error; int16_t pos_idx; int32_t ism_total_brate; @@ -1328,8 +1328,6 @@ ivas_error ivas_masa_dec_reconfigure( ivas_total_brate = st_ivas->hDecoderConfig->ivas_total_brate; last_ivas_total_brate = st_ivas->hDecoderConfig->last_ivas_total_brate; - nchan_out_buff_old = ivas_get_nchan_buffers_dec( st_ivas, -1, -1 ); - /* Copy state to TC buffer if granularity matches and we are not in OMASA EXT rendering mode */ if ( st_ivas->hSpatParamRendCom != NULL && st_ivas->hSpatParamRendCom->slot_size == st_ivas->hTcBuffer->n_samples_granularity && st_ivas->hDecoderConfig->output_config != IVAS_AUDIO_CONFIG_EXTERNAL ) { @@ -1474,6 +1472,10 @@ ivas_error ivas_masa_dec_reconfigure( ivas_masa_set_elements( ivas_total_brate, st_ivas->mc_mode, st_ivas->nchan_transport, st_ivas->hQMetaData, &tmp, &tmp, &tmp, st_ivas->ivas_format, st_ivas->ism_mode, ism_total_brate ); + /*-----------------------------------------------------------------* + * JBM TC buffers + *-----------------------------------------------------------------*/ + { int16_t tc_nchan_to_allocate; int16_t tc_nchan_transport; @@ -1499,6 +1501,25 @@ ivas_error ivas_masa_dec_reconfigure( tc_nchan_to_allocate = 2 * BINAURAL_CHANNELS; } } +#ifdef NONBE_1321_JBM_ASSERT_BITRATE_SWITCHING + if ( st_ivas->ivas_format == MASA_ISM_FORMAT && st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC && st_ivas->ism_mode == ISM_MASA_MODE_DISC ) + { + if ( n_samples_granularity > st_ivas->hTcBuffer->n_samples_granularity ) + { + if ( ( error = ivas_jbm_dec_set_discard_samples( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } + } + } + else if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC && st_ivas->ism_mode != ISM_MASA_MODE_DISC ) + { + if ( n_samples_granularity < st_ivas->hTcBuffer->n_samples_granularity ) + { + /* flush already done in IVAS_DEC_ReadFormat() */ + } + } +#endif } else if ( st_ivas->nchan_transport == 1 && ( st_ivas->renderer_type == RENDERER_DIRAC && st_ivas->hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD ) ) { @@ -1544,7 +1565,7 @@ ivas_error ivas_masa_dec_reconfigure( if ( st_ivas->ivas_format == MASA_FORMAT && st_ivas->last_ivas_format == MASA_FORMAT ) /* note: switching with OMASA is addressed in ivas_omasa_dec_config() */ { nchan_out_buff = ivas_get_nchan_buffers_dec( st_ivas, -1, -1 ); - if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff_old, nchan_out_buff ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff, st_ivas->hDecoderConfig->Opt_tsm, st_ivas->hTcBuffer ) ) != IVAS_ERR_OK ) { return error; } diff --git a/lib_dec/ivas_mc_paramupmix_dec.c b/lib_dec/ivas_mc_paramupmix_dec.c index c06e8b3fa18632bff589fa6d452bcd57394a3f1b..5753d262a078261ae49ea0abb9c6247a1ce377d0 100644 --- a/lib_dec/ivas_mc_paramupmix_dec.c +++ b/lib_dec/ivas_mc_paramupmix_dec.c @@ -679,6 +679,7 @@ static void ivas_mc_paramupmix_dec_sf( cldfbAnalysis_ts( &( pPcm_temp[ch][hMCParamUpmix->num_freq_bands * slot_idx] ), Cldfb_RealBuffer[ch][slot_idx], Cldfb_ImagBuffer[ch][slot_idx], hMCParamUpmix->num_freq_bands, st_ivas->cldfbAnaDec[ch] ); } } + for ( ch = 0; ch < MC_PARAMUPMIX_COMBINATIONS; ch++ ) { ps_pred_process_sf( hMCParamUpmix, @@ -837,6 +838,7 @@ static void ivas_mc_paramupmix_dec_sf( hMCParamUpmix->num_freq_bands, st_ivas->cldfbSynDec[ch] ); } } + /* adjust delay of other channels */ noparamupmix_delay = NS2SA( st_ivas->hDecoderConfig->output_Fs, IVAS_FB_DEC_DELAY_NS ); n_samples_rendered = st_ivas->hTcBuffer->subframe_nbslots[st_ivas->hTcBuffer->subframes_rendered] * hMCParamUpmix->num_freq_bands; @@ -844,22 +846,29 @@ static void ivas_mc_paramupmix_dec_sf( { for ( ch = 0; ch < MC_PARAMUPMIX_COMBINATIONS; ch++ ) { - float tmp_buf[L_SUBFRAME5MS_48k]; - mvr2r( &output_f[ch][n_samples_rendered - noparamupmix_delay], tmp_buf, noparamupmix_delay ); - mvr2r( output_f[ch], &output_f[ch][noparamupmix_delay], n_samples_rendered - noparamupmix_delay ); - mvr2r( hMCParamUpmix->pcm_delay[ch], output_f[ch], noparamupmix_delay ); - mvr2r( tmp_buf, hMCParamUpmix->pcm_delay[ch], noparamupmix_delay ); + /*delay is handled within LFE decoder*/ + if ( st_ivas->hIntSetup.index_lfe[0] != ch ) + { + float tmp_buf[L_SUBFRAME5MS_48k]; + mvr2r( &output_f[ch][n_samples_rendered - noparamupmix_delay], tmp_buf, noparamupmix_delay ); + mvr2r( output_f[ch], &output_f[ch][noparamupmix_delay], n_samples_rendered - noparamupmix_delay ); + mvr2r( hMCParamUpmix->pcm_delay[ch], output_f[ch], noparamupmix_delay ); + mvr2r( tmp_buf, hMCParamUpmix->pcm_delay[ch], noparamupmix_delay ); + } } } else { for ( ch = 0; ch < MC_PARAMUPMIX_COMBINATIONS; ch++ ) { - float tmp_buf[L_SUBFRAME5MS_48k]; - mvr2r( &output_f[ch][0], tmp_buf, n_samples_rendered ); - mvr2r( hMCParamUpmix->pcm_delay[ch], output_f[ch], n_samples_rendered ); - mvr2r( &hMCParamUpmix->pcm_delay[ch][n_samples_rendered], &hMCParamUpmix->pcm_delay[ch][0], noparamupmix_delay - n_samples_rendered ); - mvr2r( tmp_buf, &hMCParamUpmix->pcm_delay[ch][noparamupmix_delay - n_samples_rendered], n_samples_rendered ); + if ( st_ivas->hIntSetup.index_lfe[0] != ch ) + { + float tmp_buf[L_SUBFRAME5MS_48k]; + mvr2r( &output_f[ch][0], tmp_buf, n_samples_rendered ); + mvr2r( hMCParamUpmix->pcm_delay[ch], output_f[ch], n_samples_rendered ); + mvr2r( &hMCParamUpmix->pcm_delay[ch][n_samples_rendered], &hMCParamUpmix->pcm_delay[ch][0], noparamupmix_delay - n_samples_rendered ); + mvr2r( tmp_buf, &hMCParamUpmix->pcm_delay[ch][noparamupmix_delay - n_samples_rendered], n_samples_rendered ); + } } } } diff --git a/lib_dec/ivas_mct_dec.c b/lib_dec/ivas_mct_dec.c index 8fb966c36518fb51edbce486791ec79dd5ba17b3..eaa094b68bbedb956823e0b04baa002be3e19a2f 100644 --- a/lib_dec/ivas_mct_dec.c +++ b/lib_dec/ivas_mct_dec.c @@ -732,11 +732,10 @@ static ivas_error ivas_mc_dec_reconfig( int16_t tc_nchan_tc_new; int16_t tc_nchan_allocate_new; int16_t tc_granularity_new; - int16_t nchan_out_buff_old, nchan_out_buff; + int16_t nchan_out_buff; ivas_total_brate = st_ivas->hDecoderConfig->ivas_total_brate; nchan_transport_old = st_ivas->nchan_transport; - nchan_out_buff_old = ivas_get_nchan_buffers_dec( st_ivas, -1, -1 ); last_mc_mode = ivas_mc_mode_select( ivas_mc_map_output_config_to_mc_ls_setup( st_ivas->transport_config ), st_ivas->hDecoderConfig->last_ivas_total_brate ); /* NB: this assumes that LS config remains the same between frames */ /* temporally set the current mc_mode back to the previous one to make sure the following call to @@ -789,6 +788,25 @@ static ivas_error ivas_mc_dec_reconfig( } } +#ifdef NONBE_1321_JBM_ASSERT_BITRATE_SWITCHING + /* JBM: when granularity goes down (e.g. MCT with CREND -> ParamMC with binaural fastconv + render what still fits in the new granularity */ + tc_granularity_new = ivas_jbm_dec_get_render_granularity( st_ivas->renderer_type, RENDERER_DISABLE, st_ivas->hDecoderConfig->output_Fs ); + + if ( tc_granularity_new < st_ivas->hTcBuffer->n_samples_granularity ) + { + /* flush already done in IVAS_DEC_ReadFormat() */ + } + /* JBM: when granularity goes up set samples to discard at the beginning of the frame */ + else if ( tc_granularity_new > st_ivas->hTcBuffer->n_samples_granularity ) + { + if ( ( error = ivas_jbm_dec_set_discard_samples( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } + } + +#endif if ( st_ivas->mc_mode == MC_MODE_MCT ) { st_ivas->nchan_transport = ivas_mc_ls_setup_get_num_channels( ivas_mc_map_output_config_to_mc_ls_setup( st_ivas->transport_config ) ); @@ -1077,42 +1095,6 @@ static ivas_error ivas_mc_dec_reconfig( return error; } - /*-----------------------------------------------------------------* - * Allocate the LFE handle that is coded separately after the allocation of the core coders - *-----------------------------------------------------------------*/ - - if ( ( st_ivas->mc_mode == MC_MODE_MCT || st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) && st_ivas->hLFE == NULL ) - { - int32_t delay_ns = st_ivas->binaural_latency_ns; - if ( st_ivas->hBinRenderer != NULL ) - { - if ( st_ivas->hBinRenderer->render_lfe ) - { - /* Account for filterbank delay */ - delay_ns += IVAS_FB_DEC_DELAY_NS; - } - else - { - delay_ns = 0; - } - } - else - { - if ( ( st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) && ( st_ivas->cldfbSynDec[0] != NULL ) ) - { - delay_ns += IVAS_FB_DEC_DELAY_NS; - } - } - - if ( ( error = ivas_create_lfe_dec( &st_ivas->hLFE, st_ivas->hDecoderConfig->output_Fs, delay_ns ) ) != IVAS_ERR_OK ) - { - return error; - } - - set_zero( st_ivas->hLFE->prevsynth_buf, LFE_PLC_BUFLEN ); - set_zero( st_ivas->hLFE->prior_out_buffer, L_FRAME48k ); - } - /*-----------------------------------------------------------------* * Reconfigure renderers *-----------------------------------------------------------------*/ @@ -1264,6 +1246,63 @@ static ivas_error ivas_mc_dec_reconfig( return error; } + + /*-----------------------------------------------------------------* + * Allocate the LFE handle that is coded separately after the allocation of the core coders + *-----------------------------------------------------------------*/ + + if ( ( st_ivas->mc_mode == MC_MODE_MCT || st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) ) + { + int32_t delay_ns; + if ( st_ivas->hIntSetup.index_lfe[0] != -1 ) + { + delay_ns = st_ivas->binaural_latency_ns; + } + else + { + delay_ns = 0; + } + + if ( st_ivas->hBinRenderer != NULL ) + { + if ( st_ivas->hBinRenderer->render_lfe ) + { + /* Account for filterbank delay */ + delay_ns += IVAS_FB_DEC_DELAY_NS; + } + else + { + delay_ns = 0; + } + } + else + { + if ( ( st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) && ( st_ivas->cldfbSynDec[0] != NULL ) ) + { + delay_ns += IVAS_FB_DEC_DELAY_NS; + } + } + + if ( st_ivas->hLFE != NULL ) + { + if ( st_ivas->hLFE->delay_ns != delay_ns ) + { + ivas_lfe_dec_close( &( st_ivas->hLFE ) ); + } + } + + if ( st_ivas->hLFE == NULL ) + { + if ( ( error = ivas_create_lfe_dec( &st_ivas->hLFE, st_ivas->hDecoderConfig->output_Fs, delay_ns ) ) != IVAS_ERR_OK ) + { + return error; + } + + set_zero( st_ivas->hLFE->prevsynth_buf, LFE_PLC_BUFLEN ); + set_zero( st_ivas->hLFE->prior_out_buffer, L_FRAME48k ); + } + } + /*-----------------------------------------------------------------* * JBM TC buffers *-----------------------------------------------------------------*/ @@ -1276,7 +1315,9 @@ static ivas_error ivas_mc_dec_reconfig( tc_nchan_tc_new = ivas_jbm_dec_get_num_tc_channels( st_ivas ); tc_nchan_allocate_new = tc_nchan_tc_new; tc_nchan_full_new = tc_nchan_tc_new; +#ifndef NONBE_1321_JBM_ASSERT_BITRATE_SWITCHING tc_granularity_new = ivas_jbm_dec_get_render_granularity( st_ivas->renderer_type, RENDERER_DISABLE, st_ivas->hDecoderConfig->output_Fs ); +#endif if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC ) { @@ -1320,6 +1361,7 @@ static ivas_error ivas_mc_dec_reconfig( return error; } } + /* transfer subframe info from central tc buffer to ParamMC or McMASA (DirAC) */ if ( st_ivas->hSpatParamRendCom != NULL ) { @@ -1344,8 +1386,7 @@ static ivas_error ivas_mc_dec_reconfig( *-----------------------------------------------------------------*/ nchan_out_buff = ivas_get_nchan_buffers_dec( st_ivas, -1, -1 ); - - if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff_old, nchan_out_buff ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff, st_ivas->hDecoderConfig->Opt_tsm, st_ivas->hTcBuffer ) ) != IVAS_ERR_OK ) { return error; } diff --git a/lib_dec/ivas_mdct_core_dec.c b/lib_dec/ivas_mdct_core_dec.c index 7ba536809ca7f5f5988fcb7bb17e4e2be0d280d6..426be4d02d602a22681f0b102cff880bd55d7bc4 100644 --- a/lib_dec/ivas_mdct_core_dec.c +++ b/lib_dec/ivas_mdct_core_dec.c @@ -1104,7 +1104,17 @@ void ivas_mdct_core_tns_ns( decoder_tcx_tns( st, L_frame_global[ch], L_spec[ch], L_frame[ch], L_frameTCX[ch], &x[ch][k][0], fUseTns[ch][k], &tnsData[ch][k], bfi, k, 1 ); sns_shape_spectrum( x[ch][k], st->hTcxCfg->psychParamsCurrent, &sns_int_scf[0], st->hTcxCfg->psychParamsCurrent->nBins ); +#ifdef NONBE_FIX_1376_MDCT_CONCEALMENT + /* + 2025-09-07, mul: + in case of PLC, applying SNS up to L_spec might not be enough: In case the transition frame from DTX after an inactive period is lost, L_spec is assumed to represent a regular TCX frame, + however, this frame is nevertheless acting as an transition frame as also visible in L_frameTCX; thus, the safer approach to prevent high frequency artifacts is to apply the SNS up to L_frameTCX; + in case this is not necessary, x[] is filled with zeros, and the multiplication is not causing any additional harm + */ + v_multc( x[ch][k] + st->hTcxCfg->psychParamsCurrent->nBins, sns_int_scf[FDNS_NPTS - 1], x[ch][k] + st->hTcxCfg->psychParamsCurrent->nBins, max( L_spec[ch], L_frameTCX[ch] ) - st->hTcxCfg->psychParamsCurrent->nBins ); +#else v_multc( x[ch][k] + st->hTcxCfg->psychParamsCurrent->nBins, sns_int_scf[FDNS_NPTS - 1], x[ch][k] + st->hTcxCfg->psychParamsCurrent->nBins, L_spec[ch] - st->hTcxCfg->psychParamsCurrent->nBins ); +#endif decoder_tcx_tns( st, L_frame_global[ch], L_spec[ch], L_frame[ch], L_frameTCX[ch], &x[ch][k][0], fUseTns[ch][k], &tnsData[ch][k], bfi, k, 0 ); } diff --git a/lib_dec/ivas_omasa_dec.c b/lib_dec/ivas_omasa_dec.c index beaf645fa0d1bfad365e0136c0f1025bd71ab945..279dfe6931b02269e831481f7b4341d9e3bd8b81 100644 --- a/lib_dec/ivas_omasa_dec.c +++ b/lib_dec/ivas_omasa_dec.c @@ -200,7 +200,7 @@ ivas_error ivas_omasa_dec_config( int32_t ivas_total_brate, ism_total_brate, cpe_brate; ISM_MODE ism_mode_old; IVAS_FORMAT ivas_format_orig; - int16_t nchan_out_buff, nchan_out_buff_old; + int16_t nchan_out_buff; ivas_error error; RENDERER_TYPE old_renderer_type; @@ -215,8 +215,6 @@ ivas_error ivas_omasa_dec_config( ivas_format_orig = st_ivas->ivas_format; st_ivas->ivas_format = st_ivas->last_ivas_format; ivas_init_dec_get_num_cldfb_instances( st_ivas, &numCldfbAnalyses_old, &numCldfbSyntheses_old ); - nchan_out_buff_old = ivas_get_nchan_buffers_dec( st_ivas, -1, -1 ); - st_ivas->ivas_format = ivas_format_orig; nSCE_old = st_ivas->nSCE; @@ -470,7 +468,7 @@ ivas_error ivas_omasa_dec_config( *-----------------------------------------------------------------*/ nchan_out_buff = ivas_get_nchan_buffers_dec( st_ivas, -1, -1 ); - if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff_old, nchan_out_buff ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff, st_ivas->hDecoderConfig->Opt_tsm, st_ivas->hTcBuffer ) ) != IVAS_ERR_OK ) { return error; } @@ -673,60 +671,55 @@ void ivas_omasa_dirac_rend_jbm( ) { int16_t subframes_rendered; - int16_t slots_rendered; int16_t n; float data_separated_objects[MAX_NUM_OBJECTS][L_FRAME48k]; - if ( !st_ivas->hDecoderConfig->Opt_tsm ) + *nSamplesRendered = min( nSamplesAsked, st_ivas->hTcBuffer->n_samples_available ); + + if ( st_ivas->ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ ) { - *nSamplesRendered = min( nSamplesAsked, st_ivas->hTcBuffer->n_samples_available ); + mvr2r( &output_f[CPE_CHANNELS][st_ivas->hTcBuffer->n_samples_rendered], data_separated_objects[0], *nSamplesRendered ); - if ( st_ivas->ism_mode == ISM_MASA_MODE_MASA_ONE_OBJ || st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ ) + if ( !st_ivas->hDecoderConfig->Opt_tsm && st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ ) { - mvr2r( &output_f[CPE_CHANNELS][st_ivas->hTcBuffer->n_samples_rendered], data_separated_objects[0], *nSamplesRendered ); - - if ( st_ivas->ism_mode == ISM_MASA_MODE_PARAM_ONE_OBJ ) + /* Gain separated object, if edited */ + for ( n = 0; n < st_ivas->nchan_ism; n++ ) { - /* Gain separated object, if edited */ - for ( n = 0; n < st_ivas->nchan_ism; n++ ) + if ( st_ivas->hMasaIsmData->ism_gain_is_edited[n] && st_ivas->hMasaIsmData->idx_separated_ism == n ) { - if ( st_ivas->hMasaIsmData->ism_gain_is_edited[n] && st_ivas->hMasaIsmData->idx_separated_ism == n ) - { - v_multc( data_separated_objects[0], st_ivas->hMasaIsmData->gain_ism_edited[n], data_separated_objects[0], *nSamplesRendered ); - } + v_multc( data_separated_objects[0], st_ivas->hMasaIsmData->gain_ism_edited[n], data_separated_objects[0], *nSamplesRendered ); } } } - else + } + else + { + for ( n = 0; n < st_ivas->nchan_ism; n++ ) { - for ( n = 0; n < st_ivas->nchan_ism; n++ ) - { - mvr2r( &output_f[n + CPE_CHANNELS][st_ivas->hTcBuffer->n_samples_rendered], data_separated_objects[n], *nSamplesRendered ); + mvr2r( &output_f[n + CPE_CHANNELS][st_ivas->hTcBuffer->n_samples_rendered], data_separated_objects[n], *nSamplesRendered ); - /* Gain discrete objects, if edited */ - if ( st_ivas->hMasaIsmData->ism_gain_is_edited[n] ) - { - v_multc( data_separated_objects[n], st_ivas->hMasaIsmData->gain_ism_edited[n], data_separated_objects[n], *nSamplesRendered ); - } + /* Gain discrete objects, if edited */ + if ( !st_ivas->hDecoderConfig->Opt_tsm && st_ivas->hMasaIsmData->ism_gain_is_edited[n] ) + { + v_multc( data_separated_objects[n], st_ivas->hMasaIsmData->gain_ism_edited[n], data_separated_objects[n], *nSamplesRendered ); } + } - /* Gain MASA part, if edited */ - if ( st_ivas->hMasaIsmData->masa_gain_is_edited ) + /* Gain MASA part, if edited */ + if ( !st_ivas->hDecoderConfig->Opt_tsm && st_ivas->hMasaIsmData->masa_gain_is_edited ) + { + for ( int16_t ch = 0; ch < 2; ch++ ) { - for ( int16_t ch = 0; ch < 2; ch++ ) - { - v_multc( output_f[ch], st_ivas->hMasaIsmData->gain_masa_edited, output_f[ch], *nSamplesRendered ); - } + v_multc( output_f[ch], st_ivas->hMasaIsmData->gain_masa_edited, output_f[ch], *nSamplesRendered ); } } } subframes_rendered = st_ivas->hSpatParamRendCom->subframes_rendered; - slots_rendered = st_ivas->hSpatParamRendCom->slots_rendered; ivas_dirac_dec_render( st_ivas, nchan_transport, nSamplesAsked, nSamplesRendered, nSamplesAvailable, output_f ); - ivas_omasa_separate_object_render_jbm( st_ivas, *nSamplesRendered, data_separated_objects, output_f, subframes_rendered, slots_rendered ); + ivas_omasa_separate_object_render_jbm( st_ivas, *nSamplesRendered, data_separated_objects, output_f, subframes_rendered ); return; } diff --git a/lib_dec/ivas_osba_dec.c b/lib_dec/ivas_osba_dec.c index ab1b378ab6eac2daa36f7c9ce5989cbbca85f8ca..8f790bde916f0edd19d915d85d3694905b437287 100644 --- a/lib_dec/ivas_osba_dec.c +++ b/lib_dec/ivas_osba_dec.c @@ -183,21 +183,11 @@ ivas_error ivas_osba_dirac_td_binaural_jbm( for ( b = 0; b < num_cldfb_bands; b++ ) { st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[n][slot_idx_start + slot_idx][b] = -#ifndef NONBE_1352_HARMONIZE_OSBA_LOUDNESS - ( 0.5f * st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[n][slot_idx_start + slot_idx][b] ) + - ( 0.5f * Cldfb_RealBuffer[b] ); -#else st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural[n][slot_idx_start + slot_idx][b] + Cldfb_RealBuffer[b]; -#endif st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[n][slot_idx_start + slot_idx][b] = -#ifndef NONBE_1352_HARMONIZE_OSBA_LOUDNESS - ( 0.5f * st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[n][slot_idx_start + slot_idx][b] ) + - ( 0.5f * Cldfb_ImagBuffer[b] ); -#else st_ivas->hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural[n][slot_idx_start + slot_idx][b] + Cldfb_ImagBuffer[b]; -#endif } } } @@ -214,11 +204,7 @@ ivas_error ivas_osba_dirac_td_binaural_jbm( int16_t i; for ( i = 0; i < nSamplesAsked; i++ ) { -#ifndef NONBE_1352_HARMONIZE_OSBA_LOUDNESS - output_f[n][i] = 0.5f * output_f[channel_offset + n][i] + 0.5f * p_sepobj[n][i]; -#else output_f[n][i] = output_f[channel_offset + n][i] + p_sepobj[n][i]; -#endif } } } @@ -272,45 +258,35 @@ ivas_error ivas_osba_render_sf( ) { int16_t n; - float output_ism[MAX_OUTPUT_CHANNELS][L_FRAME48k]; - float *p_output_ism[MAX_OUTPUT_CHANNELS]; + float output_sba[MAX_OUTPUT_CHANNELS][L_FRAME48k]; + float *p_output_sba[MAX_OUTPUT_CHANNELS]; ivas_error error; for ( n = 0; n < MAX_OUTPUT_CHANNELS; n++ ) { - p_output_ism[n] = &output_ism[n][0]; - } - - if ( !st_ivas->hDecoderConfig->Opt_tsm ) - { - int16_t tc_offset; - tc_offset = st_ivas->hTcBuffer->n_samples_rendered; - for ( n = 0; n < st_ivas->nchan_ism; n++ ) - { - mvr2r( &p_output[n][tc_offset], &output_ism[n][tc_offset], nSamplesAsked ); - } + p_output_sba[n] = output_sba[n]; } - if ( ( error = ivas_sba_dec_render( st_ivas, nSamplesAsked, nSamplesRendered, nSamplesAvailableNext, p_output ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_sba_dec_render( st_ivas, nSamplesAsked, nSamplesRendered, nSamplesAvailableNext, p_output_sba ) ) != IVAS_ERR_OK ) { return error; } if ( st_ivas->renderer_type != RENDERER_BINAURAL_FASTCONV_ROOM ) { - ivas_ism_render_sf( st_ivas, st_ivas->renderer_type, p_output_ism, *nSamplesRendered ); + ivas_ism_render_sf( st_ivas, st_ivas->renderer_type, p_output, *nSamplesRendered ); } for ( n = 0; n < st_ivas->hDecoderConfig->nchan_out; n++ ) { if ( st_ivas->renderer_type != RENDERER_BINAURAL_FASTCONV_ROOM ) { - v_add( p_output[n], p_output_ism[n], p_output[n], *nSamplesRendered ); + v_add( p_output[n], p_output_sba[n], p_output[n], *nSamplesRendered ); + } + else + { + mvr2r( p_output_sba[n], p_output[n], *nSamplesRendered ); } - -#ifndef NONBE_1352_HARMONIZE_OSBA_LOUDNESS - v_multc( p_output[n], 0.5f, p_output[n], *nSamplesRendered ); -#endif } return IVAS_ERR_OK; @@ -353,12 +329,6 @@ void ivas_osba_stereo_add_channels( } } -#ifndef NONBE_1352_HARMONIZE_OSBA_LOUDNESS - for ( n = 0; n < nchan_out; n++ ) - { - v_multc( output_f[n], 0.5f, output_f[n], n_samples_to_render ); - } -#endif return; } diff --git a/lib_dec/ivas_sba_dec.c b/lib_dec/ivas_sba_dec.c index 8ddc7f040616d8de7d70a4e2372ebf531c174cdd..72f42e458c882d9682c9c35d05d6860d2b807344 100644 --- a/lib_dec/ivas_sba_dec.c +++ b/lib_dec/ivas_sba_dec.c @@ -111,8 +111,7 @@ ivas_error ivas_sba_dec_reconfigure( int32_t ivas_total_brate; int32_t last_ivas_total_brate; int16_t num_channels, num_md_sub_frames; - int16_t nchan_out_buff, nchan_out_buff_old; - int16_t sba_analysis_order_old_flush; + int16_t nchan_out_buff; DECODER_CONFIG_HANDLE hDecoderConfig; ivas_error error; ISM_MODE ism_mode_old; @@ -123,15 +122,12 @@ ivas_error ivas_sba_dec_reconfigure( hDecoderConfig = st_ivas->hDecoderConfig; ivas_total_brate = hDecoderConfig->ivas_total_brate; last_ivas_total_brate = st_ivas->last_active_ivas_total_brate; - sba_analysis_order_old_flush = st_ivas->sba_analysis_order; /*-----------------------------------------------------------------* * Set SBA high-level parameters * Save old SBA high-level parameters *-----------------------------------------------------------------*/ - nchan_out_buff_old = ivas_get_nchan_buffers_dec( st_ivas, sba_analysis_order_old_flush, last_ivas_total_brate ); - ivas_init_dec_get_num_cldfb_instances( st_ivas, &numCldfbAnalyses_old, &numCldfbSyntheses_old ); nchan_hp20_old = getNumChanSynthesis( st_ivas ); @@ -166,6 +162,27 @@ ivas_error ivas_sba_dec_reconfigure( /* determine new granularity */ granularity_new = ivas_jbm_dec_get_render_granularity( st_ivas->renderer_type, ivas_renderer_secondary_select( st_ivas ), st_ivas->hDecoderConfig->output_Fs ); +#ifdef NONBE_1321_JBM_ASSERT_BITRATE_SWITCHING + /* flush renderer on granularity change form 5ms to 1.25ms, again only possible for binaural rendering */ + if ( granularity_new < st_ivas->hTcBuffer->n_samples_granularity ) + { + /* flush already done in IVAS_DEC_ReadFormat() */ + } + else if ( granularity_new > st_ivas->hTcBuffer->n_samples_granularity ) + { + if ( ( error = ivas_jbm_dec_set_discard_samples( st_ivas ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* make sure the changed number of slots in the last subframe is not lost in the following steps */ + if ( st_ivas->hSpatParamRendCom != NULL ) + { + st_ivas->hSpatParamRendCom->subframe_nbslots[st_ivas->hSpatParamRendCom->nb_subframes - 1] = st_ivas->hTcBuffer->subframe_nbslots[st_ivas->hTcBuffer->nb_subframes - 1]; + } + st_ivas->hSpar->subframe_nbslots[st_ivas->hSpar->nb_subframes - 1] = st_ivas->hTcBuffer->subframe_nbslots[st_ivas->hTcBuffer->nb_subframes - 1]; + } +#else if ( granularity_new > st_ivas->hTcBuffer->n_samples_granularity ) { /* make sure the changed number of slots in the last subframe is not lost in the following steps */ @@ -175,6 +192,7 @@ ivas_error ivas_sba_dec_reconfigure( } st_ivas->hSpar->subframe_nbslots[st_ivas->hSpar->nb_subframes - 1] = st_ivas->hTcBuffer->subframe_nbslots[st_ivas->hTcBuffer->nb_subframes - 1]; } +#endif } /* save old */ @@ -591,8 +609,7 @@ ivas_error ivas_sba_dec_reconfigure( *-----------------------------------------------------------------*/ nchan_out_buff = ivas_get_nchan_buffers_dec( st_ivas, st_ivas->sba_analysis_order, st_ivas->hDecoderConfig->ivas_total_brate ); - - if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff_old, nchan_out_buff ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_output_buff_dec( st_ivas->p_output_f, nchan_out_buff, hDecoderConfig->Opt_tsm, st_ivas->hTcBuffer ) ) != IVAS_ERR_OK ) { return error; } @@ -712,6 +729,12 @@ ivas_error ivas_sba_dec_render( { nchan_out = max( nchan_internal, st_ivas->hDecoderConfig->nchan_out - st_ivas->nchan_ism ); } +#ifdef FIX_1372_OSBA_OBJECT_EDITING + else if ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) + { + nchan_out = BINAURAL_CHANNELS; + } +#endif } nchan_out = min( nchan_out, ivas_get_nchan_buffers_dec( st_ivas, st_ivas->sba_analysis_order, st_ivas->hDecoderConfig->ivas_total_brate ) ); diff --git a/lib_dec/ivas_spar_decoder.c b/lib_dec/ivas_spar_decoder.c index 41319e9fe2c3d4732ec4a5d2008488b58cca7bd1..2a575c6177861e150e2ab390b3f993036a79afe9 100644 --- a/lib_dec/ivas_spar_decoder.c +++ b/lib_dec/ivas_spar_decoder.c @@ -1406,7 +1406,11 @@ void ivas_spar_dec_upmixer_sf( p_tc[i] = st_ivas->hTcBuffer->tc[i + nchan_ism] + slot_idx_start * slot_size; } +#ifdef FIX_1372_OSBA_OBJECT_EDITING + if ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) +#else if ( st_ivas->ivas_format == SBA_ISM_FORMAT && st_ivas->ism_mode == ISM_SBA_MODE_DISC && st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) +#endif { for ( i = 0; i < nchan_ism; i++ ) { diff --git a/lib_dec/ivas_stat_dec.h b/lib_dec/ivas_stat_dec.h index 282d798e4d66fac476e7efd50bf06fd0957a63a9..0f0ad4cedba35a0529c345d40c95669a80fb8a85 100644 --- a/lib_dec/ivas_stat_dec.h +++ b/lib_dec/ivas_stat_dec.h @@ -790,7 +790,7 @@ typedef struct ivas_lfe_dec_data_structure LFE_WINDOW_HANDLE pWindow_state; const uint16_t *cum_freq_models[IVAS_MAX_NUM_QUANT_STRATS][IVAS_MAX_NUM_DCT_COEF_GROUPS]; int16_t lfe_dec_indices_coeffs_tbl[IVAS_MAX_NUM_QUANT_STRATS][IVAS_MAX_NUM_DCT_COEF_GROUPS]; - float lfe_block_delay_s; + int32_t delay_ns; int16_t lfe_prior_buf_len; float prior_out_buffer[L_FRAME48k]; @@ -846,6 +846,7 @@ typedef struct } ISAR_DEC_SPLIT_REND_WRAPPER, *ISAR_DEC_SPLIT_REND_WRAPPER_HANDLE; + /*----------------------------------------------------------------------------------* * MASA decoder structures *----------------------------------------------------------------------------------*/ @@ -963,6 +964,8 @@ typedef struct decoder_tc_buffer_structure int16_t num_slots; int16_t n_samples_discard; /* number of samples to discard from the beginning of the output */ + float *tc_buffer2; /* non-scaled buffer of output audio - needed only when '*tc_buffer* is not long enough */ + } DECODER_TC_BUFFER, *DECODER_TC_BUFFER_HANDLE; typedef struct jbm_metadata_structure diff --git a/lib_dec/ivas_svd_dec.c b/lib_dec/ivas_svd_dec.c index 1d6282b39c3c34e982694f5ad349413cc5538246..12a98e87e954da5b1b676f6dab3a23541db55419 100644 --- a/lib_dec/ivas_svd_dec.c +++ b/lib_dec/ivas_svd_dec.c @@ -60,9 +60,9 @@ static float GivensRotation( const float x, const float z ); -static void biDiagonalReductionLeft( float singularVectors[][MAX_OUTPUT_CHANNELS], float singularValues[MAX_OUTPUT_CHANNELS], float secDiag[MAX_OUTPUT_CHANNELS], const int16_t nChannelsL, const int16_t nChannelsC, const int16_t currChannel, float *sig_x, float *g ); +static void biDiagonalReductionLeft( float singularVectors[][MAX_OUTPUT_CHANNELS], const int16_t nChannelsL, const int16_t nChannelsC, const int16_t currChannel, float *g ); -static void biDiagonalReductionRight( float singularVectors[][MAX_OUTPUT_CHANNELS], float secDiag[MAX_OUTPUT_CHANNELS], const int16_t nChannelsL, const int16_t nChannelsC, const int16_t currChannel, float *sig_x, float *g ); +static void biDiagonalReductionRight( float singularVectors[][MAX_OUTPUT_CHANNELS], const int16_t nChannelsL, const int16_t nChannelsC, const int16_t currChannel, float *g ); static void singularVectorsAccumulationLeft( float singularVectors_Left[][MAX_OUTPUT_CHANNELS], float singularValues[MAX_OUTPUT_CHANNELS], const int16_t nChannelsL, const int16_t nChannelsC ); @@ -489,13 +489,17 @@ static void HouseholderReduction( float *eps_x ) { int16_t nCh; - float g = 0.0f, sig_x = 0.0f; + float g_left = 0.0f; + float g_right = 0.0f; /* Bidiagonal Reduction for every channel */ for ( nCh = 0; nCh < nChannelsC; nCh++ ) /* nChannelsC */ { - biDiagonalReductionLeft( singularVectors_Left, singularValues, secDiag, nChannelsL, nChannelsC, nCh, &sig_x, &g ); - biDiagonalReductionRight( singularVectors_Left, secDiag, nChannelsL, nChannelsC, nCh, &sig_x, &g ); + secDiag[nCh] = g_right; /* from the previous channel */ + biDiagonalReductionLeft( singularVectors_Left, nChannelsL, nChannelsC, nCh, &g_left ); + singularValues[nCh] = g_left; + biDiagonalReductionRight( singularVectors_Left, nChannelsL, nChannelsC, nCh, &g_right ); + *eps_x = max( *eps_x, ( fabsf( singularValues[nCh] ) + fabsf( secDiag[nCh] ) ) ); } @@ -515,49 +519,36 @@ static void HouseholderReduction( static void biDiagonalReductionLeft( float singularVectors[][MAX_OUTPUT_CHANNELS], - float singularValues[MAX_OUTPUT_CHANNELS], - float secDiag[MAX_OUTPUT_CHANNELS], const int16_t nChannelsL, const int16_t nChannelsC, const int16_t currChannel, - float *sig_x, float *g ) { - int16_t iCh, jCh, idx; + int16_t iCh, jCh; float norm_x, f, r; - secDiag[currChannel] = ( *sig_x ) * ( *g ); - /* Setting values to 0 */ - ( *sig_x ) = 0.0f; ( *g ) = 0.0f; if ( currChannel < nChannelsL ) /* i <= m */ { - idx = currChannel; + norm_x = 0.0f; - for ( jCh = idx; jCh < nChannelsL; jCh++ ) /* nChannelsL */ + for ( jCh = currChannel; jCh < nChannelsL; jCh++ ) /* nChannelsL */ { - ( *sig_x ) += fabsf( singularVectors[jCh][currChannel] ); + norm_x += ( singularVectors[jCh][currChannel] * singularVectors[jCh][currChannel] ); } - if ( ( *sig_x ) ) /*(fabsf(*sig_x) > EPSILON * fabsf(*sig_x)) { */ + if ( ( norm_x ) ) /*(fabsf(*sig_x) > EPSILON * fabsf(*sig_x)) { */ { - norm_x = 0.0f; - - for ( jCh = idx; jCh < nChannelsL; jCh++ ) /* nChannelsL */ - { - singularVectors[jCh][currChannel] = ( singularVectors[jCh][currChannel] / maxWithSign( ( *sig_x ) ) ); - norm_x += ( singularVectors[jCh][currChannel] * singularVectors[jCh][currChannel] ); - } - ( *g ) = -( singularVectors[currChannel][idx] >= 0 ? 1 : ( -1 ) ) * sqrtf( norm_x ); - r = ( *g ) * singularVectors[currChannel][idx] - norm_x; - singularVectors[currChannel][idx] = ( singularVectors[currChannel][idx] - ( *g ) ); + ( *g ) = -( singularVectors[currChannel][currChannel] >= 0 ? 1 : ( -1 ) ) * sqrtf( norm_x ); + r = ( *g ) * singularVectors[currChannel][currChannel] - norm_x; + singularVectors[currChannel][currChannel] = ( singularVectors[currChannel][currChannel] - ( *g ) ); for ( iCh = currChannel + 1; iCh < nChannelsC; iCh++ ) /* nChannelsC */ { norm_x = 0.0f; - for ( jCh = idx; jCh < nChannelsL; jCh++ ) /* nChannelsL */ + for ( jCh = currChannel; jCh < nChannelsL; jCh++ ) /* nChannelsL */ { norm_x += ( singularVectors[jCh][currChannel] * singularVectors[jCh][iCh] ); } @@ -565,20 +556,12 @@ static void biDiagonalReductionLeft( f = norm_x / maxWithSign( r ); - for ( jCh = idx; jCh < nChannelsL; jCh++ ) /* nChannelsL */ + for ( jCh = currChannel; jCh < nChannelsL; jCh++ ) /* nChannelsL */ { singularVectors[jCh][iCh] += ( f * singularVectors[jCh][currChannel] ); } } - - - for ( jCh = idx; jCh < nChannelsL; jCh++ ) /* nChannelsL */ - { - singularVectors[jCh][currChannel] = ( singularVectors[jCh][currChannel] * ( *sig_x ) ); - } } - - singularValues[currChannel] = ( ( *sig_x ) * ( *g ) ); } return; @@ -593,47 +576,34 @@ static void biDiagonalReductionLeft( static void biDiagonalReductionRight( float singularVectors[][MAX_OUTPUT_CHANNELS], - float secDiag[MAX_OUTPUT_CHANNELS], const int16_t nChannelsL, const int16_t nChannelsC, const int16_t currChannel, - float *sig_x, float *g ) { int16_t iCh, jCh, idx; float norm_x, r; /* Setting values to 0 */ - ( *sig_x ) = 0.0f; ( *g ) = 0.0f; if ( currChannel < nChannelsL && currChannel != ( nChannelsC - 1 ) ) /* i <=m && i !=n */ { idx = currChannel + 1; - for ( jCh = idx; jCh < nChannelsC; jCh++ ) /* nChannelsC */ + norm_x = 0.0f; + + for ( jCh = idx; jCh < nChannelsC; jCh++ ) /*nChannelsC */ { - ( *sig_x ) += fabsf( singularVectors[currChannel][jCh] ); + norm_x += ( singularVectors[currChannel][jCh] * singularVectors[currChannel][jCh] ); } - if ( ( *sig_x ) ) /*(fabsf(*sig_x) > EPSILON * fabsf(*sig_x)) { */ + if ( norm_x ) /*(fabsf(*sig_x) > EPSILON * fabsf(*sig_x)) { */ { - norm_x = 0.0f; - - for ( jCh = idx; jCh < nChannelsC; jCh++ ) /*nChannelsC */ - { - singularVectors[currChannel][jCh] = ( singularVectors[currChannel][jCh] / maxWithSign( ( *sig_x ) ) ); - norm_x += ( singularVectors[currChannel][jCh] * singularVectors[currChannel][jCh] ); - } ( *g ) = -( singularVectors[currChannel][idx] >= 0 ? 1 : ( -1 ) ) * sqrtf( norm_x ); r = ( *g ) * singularVectors[currChannel][idx] - norm_x; singularVectors[currChannel][idx] = ( singularVectors[currChannel][idx] - ( *g ) ); - for ( jCh = idx; jCh < nChannelsC; jCh++ ) /* nChannelsC */ - { - secDiag[jCh] = singularVectors[currChannel][jCh] / maxWithSign( r ); - } - for ( iCh = currChannel + 1; iCh < nChannelsL; iCh++ ) /* nChannelsL */ { norm_x = 0.0f; @@ -641,17 +611,12 @@ static void biDiagonalReductionRight( { norm_x += ( singularVectors[iCh][jCh] * singularVectors[currChannel][jCh] ); } - + norm_x /= r; for ( jCh = idx; jCh < nChannelsC; jCh++ ) /* nChannelsC */ { - singularVectors[iCh][jCh] += ( norm_x * secDiag[jCh] ); + singularVectors[iCh][jCh] += ( norm_x * singularVectors[currChannel][jCh] ); } } - - for ( jCh = idx; jCh < nChannelsC; jCh++ ) /* nChannelsC */ - { - singularVectors[currChannel][jCh] = ( singularVectors[currChannel][jCh] * ( *sig_x ) ); - } } } diff --git a/lib_dec/jbm_pcmdsp_apa.c b/lib_dec/jbm_pcmdsp_apa.c index 0c0b478a1b4f5fc58bc090a19611b978931cc36e..84dd867403bf40dd1df5e19528dc5276d0cb6cbe 100644 --- a/lib_dec/jbm_pcmdsp_apa.c +++ b/lib_dec/jbm_pcmdsp_apa.c @@ -725,6 +725,17 @@ uint8_t apa_exec( ps->nFramesSinceSetScale >>= statsResetShift; } +#ifdef DEBUG_APA_SILENCE_NON_SCALED + if ( l_in == *l_out ) + { + set_zero( a_out, *l_out ); + } + else + { + set_f( a_out, (float) INT16_MAX, *l_out ); + } +#endif + return 0; } diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 0e04971fc390a79cb44ed93ef9629b80dfa555e7..41feeafec2cb0add778f6379f96d2170430007a7 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -1080,6 +1080,7 @@ ivas_error IVAS_DEC_ReadFormat( return error; } } +#ifndef NONBE_1321_JBM_ASSERT_BITRATE_SWITCHING /* when granularity goes up, discard samples at the beginning of the frame */ else if ( tc_granularity_new > st_ivas->hTcBuffer->n_samples_granularity ) { @@ -1088,6 +1089,7 @@ ivas_error IVAS_DEC_ReadFormat( return error; } } +#endif } } diff --git a/lib_enc/acelp_core_enc.c b/lib_enc/acelp_core_enc.c index 535a52430ebcf3d24c780fe89e8dd6ca8f2ea651..33bef3e67a26bc212898ab133ba1c5a5ad420f4a 100644 --- a/lib_enc/acelp_core_enc.c +++ b/lib_enc/acelp_core_enc.c @@ -695,7 +695,12 @@ ivas_error acelp_core_enc( if ( !st->Opt_SC_VBR && ( st->idchan == 0 || st->element_mode != IVAS_CPE_TD || ( st->idchan == 1 && st->element_mode == IVAS_CPE_TD && st->tdm_LRTD_flag ) ) ) { /* Apply a non linearity to the SHB excitation */ - non_linearity( bwe_exc, bwe_exc_extended, st->hBWE_TD->old_bwe_exc_extended, L_FRAME32k, &st->hBWE_TD->bwe_non_lin_prev_scale, st->coder_type, voice_factors, st->L_frame ); + non_linearity( bwe_exc, bwe_exc_extended, st->hBWE_TD->old_bwe_exc_extended, L_FRAME32k, &st->hBWE_TD->bwe_non_lin_prev_scale, st->coder_type, voice_factors, st->L_frame +#ifdef NONBE_1328_FIX_NON_LINEARITY + , + st->element_mode +#endif + ); } if ( st->core_brate == SID_2k40 || st->core_brate == FRAME_NO_DATA ) diff --git a/lib_enc/enc_acelp_tcx_main.c b/lib_enc/enc_acelp_tcx_main.c index 6ede9b9bf18b75a00fcb10e70c379746b0da5e6a..8851d9be5e0c358e9470583a923ad7836d14c09b 100644 --- a/lib_enc/enc_acelp_tcx_main.c +++ b/lib_enc/enc_acelp_tcx_main.c @@ -99,7 +99,12 @@ void enc_acelp_tcx_main( /* Apply non linearity to the SHB excitation */ if ( st->core == ACELP_CORE && st->igf ) { - non_linearity( ptr_bwe_exc, bwe_exc_extended, st->hBWE_TD->old_bwe_exc_extended, L_FRAME32k, &st->hBWE_TD->bwe_non_lin_prev_scale, st->coder_type, voice_factors, st->L_frame ); + non_linearity( ptr_bwe_exc, bwe_exc_extended, st->hBWE_TD->old_bwe_exc_extended, L_FRAME32k, &st->hBWE_TD->bwe_non_lin_prev_scale, st->coder_type, voice_factors, st->L_frame +#ifdef NONBE_1328_FIX_NON_LINEARITY + , + st->element_mode +#endif + ); /* update the old_BWE_exc memory */ mvr2r( &old_bwe_exc[L_FRAME32k], st->hBWE_TD->old_bwe_exc, PIT16k_MAX * 2 ); diff --git a/lib_enc/hq_lr_enc.c b/lib_enc/hq_lr_enc.c index 65b5dd4ef5b3a37deeae00c7a6a382ad2ae8f416..13637fdbd2873f7c1c7b4a7ccc854ee4d6b2511b 100644 --- a/lib_enc/hq_lr_enc.c +++ b/lib_enc/hq_lr_enc.c @@ -336,7 +336,11 @@ void hq_lr_enc( frac1 = L_Extract_lc( L_tmp, &exp ); /* Extract exponent of L_tmp */ L_tmp = Pow2( 30, frac1 ); exp = sub( exp, 30 ); - Ep_fx[i] = L_shl( L_tmp, sub( exp, 6 ) ); /* Q -6 */ +#ifdef BASOP_NOGLOB + Ep_fx[i] = L_shl_o( L_tmp, s_max( sub( exp, 6 ), -31 ), &Overflow ); /* Q -6 */ +#else + Ep_fx[i] = L_shl( L_tmp, s_max( sub( exp, 6 ), -31 ) ); /* Q -6 */ +#endif Ep[i] = (float) ( Ep_fx[i] / pow( 2.0, -6 ) ); } diff --git a/lib_isar/isar_lc3plus_common.c b/lib_isar/isar_lc3plus_common.c index 4236c9ced7cc64a4615b798d79b0ab1a0ac14300..a186908990ca5366ef81bb6e5a5b53c8726eb6fc 100644 --- a/lib_isar/isar_lc3plus_common.c +++ b/lib_isar/isar_lc3plus_common.c @@ -33,7 +33,7 @@ #include "options.h" #include "isar_lc3plus_common.h" #include "ivas_error.h" -#include "lc3.h" +#include "lc3plus.h" /*-----------------------------------------------------------------------------------------* * Function ISAR_LC3PLUS_LC3plusErrToIvasErr() diff --git a/lib_isar/isar_lc3plus_common.h b/lib_isar/isar_lc3plus_common.h index b99348e0ed33b2269ce7e5b9e41d2715c8102712..eb3e7b0ad2d7d245c046cd7fc7699d7a178b8b78 100644 --- a/lib_isar/isar_lc3plus_common.h +++ b/lib_isar/isar_lc3plus_common.h @@ -37,7 +37,7 @@ #include #include "options.h" #include "ivas_error.h" -#include "lc3.h" +#include "lc3plus.h" #include "isar_lc3plus_payload.h" /*! common configuration parameters between encoder and decoder */ diff --git a/lib_isar/isar_lc3plus_dec.c b/lib_isar/isar_lc3plus_dec.c index 560f34f1c46077a88416829e3c748c11caf75e2b..c5d78f444684b1433894114ea9f1377ee9a49e4b 100644 --- a/lib_isar/isar_lc3plus_dec.c +++ b/lib_isar/isar_lc3plus_dec.c @@ -36,7 +36,7 @@ #include "ivas_prot.h" #include "isar_lc3plus_dec.h" #include "isar_lc3plus_common.h" -#include "lc3.h" +#include "lc3plus.h" #include "ivas_error_utils.h" #include "wmc_auto.h" diff --git a/lib_isar/isar_lc3plus_dec.h b/lib_isar/isar_lc3plus_dec.h index 82b9e51e1948a81bed58b6e63dbb49b88a5033d0..d5cb37aaa917dfc2dc004a1ca7b64a6ad6eb3d20 100644 --- a/lib_isar/isar_lc3plus_dec.h +++ b/lib_isar/isar_lc3plus_dec.h @@ -35,7 +35,7 @@ #include #include "options.h" -#include "lc3.h" +#include "lc3plus.h" #include "ivas_error.h" #include "ivas_cnst.h" #include "isar_lc3plus_common.h" diff --git a/lib_isar/isar_lc3plus_enc.c b/lib_isar/isar_lc3plus_enc.c index 62a803f38fc4c72e08084c22905c7d6f00561cbc..c6e2d31334271169367f7f0695806256a7f4c049 100644 --- a/lib_isar/isar_lc3plus_enc.c +++ b/lib_isar/isar_lc3plus_enc.c @@ -32,7 +32,7 @@ #include "isar_lc3plus_enc.h" #include "isar_lc3plus_common.h" -#include "lc3.h" +#include "lc3plus.h" #include "ivas_error_utils.h" #include "prot.h" #include "wmc_auto.h" diff --git a/lib_isar/isar_lc3plus_enc.h b/lib_isar/isar_lc3plus_enc.h index 9c80033fd36a9d7fea205bd63bb9497611131167..ed6c526011d7a4861dd040ae4d6b3696437aa578 100644 --- a/lib_isar/isar_lc3plus_enc.h +++ b/lib_isar/isar_lc3plus_enc.h @@ -35,7 +35,7 @@ #include #include "ivas_error.h" -#include "lc3.h" +#include "lc3plus.h" #include "isar_lc3plus_common.h" #include "isar_lc3plus_payload.h" diff --git a/lib_isar/isar_lc3plus_payload.h b/lib_isar/isar_lc3plus_payload.h index e95128578493f5561fdcb2292aef37f0c202e428..580a58ca651defe96eeb84229b8f07b3407a756c 100644 --- a/lib_isar/isar_lc3plus_payload.h +++ b/lib_isar/isar_lc3plus_payload.h @@ -35,7 +35,7 @@ #include #include -#include "lc3.h" +#include "lc3plus.h" #include "options.h" diff --git a/lib_isar/lib_isar_pre_rend.c b/lib_isar/lib_isar_pre_rend.c index 09323f6eedf08d3900bde17cb70a27a71e8be582..d24bc94de7411889db57dd0757fbd50945d41dcf 100644 --- a/lib_isar/lib_isar_pre_rend.c +++ b/lib_isar/lib_isar_pre_rend.c @@ -53,8 +53,8 @@ *------------------------------------------------------------------------*/ ivas_error ISAR_PRE_REND_open( - SPLIT_REND_WRAPPER *hSplitBinRend, /* i/o: Split renderer pre-renerer handle */ - ISAR_SPLIT_REND_CONFIG_DATA *pSplitRendConfig, /* i/o: Split renderer pre-renerer config */ + SPLIT_REND_WRAPPER *hSplitBinRend, /* i/o: Split renderer pre-renderer handle */ + ISAR_SPLIT_REND_CONFIG_DATA *pSplitRendConfig, /* i/o: Split renderer pre-renderer config */ const int32_t output_Fs, /* i : output sampling rate */ const int16_t cldfb_in_flag, /* i : Flag to indicate CLDFB or time doamin input */ const int16_t pcm_out_flag, /* i : Flag to indicate PCM output */ @@ -94,9 +94,7 @@ ivas_error ISAR_PRE_REND_open( isCldfbNeeded = 1; } - hSplitBinRend->hCldfbHandles = NULL; - - if ( isCldfbNeeded ) + if ( isCldfbNeeded && hSplitBinRend->hCldfbHandles == NULL ) { if ( ( hSplitBinRend->hCldfbHandles = (CLDFB_HANDLES_WRAPPER_HANDLE) malloc( sizeof( CLDFB_HANDLES_WRAPPER ) ) ) == NULL ) { @@ -286,7 +284,7 @@ ivas_error ISAR_PRE_REND_MultiBinToSplitBinaural( const int16_t max_bands, /* i : CLDFB bands */ float *output[], /* i/o: PCM in/out buffer */ const int16_t low_res_pre_rend_rot, /* i : low time resolution pre-renderer flag */ - const int16_t cldfb_in_flag, /* i : Flag to indicate CLDFB or time doamin input */ + const int16_t cldfb_in_flag, /* i : Flag to indicate CLDFB or time domain input */ const int16_t pcm_out_flag, /* i : Flag to indicate PCM output */ const int16_t ro_md_flag /* i : Flag to indicate real only metadata for yaw */ ) diff --git a/lib_lc3plus/functions.h b/lib_lc3plus/functions.h index 46daa64bf3f3757f8f546a4c2d5c878a7924eb2b..a2f4857b2ae4a3d10511b5e08249d95a73634be4 100644 --- a/lib_lc3plus/functions.h +++ b/lib_lc3plus/functions.h @@ -15,9 +15,9 @@ #include "clib.h" #include "defines.h" #include "float.h" -#include "lc3.h" -#include "setup_dec_lc3.h" -#include "setup_enc_lc3.h" +#include "lc3plus.h" +#include "setup_dec_lc3plus.h" +#include "setup_enc_lc3plus.h" #include "structs.h" #include "util.h" diff --git a/lib_lc3plus/lc3plus.c b/lib_lc3plus/lc3plus.c new file mode 100644 index 0000000000000000000000000000000000000000..d208cfb1512bfd8a028e01bca5b8db1bfa0efbfa --- /dev/null +++ b/lib_lc3plus/lc3plus.c @@ -0,0 +1,438 @@ +/****************************************************************************** +* ETSI TS 103 634 V1.5.1 * +* Low Complexity Communication Codec Plus (LC3plus) * +* * +* Copyright licence is solely granted through ETSI Intellectual Property * +* Rights Policy, 3rd April 2019. No patent licence is granted by implication, * +* estoppel or otherwise. * +******************************************************************************/ + +#include "options.h" +#include "wmc_auto.h" +#include "lc3plus.h" +#include "defines.h" +#include "functions.h" +#include + +#include "setup_dec_lc3plus.h" +#include "setup_enc_lc3plus.h" + +#define RETURN_IF(cond, error) \ + if (cond) \ + return (error) + +/* ensure api header constants are up to date */ +STATIC_ASSERT(LC3PLUS_MAX_SAMPLES >= MAX_LEN); +STATIC_ASSERT(LC3PLUS_MAX_CHANNELS >= MAX_CHANNELS); +STATIC_ASSERT(LC3PLUS_MAX_BYTES >= BYTESBUFSIZE); + +/* misc functions ************************************************************/ + +int lc3plus_version(void) +{ + return LC3PLUS_VERSION; +} + +int lc3plus_channels_supported(int channels) +{ + return channels >= 1 && channels <= MAX_CHANNELS; +} + +int lc3plus_samplerate_supported(int samplerate) +{ + switch (samplerate) + { + case 8000: return 1; + case 16000: return 1; + case 24000: return 1; + case 32000: return 1; + case 44100: return 1; + case 48000: return 1; + case 96000: return 1; + default: break; + } + return 0; +} + +static int lc3plus_plc_mode_supported(LC3PLUS_PlcMode plc_mode) +{ + switch ((int)plc_mode) + { + case LC3PLUS_PLC_ADVANCED: /* fallthru */ + return 1; + default: break; + } + return 0; +} + +static int lc3plus_frame_size_supported(float frame_ms) +{ + switch ((int)(ceil(frame_ms * 10))) + { + case 25: /* fallthru */ + case 50: /* fallthru */ + case 75: /* fallthru */ + case 100: return 1; + default: break; + } + return 0; +} + +static int null_in_list(void **list, int n) +{ + while (--n >= 0) + RETURN_IF(list[n] == NULL, 1); + return 0; +} + +/* return pointer to aligned base + base_size, *base_size += size + 4 bytes align */ +void *balloc(void *base, size_t *base_size, size_t size) +{ + uintptr_t ptr = ((uintptr_t)base + *base_size + 3) & (uintptr_t)(~3); + assert((uintptr_t)base % 4 == 0); /* base must be 4-byte aligned */ + *base_size = (*base_size + size + 3) & (uintptr_t)(~3); + return (void *)ptr; +} + +int32_t lc3_enc_supported_lfe(void) +{ + return 1; +} + +/* encoder functions *********************************************************/ +LC3PLUS_Error lc3plus_enc_init(LC3PLUS_Enc *encoder, int samplerate, int channels, int hrmode, int32_t lfe_channel_array[]) +{ + int ch = 0; + RETURN_IF(encoder == NULL, LC3PLUS_NULL_ERROR); + RETURN_IF((uintptr_t)encoder % 4 != 0, LC3PLUS_ALIGN_ERROR); + RETURN_IF(!lc3plus_samplerate_supported(samplerate), LC3PLUS_SAMPLERATE_ERROR); + RETURN_IF(!lc3plus_channels_supported(channels), LC3PLUS_CHANNELS_ERROR); + RETURN_IF(samplerate==96000 && hrmode == 0, LC3PLUS_HRMODE_ERROR); + + if (lfe_channel_array != NULL) + { + for (ch = 0; ch < channels; ch++) + { + RETURN_IF(!lc3_enc_supported_lfe() && lfe_channel_array[ch], LC3PLUS_LFE_MODE_NOT_SUPPORTED); + } + } + + return FillEncSetup(encoder, samplerate, channels, hrmode, lfe_channel_array); /* real bitrate check happens here */ +} + +int lc3plus_enc_get_size(int samplerate, int channels) +{ + RETURN_IF(!lc3plus_samplerate_supported(samplerate), 0); + RETURN_IF(!lc3plus_channels_supported(channels), 0); + return alloc_encoder(NULL, channels); +} + +/* Dummy function for API alignment */ +int lc3plus_enc_get_scratch_size(const LC3PLUS_Enc *encoder) +{ + UNUSED(encoder); + return 0; +} + +int lc3plus_enc_get_input_samples(const LC3PLUS_Enc *encoder) +{ + RETURN_IF(encoder == NULL, 0); + return encoder->frame_length; +} + +int lc3plus_enc_get_num_bytes(const LC3PLUS_Enc *encoder) +{ + RETURN_IF(encoder == NULL, 0); + + return encoder->bitrate * encoder->frame_length / (8 * encoder->fs_in); +} + +int lc3plus_enc_get_real_bitrate(const LC3PLUS_Enc *encoder) +{ + int ch = 0, totalBytes = 0; + int bitrate; + RETURN_IF(encoder == NULL, 0); + RETURN_IF(!encoder->lc3_br_set, LC3PLUS_BITRATE_UNSET_ERROR); + + for (ch = 0; ch < encoder->channels; ch++) + { + totalBytes += encoder->channel_setup[ch]->targetBytes; + } + + bitrate = (totalBytes * 80000.0 + encoder->frame_dms - 1) / encoder->frame_dms; + + if (encoder->fs_in == 44100) + { + int rem = bitrate % 480; + bitrate = ((bitrate - rem) / 480) * 441 + (rem * 441) / 480; + } + + return bitrate; +} + + +LC3PLUS_Error lc3plus_enc_set_bitrate(LC3PLUS_Enc *encoder, int bitrate) +{ + RETURN_IF(encoder == NULL, LC3PLUS_NULL_ERROR); + RETURN_IF(bitrate <= 0, LC3PLUS_BITRATE_ERROR); +#ifndef STRIP_HR_MODE_API + RETURN_IF(encoder->fs_idx == 5 && encoder->hrmode == 0, LC3PLUS_HRMODE_ERROR); +#endif + return update_enc_bitrate(encoder, bitrate); +} + +int lc3plus_enc_get_delay(const LC3PLUS_Enc *encoder) +{ + RETURN_IF(encoder == NULL, 0); + return encoder->frame_length - 2 * encoder->la_zeroes; +} + +LC3PLUS_Error lc3plus_enc_set_frame_dms(LC3PLUS_Enc *encoder, int frame_dms) +{ + RETURN_IF(encoder == NULL, LC3PLUS_NULL_ERROR); + RETURN_IF(!lc3plus_frame_size_supported(frame_dms / 10.0), LC3PLUS_FRAMEMS_ERROR); + RETURN_IF(encoder->lc3_br_set, LC3PLUS_BITRATE_SET_ERROR); + encoder->frame_dms = frame_dms; + encoder->frame_ms = frame_dms / 10.0; + set_enc_frame_params(encoder); + return LC3PLUS_OK; +} + +LC3PLUS_Error lc3plus_enc_set_bandwidth(LC3PLUS_Enc *encoder, int bandwidth) +{ + LC3_INT effective_fs; + RETURN_IF(encoder == NULL, LC3PLUS_NULL_ERROR); +#ifdef ENABLE_HR_MODE_FL_FLAG + RETURN_IF(encoder->hrmode == 1, LC3PLUS_HRMODE_BW_ERROR); +#endif + effective_fs = encoder->fs_in; + if (encoder->bandwidth != bandwidth) { + if (encoder->fs_in > 40000) { + effective_fs = 40000; + } + if ((bandwidth * 2) > effective_fs) { + return LC3PLUS_BW_WARNING; + } + else { + encoder->bandwidth = bandwidth; + encoder->bandwidth_preset = bandwidth; + encoder->bw_ctrl_active = 1; + update_enc_bitrate(encoder, encoder->bitrate); + } + } + return LC3PLUS_OK; +} + + +LC3PLUS_Error lc3plus_enc16(LC3PLUS_Enc* encoder, int16_t** input_samples, void* output_bytes, int* num_bytes +, void *scratch +) +{ + UNUSED(scratch); + return lc3plus_enc_fl(encoder, (void**)input_samples, 16, output_bytes, num_bytes); +} + +LC3PLUS_Error lc3plus_enc24(LC3PLUS_Enc* encoder, int32_t** input_samples, void* output_bytes, int* num_bytes +, void *scratch +) +{ + UNUSED(scratch); + return lc3plus_enc_fl(encoder, (void**)input_samples, 24, output_bytes, num_bytes); +} + + +LC3PLUS_Error lc3plus_enc_fl(LC3PLUS_Enc* encoder, void** input_samples, int bitdepth, void* output_bytes, int* num_bytes) +{ + RETURN_IF(!encoder || !input_samples || !output_bytes || !num_bytes, LC3PLUS_NULL_ERROR); + RETURN_IF(null_in_list(input_samples, encoder->channels), LC3PLUS_NULL_ERROR); + RETURN_IF(bitdepth != 16 && bitdepth != 24, LC3PLUS_ERROR); + *num_bytes = Enc_LC3PLUS_fl(encoder, input_samples, output_bytes, bitdepth + , *num_bytes == -1 + ); + assert(*num_bytes == lc3plus_enc_get_num_bytes(encoder)); + return LC3PLUS_OK; +} + +/* decoder functions *********************************************************/ + +LC3PLUS_Error lc3plus_dec_init(LC3PLUS_Dec* decoder, int samplerate, int channels, LC3PLUS_PlcMode plc_mode, int hrmode) +{ + RETURN_IF(decoder == NULL, LC3PLUS_NULL_ERROR); + RETURN_IF(!lc3plus_samplerate_supported(samplerate), LC3PLUS_SAMPLERATE_ERROR); + RETURN_IF(!lc3plus_channels_supported(channels), LC3PLUS_CHANNELS_ERROR); + RETURN_IF(!lc3plus_plc_mode_supported(plc_mode), LC3PLUS_PLCMODE_ERROR); + RETURN_IF(samplerate==96000 && hrmode == 0, LC3PLUS_HRMODE_ERROR); + return FillDecSetup(decoder, samplerate, channels, plc_mode, hrmode); +} + +int lc3plus_dec_get_size(int samplerate, int channels) +{ + RETURN_IF(!lc3plus_samplerate_supported(samplerate), 0); + RETURN_IF(!lc3plus_channels_supported(channels), 0); + return alloc_decoder(NULL, samplerate, channels); +} + +/* Dummy function for API alignment */ +int lc3plus_dec_get_scratch_size(const LC3PLUS_Dec *decoder) +{ + UNUSED(decoder); + return 0; +} + +LC3PLUS_Error lc3plus_dec_set_frame_dms(LC3PLUS_Dec *decoder, int frame_dms) +{ + RETURN_IF(decoder == NULL, LC3PLUS_NULL_ERROR); + RETURN_IF(!lc3plus_frame_size_supported(frame_dms / 10.0), LC3PLUS_FRAMEMS_ERROR); + RETURN_IF(decoder->plcMeth == 2 && frame_dms != 100, LC3PLUS_FRAMEMS_ERROR); + + decoder->frame_dms = frame_dms; + decoder->frame_ms = frame_dms / 10.0; + set_dec_frame_params(decoder); + return LC3PLUS_OK; +} + +int lc3plus_dec_get_output_samples(const LC3PLUS_Dec* decoder) +{ + RETURN_IF(decoder == NULL, 0); + return decoder->frame_length; +} + +int lc3plus_dec_get_delay(const LC3PLUS_Dec* decoder) +{ + RETURN_IF(decoder == NULL, 0); + return decoder->frame_length - 2 * decoder->la_zeroes; +} + +LC3PLUS_Error lc3plus_dec_fl(LC3PLUS_Dec* decoder, void* input_bytes, int num_bytes, void** output_samples, int bps, int bfi_ext) +{ + if (bfi_ext == 1) + { + RETURN_IF(!decoder || !output_samples, LC3PLUS_NULL_ERROR); + } else { + RETURN_IF(!decoder || !input_bytes || !output_samples, LC3PLUS_NULL_ERROR); + } + + RETURN_IF(null_in_list((void**)output_samples, decoder->channels), LC3PLUS_NULL_ERROR); + return Dec_LC3PLUS_fl(decoder, input_bytes, num_bytes, output_samples, bps, bfi_ext); +} + +LC3PLUS_Error lc3plus_dec16(LC3PLUS_Dec* decoder, void* input_bytes, int num_bytes, int16_t** output_samples, + void* scratch, + int bfi_ext) +{ + UNUSED(scratch); + return lc3plus_dec_fl(decoder, input_bytes, num_bytes, (void**)output_samples, 16, bfi_ext); +} + +LC3PLUS_Error lc3plus_dec24(LC3PLUS_Dec* decoder, void* input_bytes, int num_bytes, int32_t** output_samples, + void* scratch, + int bfi_ext) +{ + UNUSED(scratch); + return lc3plus_dec_fl(decoder, input_bytes, num_bytes, (void**)output_samples, 24, bfi_ext); +} + +/* memory functions *********************************************************/ + +LC3PLUS_Error lc3plus_enc_free_memory(LC3PLUS_Enc* encoder) +{ + RETURN_IF(!encoder, LC3PLUS_NULL_ERROR); + + lc3plus_free_encoder_structs(encoder); + + return LC3PLUS_OK; +} + +LC3PLUS_Error lc3plus_dec_free_memory(LC3PLUS_Dec* decoder) +{ + RETURN_IF(!decoder, LC3PLUS_NULL_ERROR); + + lc3plus_free_decoder_structs(decoder); + + return LC3PLUS_OK; +} + +LC3PLUS_Error lc3plus_free_encoder_structs(LC3PLUS_Enc* encoder) +{ + int ch = 0; + RETURN_IF(!encoder, LC3PLUS_NULL_ERROR); + + for (ch = 0; ch < encoder->channels; ch++) { + mdct_free(&encoder->channel_setup[ch]->mdctStruct); + dct2_free(&encoder->channel_setup[ch]->dct2StructSNS); + } + + return LC3PLUS_OK; +} + +LC3PLUS_Error lc3plus_free_decoder_structs(LC3PLUS_Dec* decoder) +{ + int ch = 0; + RETURN_IF(!decoder, LC3PLUS_NULL_ERROR); + + for (ch = 0; ch < decoder->channels; ch++) { + dct4_free(&decoder->channel_setup[ch]->dct4structImdct); + real_fft_free(&decoder->channel_setup[ch]->PlcAdvSetup->PlcPhEcuSetup.PhEcu_Fft); + real_fft_free(&decoder->channel_setup[ch]->PlcAdvSetup->PlcPhEcuSetup.PhEcu_Ifft); + } + + return LC3PLUS_OK; +} + + +LC3PLUS_EpModeRequest lc3plus_dec_get_ep_mode_request(const LC3PLUS_Dec *decoder) +{ + RETURN_IF(decoder == NULL, LC3PLUS_EPMR_ZERO); + return (LC3PLUS_EpModeRequest)decoder->epmr; +} + +int lc3plus_dec_get_error_report(const LC3PLUS_Dec *decoder) +{ + RETURN_IF(decoder == NULL, 0); + return decoder->error_report == 2047 ? -1 : decoder->error_report & 0x07FF; +} + +LC3PLUS_Error lc3plus_enc_set_ep_mode(LC3PLUS_Enc *encoder, LC3PLUS_EpMode epmode) +{ + LC3PLUS_EpMode oldEpmode; + LC3PLUS_Error error; + RETURN_IF(encoder == NULL, LC3PLUS_NULL_ERROR); + RETURN_IF((unsigned)epmode > LC3PLUS_EP_HIGH, LC3PLUS_EPMODE_ERROR); + oldEpmode = encoder->epmode; + encoder->epmode = epmode; + error = encoder->lc3_br_set ? update_enc_bitrate(encoder, encoder->bitrate) : LC3PLUS_OK; + if (error != LC3PLUS_OK) + { + encoder->epmode = oldEpmode; // preserve old epmode in case of failure + } + return error; +} + +LC3PLUS_Error lc3plus_enc_set_ep_mode_request(LC3PLUS_Enc *encoder, LC3PLUS_EpModeRequest epmr) +{ + RETURN_IF(encoder == NULL, LC3PLUS_NULL_ERROR); + RETURN_IF((unsigned)epmr > LC3PLUS_EPMR_HIGH, LC3PLUS_EPMODE_ERROR); + encoder->epmr = epmr; + return LC3PLUS_OK; +} + +LC3PLUS_Error lc3plus_dec_set_ep_enabled(LC3PLUS_Dec *decoder, int32_t ep_enabled) +{ + RETURN_IF(decoder == NULL, LC3PLUS_NULL_ERROR); + decoder->ep_enabled = ep_enabled != 0; + decoder->epmr = LC3PLUS_EPMR_ZERO; + return LC3PLUS_OK; +} + +int lc3plus_dec_get_epok_flags(const LC3PLUS_Dec *decoder) +{ + RETURN_IF(decoder == NULL, 0); + return decoder->error_report >> 11; +} + +#ifndef STRIP_ERROR_PROTECTION_API_FL +#endif /* STRIP_ERROR_PROTECTION_API_FL */ + +#ifndef STRIP_ERROR_PROTECTION_API_FL +#endif /* STRIP_ERROR_PROTECTION_API_FL */ + diff --git a/lib_lc3plus/lc3plus.h b/lib_lc3plus/lc3plus.h new file mode 100644 index 0000000000000000000000000000000000000000..063714467da07d43f63d214cbfcec5eb13ff507c --- /dev/null +++ b/lib_lc3plus/lc3plus.h @@ -0,0 +1,520 @@ +/****************************************************************************** +* ETSI TS 103 634 V1.5.1 * +* Low Complexity Communication Codec Plus (LC3plus) * +* * +* Copyright licence is solely granted through ETSI Intellectual Property * +* Rights Policy, 3rd April 2019. No patent licence is granted by implication, * +* estoppel or otherwise. * +******************************************************************************/ + +/*! \file lc3plus.h + * This header provides the API for LC3plus. + * + * This library is targeting devices with extreme memory limitations, so memory management + * must be handeled by the user. This includes allocating memory for the structs. The structs are persistent + * between function calls. + * + * The amount of memory needed for various configurations can be obtained from the lc3plus_*_get_size + * function. The LC3PLUS_*_MAX_SIZE macro can be used for all configurations. + * + * Depending on the build configuration some functions might not be available. + */ + +#ifndef LC3PLUS_H +#define LC3PLUS_H + +#ifndef _MSC_VER +#include "options.h" +#include "wmc_auto.h" +#include +#else +typedef unsigned char uint8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +#endif + +/*! Construct version number from major/minor/micro values. */ +#define LC3PLUS_VERSION_INT(major, minor, micro) (((major) << 16) | ((minor) << 8) | (micro)) + +/*! Version number to ensure header and binary are matching. */ +#define LC3PLUS_VERSION LC3PLUS_VERSION_INT(1, 7, 4) + +/*! Maximum number of supported channels. The actual binary might support + * less, use lc3plus_channels_supported() to check. */ +#define LC3PLUS_MAX_CHANNELS 2 + +/*! Maximum number of samples per channel that can be stored in one LC3plus frame. + */ +#define LC3PLUS_MAX_SAMPLES 960 + +/*! Maximum number of bytes of one LC3plus frame. */ +#define LC3PLUS_MAX_BYTES 1250 + +/*! Maximum size needed to store encoder state. */ +#define LC3PLUS_ENC_MAX_SIZE 20392 + +/*! Maximum size needed to store decoder state. */ +#define LC3PLUS_DEC_MAX_SIZE 87528 + +/*! Error codes returned by functions. */ +typedef enum +{ + LC3PLUS_PLC_ADVANCED = 1 /*!< Enhanced concealment method */ +} LC3PLUS_PlcMode; + +/*! Error protection mode. LC3PLUS_EP_ZERO differs to LC3PLUS_EP_OFF in that + * errors can be detected but not corrected. */ +typedef enum +{ + LC3PLUS_EP_OFF = 0, /*!< Error protection is disabled */ + LC3PLUS_EP_ZERO = 1, /*!< Error protection with 0 bit correction */ + LC3PLUS_EP_LOW = 2, /*!< Error protection correcting one symbol per codeword */ + LC3PLUS_EP_MEDIUM = 3, /*!< Error protection correcting two symbols per codeword */ + LC3PLUS_EP_HIGH = 4 /*!< Error protection correcting three symbols per codeword */ +} LC3PLUS_EpMode; + +/*! Error protection mode request. On the encoder sidem, LC3PLUS_EPMR_ZERO to LC3PLUS_EPMR_HIGH + * can be set. The decoder returns mode requests with different confidences. */ +typedef enum +{ + LC3PLUS_EPMR_ZERO = 0, /*!< Request no error correction. High confidence if returned by decoder. */ + LC3PLUS_EPMR_LOW = 1, /*!< Request low error correction. High confidence if returned by decoder. */ + LC3PLUS_EPMR_MEDIUM = 2, /*!< Request medium error correction. High confidence if returned by decoder. */ + LC3PLUS_EPMR_HIGH = 3, /*!< Request high error correction. High confidence if returned by decoder. */ + LC3PLUS_EPMR_ZERO_MC = 4, /*!< No error correction requested, medium confidence. */ + LC3PLUS_EPMR_LOW_MC = 5, /*!< Low error correction requested, medium confidence. */ + LC3PLUS_EPMR_MEDIUM_MC = 6, /*!< Medium error correction requested, medium confidence. */ + LC3PLUS_EPMR_HIGH_MC = 7, /*!< High error correction requested, medium confidence. */ + LC3PLUS_EPMR_ZERO_NC = 8, /*!< No error correction requested, unvalidated. */ + LC3PLUS_EPMR_LOW_NC = 9, /*!< Low error correction requested, unvalidated. */ + LC3PLUS_EPMR_MEDIUM_NC = 10, /*!< Medium error correction requested, unvalidated. */ + LC3PLUS_EPMR_HIGH_NC = 11 /*!< High error correction requested, unvalidated. */ +} LC3PLUS_EpModeRequest; + +/*! Error codes returned by functions. */ +typedef enum +{ + LC3PLUS_OK = 0, /*!< No error occurred */ + LC3PLUS_ERROR = 1, /*!< Function call failed */ + LC3PLUS_DECODE_ERROR = 2, /*!< Frame failed to decode and was concealed */ + LC3PLUS_NULL_ERROR = 3, /*!< Pointer argument is null */ + LC3PLUS_SAMPLERATE_ERROR = 4, /*!< Invalid samplerate value */ + LC3PLUS_CHANNELS_ERROR = 5, /*!< Invalid channels value */ + LC3PLUS_BITRATE_ERROR = 6, /*!< Invalid bitrate value */ + LC3PLUS_NUMBYTES_ERROR = 7, /*!< Invalid num_bytes value */ + LC3PLUS_EPMODE_ERROR = 8, /*!< Invalid plc_method value */ + LC3PLUS_FRAMEMS_ERROR = 9, /*!< Invalid epmode value */ + LC3PLUS_ALIGN_ERROR = 10, /*!< Invalid frame_ms value */ + LC3PLUS_HRMODE_ERROR = 11, /*!< Unaligned pointer */ + LC3PLUS_BITRATE_UNSET_ERROR = 12, /*!< Invalid epmr value */ + LC3PLUS_BITRATE_SET_ERROR = 13, /*!< Invalid usage of hrmode, sampling rate and frame size */ + LC3PLUS_HRMODE_BW_ERROR = 14, /*!< Function called before bitrate has been set */ + LC3PLUS_PLCMODE_ERROR = 15, /*!< Function called after bitrate has been set */ + LC3PLUS_EPMR_ERROR = 16, /*!< Invalid external bad frame index */ + LC3PLUS_PADDING_ERROR = 17, /*!< Incorrect padding value */ + FRAMESIZE_ERROR = 18, /*!< Incorrect frame size during decoding */ + LC3PLUS_LFE_MODE_NOT_SUPPORTED = 19, /*!< LFE support not available */ + + /* START WARNING */ + LC3PLUS_WARNING = 20, + LC3PLUS_BW_WARNING = 21 /*!< Invalid bandwidth cutoff frequency */ + +} LC3PLUS_Error; + +typedef struct LC3PLUS_Enc LC3PLUS_Enc; /*!< Opaque encoder struct. */ +typedef struct LC3PLUS_Dec LC3PLUS_Dec; /*!< Opaque decoder struct. */ + +/*! \addtogroup Misc + * \{ */ + +/*! Test LFE mode support. + * + * Tests the support of the LFE mode. + * + * \return 1 for true, 0 for false. + */ +int32_t lc3_enc_supported_lfe(void); + +/*! Return library version number. It should match LC3PLUS_VERSION. */ +int lc3plus_version(void); + +/*! Tests if the library supports number of channels. + * + * \param[in] channels Number of channels. + * \return 1 for true, 0 for false. + */ +int lc3plus_channels_supported(int channels); + +/*! Tests if the library supports a sampling rate. + * + * \param[in] samplerate Sampling rate + * \return 1 for true, 0 for false + */ +int lc3plus_samplerate_supported(int samplerate); + +/*! \} + * \addtogroup Encoder + * \{ */ + +/*! + * Initialize LC3plus encoder. + * + * This function is used to fill a user-allocated encoder struct. This is typically + * called once for a samplerate / channel configuration. After init and before encoding + * the first frame you must call lc3plus_enc_set_bitrate(). + * + * \param[out] encoder Pointer to allocated encoder memory. It must have a size provided + * by lc3plus_enc_get_size() for matching samplerate / channels + * configuration or LC3PLUS_ENC_MAX_SIZE. + * \param[in] channels Number of channels. + * \param[in] samplerate Input sampling rate. Allowed sampling rates are: + * 8000, 16000, 24000, 32000, 44100, 48000 + * \param[in] hrmode High resolution mode. + * \param[in] lfe_channel_array Array containing activation of LFE mode for each individual channel. Can be NULL if LFE activation is not required. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_enc_init(LC3PLUS_Enc* encoder, int samplerate, int channels, int hrmode, int32_t lfe_channel_array[]); + +/*! + * Encode LC3plus frame with 16 bit input. + * + * Each call consumes a fixed number of samples. The number of input samples + * can be obtained from lc3plus_enc_get_input_samples(). + * Scratch parameter only works as dummy parameter to align fixed-point and floating-point APIs + * + * \param[in] encoder Encoder handle initialized by lc3plus_enc_init(). + * \param[in] input_samples Input samples. The left channel is stored in input_samples[0], + * the right channel in input_samples[1]. The input is not changed + * by the encoder. + * \param[out] output_bytes Output buffer. It must have a at least lc3plus_enc_get_num_bytes() + * or at most LC3PLUS_MAX_BYTES. + * \param[out] num_bytes Number of bytes written to output_bytes. + * \param scratch See comment above. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_enc16(LC3PLUS_Enc* encoder, int16_t** input_samples, void* output_bytes, int* num_bytes +, void *scratch +); + +/*! Encode LC3plus frame with 24 bit input. + * + * The input samples are expected to be 24-bit values, sign-extended to 32-bit. + * See lc3plus_enc16() for parameter documentation. + */ +LC3PLUS_Error lc3plus_enc24(LC3PLUS_Enc* encoder, int32_t** input_samples, void* output_bytes, int* num_bytes +, void *scratch +); + +/*! + * Internal function. Use lc3plus_enc16() or lc3plus_enc24() for encoding. + */ + +LC3PLUS_Error lc3plus_enc_fl(LC3PLUS_Enc* encoder, void** input_samples, int bitdepth, void* output_bytes, int* num_bytes); + +/*! Get the size of the LC3plus encoder struct for a samplerate / channel + * configuration. If memory is not restricted LC3PLUS_ENC_MAX_SIZE can be used for + * all configurations. + * + * \param[in] samplerate Sampling rate. + * \param[in] channels Number of channels. + * \return Size in bytes or 0 on error. + */ +int lc3plus_enc_get_size(int samplerate, int channels); + +/*! Dummy function as no scratch management available in floating-point code. Returns always zero. Used to align fixed-point and floating-point APIs. + * + * \param[in] encoder Encoder handle. + * \return Size in bytes or 0 on error. + */ +int lc3plus_enc_get_scratch_size(const LC3PLUS_Enc *encoder); + +/*! Get number of samples per channel expected by lc3plus_enc16() or lc3plus_enc24(). + * + * \param[in] encoder Encoder handle. + * \return Number of samples or 0 on error. + */ +int lc3plus_enc_get_input_samples(const LC3PLUS_Enc* encoder); + +/*! Get real internal bitrate of the encoder. It might differ from the requested + * bitrate due to 44.1 kHz input. + * + * \param[in] encoder Encoder handle. + * \return Bitrate in bits per second or 0 on error. + */ +int lc3plus_enc_get_real_bitrate(const LC3PLUS_Enc* encoder); + +/*! Get the maximum number of bytes produced by lc3plus_enc16() or lc3plus_enc24() for the current + * bitrate. It should be equal to the num_bytes output of lc3plus_enc16/24(). + * + * \param[in] encoder Encoder handle. + * \return Size in bytes or 0 on error. + */ +int lc3plus_enc_get_num_bytes(const LC3PLUS_Enc *encoder); + +/*! Set encoder bitrate for all channels. + * This function must be called at least once before encoding the first frame, but + * after other configuration functions such as lc3plus_enc_set_frame_ms(). + * + * Recommended bitrates for input sampling rates with 10 ms framing: + * kHz | kbps + * --------|----- + * 8 | 24 + * 16 | 32 + * 24 | 48 + * 32 | 64 + * 44.1/48 | 80(voice) 128(music) + * 96 | 128 + * + * \param[in] encoder Encoder handle. + * \param[in] bitrate Bitrate in bits per second. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_enc_set_bitrate(LC3PLUS_Enc* encoder, int bitrate); + +/*! Get the encoder delay in number of samples. + * + * \param[in] encoder Encoder handle. + * \return Encoder in samples or 0 on error. + */ +int lc3plus_enc_get_delay(const LC3PLUS_Enc *encoder); + +/*! Set the frame length for LC3plus decoder in deci milliseconds. + * Not all lengths may be enabled, in that case LC3PLUS_FRAMEMS_ERROR is returned. + * This only works correcly if the encoder was configured with the same vale. + * + * \param[in] decoder Decoder handle. + * \param[in] frame_ms Frame length in ms. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_enc_set_frame_dms(LC3PLUS_Enc *encoder, int frame_ms); + + +/*! Set encoder Low-frequency effect moded. deactivates LTPF, TNS, NF + * + * \param[in] encoder Encoder handle. + * \param[in] lfe LFE mode flag + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_enc_set_lfe(LC3PLUS_Enc* encoder, int lfe); + +/*! Free memory allocated within LC3plus encoder struct. + * + * \param[in] encoder Encoder handle. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_enc_free_memory(LC3PLUS_Enc* encoder); + +/*! Set encoder bandwidth to a different value. All frequency bins above the cutoff + * frequency are cut off. Allowed frequencies are: 4 kHz, 8 kHz, 12 kHz, 16 kHz and 24 kHz. + * + * \param[in] encoder Encoder handle. + * \param[in] bandwidth Cutoff Frequency in Hz + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_enc_set_bandwidth(LC3PLUS_Enc *encoder, int bandwidth); + +/*! Internal function called by lc3plus_enc_free_memory. + * + * \param[in] encoder Encoder handle. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_free_encoder_structs(LC3PLUS_Enc* encoder); + +/*! Sets error protection mode request transmitted in each channel encoded frame. + * The channel coder includes an error protection mode request (EPMR) in every frame. + * The EPMR takes value 0, 1, 2, and 3 which request ep modes 1, 2, 3, and 4 from the + * decoding device. The EPMR can be retrieved from the channel decoder via the interface + * routine lc3plus_dec_get_ep_mode_request(). + * + * \param[in] encoder Encoder handle. + * \param[in] epmr Error Protection Mode Request + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_enc_set_ep_mode_request(LC3PLUS_Enc *encoder, LC3PLUS_EpModeRequest epmr); + +/*! Set error protection mode. The default is LC3PLUS_EP_OFF. It is possible to switch between + * different modees during encoding. Dynamic switching is only allowed between LC3PLUS_EP_ZERO, + * LC3PLUS_EP_LOW, LC3_EP_MEDIUM, and LC3PLUS_EP_HIGH. The the decoder must be notified with + * lc3plus_dec_set_ep_enabled() to expect protected data if epmode is other than LC3PLUS_EP_OFF. + * + * \param[in] encoder Encoder handle. + * \param[in] epmode Error protection mode. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_enc_set_ep_mode(LC3PLUS_Enc *encoder, LC3PLUS_EpMode epmode); + +/*! \} + * \addtogroup Decoder + * \{ */ + +/*! + * Initialize LC3plus decoder. + * + * This function is used to fill a user-allocated decoder struct. This is + * typically called once for a samplerate / channel configuration. + * + * The samplerate and channel arguments must have the same values that were + * used for encoding. LC3plus does not provide a signalling scheme, transporting + * these values is the responsibility of the application. + * + * \param[out] decoder Pointer to decoder memory. It must have as size + * of least lc3plus_dec_get_size() or at most LC3PLUS_DEC_MAX_SIZE. + * \param[in] samplerate Bitstream sampling rate. \param[in] channels Bitstream + * number of channels. + * + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_dec_init(LC3PLUS_Dec* decoder, int samplerate, int channels, LC3PLUS_PlcMode plc_mode, int hrmode); + + + +/*! + * Decode compressed LC3plus frame to 16 bit PCM output. + * + * Each call decodes a fixed number of samples. Use lc3plus_dec_get_output_samples() to obtain this + * number. When the input is corrupted and can not be decoded, LC3PLUS_DECODE_ERROR is returned and + * packet loss concealment is applied, so the output is still usable. + * If error protection is enabled and the errors can be corrected the frame is corrected and + * normally decoded. Use lc3plus_dec_get_error_report() to check if errors were corrected. + * + * \param[in] decoder Decoder initialized by lc3plus_dec_init(). + * \param[in] input_bytes Input bytes. If error protection is enabled the input bytes can be + * altered when error correction is applied. This is why this buffer + * must be writable. + * \param[in] num_bytes Number of valid bytes in input_bytes. To signal a lost frame and + * generate concealment output this value must be set to 0. + * \param[out] output_samples Array of pointers to output channel buffers. Each channel buffer + * should provide enough space to hold at most LC3PLUS_MAX_SAMPLES. The + * left channel is stored in output_samples[0], the right channel in + * output_samples[1]. + * \param scratch Scratch parameter only works as dummy parameter to align fixed-point and floating-point APIs. + * \param[in] bfi_ext Bad Frame Indicator. 0: Good Frame. 1: Bad Frame, apply PLC. + * \return Returns LC3PLUS_OK on success or appropriate error code. Note there is + * a special case for LC3PLUS_DECODE_ERROR where the output is still valid. + */ +LC3PLUS_Error lc3plus_dec16(LC3PLUS_Dec* decoder, void* input_bytes, int num_bytes, int16_t** output_samples, + void* scratch, + int bfi_ext); + +/*! Decode compressed LC3plus frame to 24 bit PCM output. + * + * The output samples are 24-bit values, sign-extended to 32-bit. + * See lc3plus_dec16() for parameter documentation. + */ +LC3PLUS_Error lc3plus_dec24(LC3PLUS_Dec* decoder, void* input_bytes, int num_bytes, int32_t** output_samples, + void* scratch, + int bfi_ext); + +/* Internal function */ + LC3PLUS_Error lc3plus_dec_fl(LC3PLUS_Dec* decoder, void* input_bytes, int num_bytes, void** output_samples, int bps, int bfi_ext); + +/*! Get the size of the LC3plus decoder struct for a samplerate / channel + * configuration. If memory is not restricted LC3PLUS_DEC_MAX_SIZE can be used for + * all configurations. + * + * \param[in] channels Number of channels. + * \param[in] samplerate Sampling rate. + * \return Size in bytes or 0 on error. + */ +int lc3plus_dec_get_size(int samplerate, int channels); + +/*! Dummy function as no scratch management available in floating-point code. Returns always zero. Used to align fixed-point and floating-point APIs. + * + * \param[in] decoder Decoder handle. + * \return Size in bytes or 0 on error. + */ +int lc3plus_dec_get_scratch_size(const LC3PLUS_Dec *decoder); + +/*! Get the number of samples per channel produced by lc3plus_dec16() or lc3plus_dec24. + * + * \param[in] decoder Decoder handle. + * \return Number of samples or 0 on error. + */ +int lc3plus_dec_get_output_samples(const LC3PLUS_Dec* decoder); + +/*! Get the decoder delay in number of samples. + * + * \param[in] decoder Decoder handle. + * \return Delay in samples or 0 on error. + */ +int lc3plus_dec_get_delay(const LC3PLUS_Dec* decoder); + +/*! Set the frame length for LC3plus encoder in deci milliseconds. + * Not all lengths may be enabled, in that case LC3PLUS_FRAMEMS_ERROR is returned. + * This function must be called before lc3plus_enc_set_bitrate(). The decoder must be + * configured with lc3plus_dec_set_frame_dms() with the same value. + * + * \param[in] encoder Encoder handle. + * \param[in] frame_ms Frame length in ms. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_dec_set_frame_dms(LC3PLUS_Dec *decoder, int frame_ms); + + +/*! Free memory allocated within LC3plus decoder struct. + * + * \param[in] decoder Decoder handle. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_dec_free_memory(LC3PLUS_Dec* decoder); + +/*! Internal function called by lc3plus_dec_free_memory. + * + * \param[in] decoder Decoder handle. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_free_decoder_structs(LC3PLUS_Dec* decoder); + +/*! Enable or disable error protection. Default value is 0 (disabled). If error protection is + * enabled, the decoder expects that the frames were encoded with error protection mode + * LC3PLUS_EP_ZERO or higher. + * + * \param[in] decoder Decoder handle. + * \param[in] ep_enabled 1 (or any nonzero) for true, 0 for false. + * \return LC3PLUS_OK on success or appropriate error code. + */ +LC3PLUS_Error lc3plus_dec_set_ep_enabled(LC3PLUS_Dec *decoder, int ep_enabled); + +/*! Retrieves the error protection mode reqeust from channel decoder. + * + * The return value encodes both the error protection mode request (EPMR) + * and the confidence of the method by which it was retrieved. + * + * The requested error protection mode is (epmr % 4) + 1, where epmr is the + * function's return value. The confidence is specified as follows. + * + * Confidence | Range + * -----------|------------- + * high | 0 <= epmr < 4 + * medium | 4 <= epmr < 8 + * no | 8 <= epmr < 12 + * + * When receiving stereo content of separately channel encoded audio frames the + * return value is the minimum of two values retrieved from the individual channels. + * + * \param[in] decoder Decoder handle. + * \return Error protection mode reqeust. + */ +LC3PLUS_EpModeRequest lc3plus_dec_get_ep_mode_request(const LC3PLUS_Dec *decoder); + +/*! Get the number of corrected bit errors in the last decoded frame. This only works if + * error protection is active. If the number of errors is greater than the current error + * protection mode can correct, -1 is returned. If the last frame had no errors or the + * decoder handle is NULL, 0 is returned, + * + * \param[in] decoder Decoder handle. + * \return Number of corrected bits or -1. See description for details. + */ +int lc3plus_dec_get_error_report(const LC3PLUS_Dec *decoder); +/*! This function returns an set of flags indicating whether the last frame + * would have been channel decodable in epmode m, m ranging from 1 to 4. Note that + * this information is not available in case the last frame was not channel + * decodable in which case the return value is 0. If the last frame would have + * been decodable in epmode m, m-1th of the return value will be 1. + * Otherwise, if the frame would not have been decodable or if this information + * cannot be retrieved, the m-1th bit of the return value will be 0. + */ +int lc3plus_dec_get_epok_flags(const LC3PLUS_Dec *decoder); + +/*! \} */ +#endif /* LC3plus */ diff --git a/lib_lc3plus/setup_com_lc3plus.c b/lib_lc3plus/setup_com_lc3plus.c new file mode 100644 index 0000000000000000000000000000000000000000..f37af56a3109e415bed3f7d2d49507c99ffa5bed --- /dev/null +++ b/lib_lc3plus/setup_com_lc3plus.c @@ -0,0 +1,31 @@ +/****************************************************************************** +* ETSI TS 103 634 V1.5.1 * +* Low Complexity Communication Codec Plus (LC3plus) * +* * +* Copyright licence is solely granted through ETSI Intellectual Property * +* Rights Policy, 3rd April 2019. No patent licence is granted by implication, * +* estoppel or otherwise. * +******************************************************************************/ + +#include "options.h" +#include "wmc_auto.h" +#include "functions.h" + +LC3_FLOAT array_max_abs(LC3_FLOAT *in, LC3_INT32 len) +{ + LC3_FLOAT max; + LC3_INT32 i; + + max = LC3_FABS(in[0]); + + for (i = 0; i < len; i++) + { + if (LC3_FABS(in[i]) > LC3_FABS(max)) + { + max = LC3_FABS(in[i]); + } + } + + return max; +} + diff --git a/lib_lc3plus/setup_dec_lc3plus.c b/lib_lc3plus/setup_dec_lc3plus.c new file mode 100644 index 0000000000000000000000000000000000000000..9e9a5ea64e021c3669e4b439ac19bd22f9f1c43c --- /dev/null +++ b/lib_lc3plus/setup_dec_lc3plus.c @@ -0,0 +1,512 @@ +/****************************************************************************** +* ETSI TS 103 634 V1.5.1 * +* Low Complexity Communication Codec Plus (LC3plus) * +* * +* Copyright licence is solely granted through ETSI Intellectual Property * +* Rights Policy, 3rd April 2019. No patent licence is granted by implication, * +* estoppel or otherwise. * +******************************************************************************/ + +#include "options.h" +#include "wmc_auto.h" +#include "setup_dec_lc3plus.h" +#include "functions.h" +#include +#include + +/* if decoder is null only size is reported */ +#include "fft/iis_fft.h" + +int alloc_decoder(LC3PLUS_Dec* decoder, int samplerate, int channels) +{ + int ch = 0; + size_t size = sizeof(LC3PLUS_Dec); + size_t frame_len = DYN_MAX_LEN_EXT(samplerate); + + void *PlcAdvSetup = NULL; + LC3_FLOAT *pcmbufHist, *harmonicBuf; + LC3_FLOAT *PhECU_oold_grp_shape, *PhECU_old_grp_shape; + LC3_FLOAT *PhECU_xfp; + Complex *PhECU_X_sav_m; + LC3_INT32 *PhECU_plocs; + LC3_FLOAT *PhECU_f0est, *PhECU_mag_chg_1st, *PhECU_Xavg; + LC3_FLOAT *sine_table1_phecu, *sine_table2_phecu; + HANDLE_IIS_FFT handle_fft_phaseecu; + HANDLE_IIS_FFT handle_ifft_phaseecu; + LC3_FLOAT *q_old_res; + + LC3_INT32 * plc_longterm_advc_tdc = NULL, *plc_longterm_advc_ns = NULL; + LC3_INT16 longterm_analysis_counter_max = 0, longterm_analysis_counter_max_bytebuffer = 0; + + for (ch = 0; ch < channels; ch++) { + DecSetup* setup = balloc(decoder, &size, sizeof(DecSetup)); + + size_t max_pitch = ceilf(228.0 * CODEC_FS(samplerate) / 12800.0); + size_t pcm_plc_len = max_pitch + frame_len; + pcmbufHist = balloc(decoder, &size, sizeof(LC3_FLOAT) * pcm_plc_len); + harmonicBuf = balloc(decoder, &size, sizeof(LC3_FLOAT) * max_pitch); + PlcAdvSetup = balloc(decoder, &size, sizeof(*setup->PlcAdvSetup)); + PhECU_oold_grp_shape = balloc(decoder, &size, sizeof(LC3_FLOAT) *MAX_LGW); /* BASOP Word16 PhECU_oold_grp_shape_fx[MAX_LGW]; */ + PhECU_old_grp_shape = balloc(decoder, &size, sizeof(LC3_FLOAT) *MAX_LGW); /* BASOP Word16 PhECU_old_grp_shape_fx[MAX_LGW] ; */ + PhECU_xfp = balloc(decoder, &size, sizeof(LC3_FLOAT) *(frame_len * 16 / 10)); + PhECU_X_sav_m = balloc(decoder, &size, sizeof(Complex) *(((frame_len * 16 / 10) / 2) + 1));/*MAX_PLC_LMSPEC*/ + PhECU_plocs = balloc(decoder, &size, sizeof(LC3_INT32) * (((frame_len * 16 / 10) / 4) + 1 + 1)); /* BASOP Word16 *PhECU_plocs; */ + + handle_fft_phaseecu = balloc(decoder, &size, sizeof(IIS_FFT) * 1); + handle_ifft_phaseecu = balloc(decoder, &size, sizeof(IIS_FFT) * 1); + PhECU_f0est = balloc(decoder, &size, sizeof(LC3_FLOAT) * (((frame_len * 16 / 10) / 4) + 1)); /*BASOP Word32 *PhECU_f0est;*/ + PhECU_mag_chg_1st = balloc(decoder, &size, sizeof(LC3_FLOAT) *MAX_LGW); /* BASOP Word16 PhECU_mag_chg_1st[MAX_LGW];*/ + PhECU_Xavg = balloc(decoder, &size, sizeof(LC3_FLOAT) * MAX_LGW); /* BASOP Word16 PhECU_Xavg[MAX_LGW] ; */ + + sine_table1_phecu = balloc(decoder, &size, sizeof(LC3_FLOAT) * (((CODEC_FS(samplerate) * 16) / 1000) / 2 + 1)); + sine_table2_phecu = balloc(decoder, &size, sizeof(LC3_FLOAT) * (((CODEC_FS(samplerate) * 16) / 1000) / 2 + 1)); + + longterm_analysis_counter_max = plc_fadeout_param_maxlen[0]; + longterm_analysis_counter_max_bytebuffer = plc_fadeout_param_maxbytes[0]; + + plc_longterm_advc_tdc = balloc(decoder, &size, sizeof(LC3_INT32) * longterm_analysis_counter_max_bytebuffer); + plc_longterm_advc_ns = balloc(decoder, &size, sizeof(LC3_INT32) * longterm_analysis_counter_max_bytebuffer); + + q_old_res = balloc(decoder, &size, sizeof(LC3_FLOAT) * frame_len); + + if (decoder) { + decoder->channel_setup[ch] = setup; + + setup->PlcAdvSetup = PlcAdvSetup; + + setup->PlcAdvSetup->pcmbufHist = pcmbufHist; + setup->PlcAdvSetup->PlcTdcSetup.harmonicBuf = harmonicBuf; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_oold_grp_shape = PhECU_oold_grp_shape; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_old_grp_shape = PhECU_old_grp_shape; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_xfp = PhECU_xfp; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_X_sav_m = PhECU_X_sav_m; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_plocs = PhECU_plocs; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_f0est = PhECU_f0est; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_mag_chg_1st = PhECU_mag_chg_1st; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_Xavg = PhECU_Xavg; + setup->PlcAdvSetup->PlcPhEcuSetup.handle_fft_phaseecu = handle_fft_phaseecu; + setup->PlcAdvSetup->PlcPhEcuSetup.handle_ifft_phaseecu = handle_ifft_phaseecu; + + setup->PlcAdvSetup->PlcPhEcuSetup.handle_fft_phaseecu->sine_table = sine_table1_phecu; + setup->PlcAdvSetup->PlcPhEcuSetup.handle_ifft_phaseecu->sine_table = sine_table2_phecu; + + setup->PlcAdvSetup->longterm_analysis_counter_max = longterm_analysis_counter_max; + setup->PlcAdvSetup->longterm_analysis_counter_max_bytebuffer = longterm_analysis_counter_max_bytebuffer; + + setup->PlcAdvSetup->plc_longterm_advc_tdc = plc_longterm_advc_tdc; + setup->PlcAdvSetup->plc_longterm_advc_ns = plc_longterm_advc_ns; + + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_Lprot = (CODEC_FS(samplerate) * 16) / 1000; + real_fft_init(&(setup->PlcAdvSetup->PlcPhEcuSetup.PhEcu_Fft), setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_Lprot, &(setup->PlcAdvSetup->PlcPhEcuSetup.handle_fft_phaseecu)); + real_ifft_init(&(setup->PlcAdvSetup->PlcPhEcuSetup.PhEcu_Ifft), setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_Lprot, &(setup->PlcAdvSetup->PlcPhEcuSetup.handle_ifft_phaseecu)); + setup->statePC.q_old_res = q_old_res; + } + } + + return (int)size; +} + +LC3PLUS_Error FillDecSetup(LC3PLUS_Dec* decoder, int samplerate, int channels, LC3PLUS_PlcMode plc_mode + , int hrmode +) +{ + memset(decoder, 0, lc3plus_dec_get_size(samplerate, channels)); + alloc_decoder(decoder, samplerate, channels); + + decoder->fs = CODEC_FS(samplerate); + decoder->fs_out = samplerate; + decoder->fs_idx = FS2FS_IDX(decoder->fs); + decoder->plcMeth = plc_mode; + + decoder->hrmode = hrmode != 0; + + decoder->channels = channels; + decoder->frame_ms = 10; + decoder->frame_dms = 100; + decoder->BW_cutoff_bits = BW_cutoff_bits_all[decoder->fs_idx]; + + if (decoder->fs == 8000) { + decoder->tilt = 14; + } else if (decoder->fs == 16000) { + decoder->tilt = 18; + } else if (decoder->fs == 24000) { + decoder->tilt = 22; + } else if (decoder->fs == 32000) { + decoder->tilt = 26; + } else if (decoder->fs == 48000) { + decoder->tilt = 30; + } + else if (decoder->fs == 96000) { + decoder->tilt = 34; + } + + set_dec_frame_params(decoder); + + lc3plus_dec_set_ep_enabled(decoder, 0); + + return LC3PLUS_OK; +} + +/* set frame config params */ +void set_dec_frame_params(LC3PLUS_Dec* decoder) +{ + int ch = 0; + int n; + + if (decoder->fs_idx == 5) + { + decoder->hrmode = 1; + } + + decoder->frame_length = ceil(decoder->fs * 10 / 1000); /* fs * 0.01*2^6 */ + if (decoder->hrmode == 1) + { + decoder->yLen = decoder->frame_length; + } + else + { + decoder->yLen = MIN(MAX_BW, decoder->frame_length); + } + + decoder->bands_number = 64; + if (decoder->frame_ms == 2.5) + { + decoder->frame_length = decoder->frame_length >> 2; + decoder->yLen /= 4; + if (decoder->hrmode) + { + decoder->bands_number = bands_number_2_5ms_HR[decoder->fs_idx]; + } + else + { + decoder->bands_number = bands_number_2_5ms[decoder->fs_idx]; + } + } + if (decoder->frame_ms == 5) + { + decoder->frame_length = decoder->frame_length >> 1; + decoder->yLen /= 2; + decoder->bands_number = bands_number_5ms[decoder->fs_idx]; + } + if (decoder->frame_ms == 7.5) + { + decoder->frame_length = (decoder->frame_length >> 2) * 3; + decoder->yLen = (decoder->yLen / 4) * 3; + if (decoder->hrmode) + { + decoder->bands_number = bands_number_7_5ms_HR[decoder->fs_idx]; + } + else + { + decoder->bands_number = bands_number_7_5ms[decoder->fs_idx]; + } + } + + if (decoder->hrmode) + { + decoder->BW_cutoff_bits = 0; + } + else + { + decoder->BW_cutoff_bits = BW_cutoff_bits_all[decoder->fs_idx]; + } + + if (decoder->frame_ms == 10) + { + if (decoder->hrmode) + { + decoder->bands_offset = ACC_COEFF_PER_BAND_HR[decoder->fs_idx]; + } + else + { + decoder->bands_offset = ACC_COEFF_PER_BAND[decoder->fs_idx]; + } + decoder->cutoffBins = BW_cutoff_bin_all; + } + else if (decoder->frame_ms == 2.5) + { + if (decoder->hrmode) + { + decoder->bands_offset = ACC_COEFF_PER_BAND_2_5ms_HR[decoder->fs_idx]; + } + else + { + decoder->bands_offset = ACC_COEFF_PER_BAND_2_5ms[decoder->fs_idx]; + } + decoder->cutoffBins = BW_cutoff_bin_all_2_5ms; + } + else if (decoder->frame_ms == 5) + { + if (decoder->hrmode) + { + decoder->bands_offset = ACC_COEFF_PER_BAND_5ms_HR[decoder->fs_idx]; + } + else + { + decoder->bands_offset = ACC_COEFF_PER_BAND_5ms[decoder->fs_idx]; + } + decoder->cutoffBins = BW_cutoff_bin_all_5ms; + } + else if (decoder->frame_ms == 7.5) + { + if (decoder->hrmode) + { + decoder->bands_offset = ACC_COEFF_PER_BAND_7_5ms_HR[decoder->fs_idx]; + } + else + { + decoder->bands_offset = ACC_COEFF_PER_BAND_7_5ms[decoder->fs_idx]; + } + decoder->cutoffBins = BW_cutoff_bin_all_7_5ms; + } + + decoder->n_bandsPLC = MIN(decoder->frame_length, 80); + + if (decoder->frame_ms == 10) + { + decoder->bands_offsetPLC = ACC_COEFF_PER_BAND_PLC[decoder->fs_idx]; + } + else if (decoder->frame_ms == 5) + { + decoder->bands_offsetPLC = ACC_COEFF_PER_BAND_PLC_5ms[decoder->fs_idx]; + + if (decoder->fs == 24000) + { + decoder->n_bandsPLC = 40; + } + } + else if (decoder->frame_ms == 2.5) + { + decoder->bands_offsetPLC = ACC_COEFF_PER_BAND_PLC_2_5ms[decoder->fs_idx]; + + if (decoder->fs == 48000) + { + decoder->n_bandsPLC = 60; + } + } + else if (decoder->frame_ms == 7.5) + { + decoder->bands_offsetPLC = ACC_COEFF_PER_BAND_PLC_7_5ms[decoder->fs_idx]; + + if (decoder->fs != 32000 && decoder->fs != 96000) + { + decoder->n_bandsPLC = 60; + } + } + + assert(decoder->bands_offsetPLC); + + if (decoder->frame_ms == 10) { + decoder->imdct_win = MDCT_WINS_10ms[decoder->hrmode][decoder->fs_idx]; + decoder->imdct_laZeros = MDCT_la_zeroes[decoder->fs_idx]; + decoder->imdct_winLen = MDCT_WINDOWS_LENGTHS_10ms[decoder->fs_idx]; + } + else if (decoder->frame_ms == 2.5) { + decoder->imdct_win = MDCT_WINS_2_5ms[decoder->hrmode][decoder->fs_idx]; + decoder->imdct_laZeros = MDCT_la_zeroes_2_5ms[decoder->fs_idx]; + decoder->imdct_winLen = MDCT_WINDOWS_LENGTHS_2_5ms[decoder->fs_idx]; + } + else if (decoder->frame_ms == 5) { + decoder->imdct_win = MDCT_WINS_5ms[decoder->hrmode][decoder->fs_idx]; + decoder->imdct_laZeros = MDCT_la_zeroes_5ms[decoder->fs_idx]; + decoder->imdct_winLen = MDCT_WINDOWS_LENGTHS_5ms[decoder->fs_idx]; + } + else if (decoder->frame_ms == 7.5) { + decoder->imdct_win = MDCT_WINS_7_5ms[decoder->hrmode][decoder->fs_idx]; + decoder->imdct_laZeros = MDCT_la_zeroes_7_5ms[decoder->fs_idx]; + decoder->imdct_winLen = MDCT_WINDOWS_LENGTHS_7_5ms[decoder->fs_idx]; + } + + decoder->la_zeroes = decoder->imdct_laZeros; + + decoder->imdct_memLen = decoder->frame_length - decoder->imdct_laZeros; + + for (ch = 0; ch < decoder->channels; ch++) { + DecSetup* setup = decoder->channel_setup[ch]; + + setup->ltpf_mem_beta_idx = -1; + + setup->statePC.seed = 24607; + + if (decoder) { + /* Init DCT4 structs */ + if (setup->dct4structImdct.length != 0) { + dct4_free(&setup->dct4structImdct); + dct4_init(&setup->dct4structImdct, decoder->frame_length); + } else { + dct4_init(&setup->dct4structImdct, decoder->frame_length); + } + + setup->PlcNsSetup.cum_alpha = 1; + setup->PlcNsSetup.seed = 24607; + setup->alpha = 1; + if (setup->PlcAdvSetup) + { + LC3_INT32 pitch_max = 0, pitch_ana_len = 0, tdc_synt_len = 0; + pitch_max = ceil(228.0 * (LC3_FLOAT) decoder->fs / 12800.0); + pitch_ana_len = pitch_max + decoder->frame_length * (LC3_FLOAT) 100 / decoder->frame_dms; + tdc_synt_len = 16 + 1 + pitch_max + ceil(decoder->frame_length / 2); + setup->PlcAdvSetup->max_len_pcm_plc = MAX(pitch_ana_len, tdc_synt_len); + setup->PlcAdvSetup->PlcTdcSetup.preemphFac = plc_preemph_fac[decoder->fs_idx]; + setup->PlcAdvSetup->PlcTdcSetup.seed = 24607; + setup->PlcAdvSetup->PlcTdcSetup.lpcorder = 16; + + if (decoder->fs_idx == 0 && decoder->frame_dms == 25) + { + setup->PlcAdvSetup->PlcTdcSetup.lpcorder = 8; + } + + setup->PlcAdvSetup->stabFac = 1; + setup->PlcAdvSetup->cum_fading_fast = 1; + setup->PlcAdvSetup->cum_fading_slow = 1; + setup->PlcAdvSetup->cum_fflcAtten = 1; + + setup->PlcAdvSetup->longterm_analysis_counter_max = plc_fadeout_param_maxlen[(decoder->frame_dms / 25) - 1]; + setup->PlcAdvSetup->longterm_analysis_counter_max_bytebuffer = plc_fadeout_param_maxbytes[(decoder->frame_dms / 25) - 1]; + + if (decoder->fs_idx <= 4 && decoder->frame_dms == 100) + { + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_Lprot = (decoder->fs * 16) / 1000; /* 16 ms of samples at fs*/ + + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_f0hzLtpBin = 0; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_norm_corr = 0; + + set_vec(PHECU_GRP_SHAPE_INIT, setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_oold_grp_shape, MAX_LGW); + set_vec(PHECU_GRP_SHAPE_INIT, setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_old_grp_shape, MAX_LGW); + + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_L_oold_xfp_w_E = (LC3_FLOAT)PHECU_LTOT_MIN_MAN * LC3_POW(2.0, PHECU_LTOT_MIN_EXP - 31); + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_L_old_xfp_w_E = (LC3_FLOAT)PHECU_LTOT_MIN_MAN * LC3_POW(2.0, PHECU_LTOT_MIN_EXP - 31); + + /* CFL uses separate buffers for pcmHist, xfp and Xsav and q_d , BASOP uses an optimized joint buffer*/ + zero_float(setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_xfp, setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_Lprot); + zero_cmplx(setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_X_sav_m, (setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_Lprot/2 + 1)); + + set_vec(POS_ONE_Q15, setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_mag_chg_1st, MAX_LGW); + + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_beta_mute = (16384.0/32768.0); + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_seed = 21845; + + assert(decoder->frame_dms == 100); + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_LDWIN_OLAP = (decoder->frame_length / 4 ); /* 2.5 ms for regular 10 ms MDCT */ + + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_t_adv = ( + decoder->frame_length + + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_Lprot + + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_LDWIN_OLAP )/ 2; + } + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_short_flag_prev = 0; /* fullband transient */ + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_num_plocs = 0; + setup->PlcAdvSetup->PlcPhEcuSetup.PhECU_nonpure_tone_flag = -1; /* nonpure tone flag, -1==new calc., 0==pure, 1==nonpure */ + } + } + } + for (n=0; n < LC3_ROUND(PLC_FADEOUT_TYPE_1_IN_MS*10/decoder->frame_dms);n++){ + decoder->alpha_type_2_table[n] = type_2_fadeout(n, decoder->frame_dms); + } +} + +LC3PLUS_Error update_dec_bitrate(LC3PLUS_Dec* decoder, int ch, int nBytes) +{ + int totalBits = 0, bitsTmp = 0, channel_bytes = 0, maxBytes = 0, minBytes = 0; + DecSetup* setup; + + if (decoder->hrmode) + { + switch (decoder->frame_dms) + { + case 25: + maxBytes = 210; + minBytes = MIN_NBYTES; + break; + case 50: + maxBytes = 375; + minBytes = MIN_NBYTES; + break; + case 75: + maxBytes = 625; + minBytes = MIN_NBYTES; + break; + case 100: + maxBytes = 625; + minBytes = MIN_NBYTES; + break; + default: + return LC3PLUS_HRMODE_ERROR; + } + } + else + { + minBytes = MIN_NBYTES; + maxBytes = MAX_NBYTES_100; /* for backward compatibility, MAX_NBYTES_100 is used for all frame lengths */ + } + + channel_bytes = nBytes; + + setup = decoder->channel_setup[ch]; + + if (channel_bytes < minBytes || channel_bytes > maxBytes) + { + return LC3PLUS_NUMBYTES_ERROR; + } + + setup->targetBytes = channel_bytes; + setup->total_bits = setup->targetBytes << 3; + setup->enable_lpc_weighting = (setup->total_bits < 480); + setup->quantizedGainOff = + -(MIN(115, setup->total_bits / (10 * (decoder->fs_idx + 1))) + 105 + 5 * (decoder->fs_idx + 1)); + + if (decoder->hrmode && decoder->fs_idx == 5) + { + setup->quantizedGainOff = MAX(setup->quantizedGainOff, -181); + } + + totalBits = setup->total_bits; + + if (decoder->frame_ms == 2.5) { + setup->enable_lpc_weighting = setup->total_bits < 120; + totalBits = setup->total_bits * 4.0 * (1.0 - 0.4); + } + if (decoder->frame_ms == 5) { + setup->enable_lpc_weighting = (setup->total_bits < 240); + totalBits = setup->total_bits * 2 - 160; + } + if (decoder->frame_ms == 7.5) { + setup->enable_lpc_weighting = (setup->total_bits < 360); + totalBits = round(setup->total_bits * 10 / 7.5); + } + + if (decoder->frame_length > 40 * ((LC3_FLOAT) (decoder->frame_dms) / 10.0)) { + setup->N_red_tns = 40 * ((LC3_FLOAT) (decoder->frame_dms) / 10.0); + setup->fs_red_tns = 40000; + } else { + setup->N_red_tns = decoder->frame_length; + setup->fs_red_tns = decoder->fs; + } + + bitsTmp = totalBits; + + if (bitsTmp < 400 + (decoder->fs_idx - 1) * 80) { + setup->ltpf_conf_beta = 0.4; + setup->ltpf_conf_beta_idx = 0; + } else if (bitsTmp < 480 + (decoder->fs_idx - 1) * 80) { + setup->ltpf_conf_beta = 0.35; + setup->ltpf_conf_beta_idx = 1; + } else if (bitsTmp < 560 + (decoder->fs_idx - 1) * 80) { + setup->ltpf_conf_beta = 0.3; + setup->ltpf_conf_beta_idx = 2; + } else if (bitsTmp < 640 + (decoder->fs_idx - 1) * 80) { + setup->ltpf_conf_beta = 0.25; + setup->ltpf_conf_beta_idx = 3; + } else { + setup->ltpf_conf_beta = 0; + setup->ltpf_conf_beta_idx = -1; + } + + /* No LTPF in hrmode */ + if (decoder->hrmode == 1) { + setup->ltpf_conf_beta = 0; + setup->ltpf_conf_beta_idx = -1; + } + + return LC3PLUS_OK; +} diff --git a/lib_lc3plus/setup_dec_lc3plus.h b/lib_lc3plus/setup_dec_lc3plus.h new file mode 100644 index 0000000000000000000000000000000000000000..c3d26ee8ebe8f0b9ab46380ed6d620d7577ee9d3 --- /dev/null +++ b/lib_lc3plus/setup_dec_lc3plus.h @@ -0,0 +1,114 @@ +/****************************************************************************** +* ETSI TS 103 634 V1.5.1 * +* Low Complexity Communication Codec Plus (LC3plus) * +* * +* Copyright licence is solely granted through ETSI Intellectual Property * +* Rights Policy, 3rd April 2019. No patent licence is granted by implication, * +* estoppel or otherwise. * +******************************************************************************/ + +#ifndef SETUP_DEC_LC3_FL_H +#define SETUP_DEC_LC3_FL_H + +#include "options.h" +#include "wmc_auto.h" +#include "constants.h" + +/* Channel state and bitrate-derived values go in this struct */ +typedef struct { + LC3_INT* stDec_ola_mem_fx; /* MDCT_MEM_LEN_MAX */ + LC3_INT total_bits; + LC3_INT enable_lpc_weighting; + LC3_INT targetBytes; + LC3_INT quantizedGainOff; + LC3_INT ltpf_param[3]; + LC3_INT ltpf_param_mem[3]; + LC3_INT ltpf_mem_pitch; + LC3_INT ltpf_mem_active; + LC3_INT ltpf_mem_pitch_fr; + LC3_INT ltpf_mem_beta_idx; + LC3_INT ltpf_conf_beta_idx; + LC3_INT spec_inv_idx; + LC3_INT concealMethod; + LC3_INT last_size; + LC3_INT BW_cutoff_idx_nf; + LC3_INT prev_BW_cutoff_idx_nf; + LC3_INT fs_red_tns; + LC3_INT N_red_tns; + LC3_INT scf_idx[SCF_MAX_PARAM]; + uint8_t resBits[MAX_RESBITS_LEN]; + LC3_INT tns_idx[TNS_NUMFILTERS_MAX * MAXLAG]; + + LC3_FLOAT prev_fac_ns; + LC3_FLOAT ltpf_mem_x[3 * MAX_LEN]; + LC3_FLOAT ltpf_mem_y[3 * MAX_LEN]; + LC3_FLOAT ltpf_mem_gain; + LC3_FLOAT ltpf_conf_beta; + LC3_FLOAT sqQdec_fl[MAX_LEN]; + LC3_FLOAT scf_q[M]; + LC3_FLOAT int_scf[MAX_BANDS_NUMBER]; + LC3_FLOAT x_fl[MAX_LEN]; + LC3_FLOAT imdct_mem[MAX_LEN]; + LC3_FLOAT alpha; + LC3_FLOAT rel_pitch_change; + Dct4 dct4structImdct; + + PlcSetup PlcSetup; + PlcNsSetup PlcNsSetup; + + pcState statePC; + PlcAdvSetup* PlcAdvSetup; +} DecSetup; + +/* Constants and sampling rate derived values go in this struct */ +struct LC3PLUS_Dec { + LC3_FLOAT alpha_type_2_table[PLC_FADEOUT_TYPE_1_IN_MS*10/25]; /* [80] */ + DecSetup* channel_setup[MAX_CHANNELS]; + const LC3_INT* W_fx; + const LC3_INT* bands_offset; + const LC3_INT* cutoffBins; + + LC3_INT fs; /* sampling rate, 44.1 maps to 48 */ + LC3_INT fs_out; /* output sampling rate */ + LC3_INT fs_idx; /* sampling rate index */ + LC3_INT frame_length; /* sampling rate index */ + LC3_INT channels; /* number of channels */ + LC3_FLOAT frame_ms; /* frame length in ms (wrong for 44.1) */ + LC3_INT frame_dms; /* frame length in ms * 10 (wrong for 44.1) */ + LC3_INT last_size; /* size of last frame, without error protection */ + LC3_INT ep_enabled; /* error protection enabled */ + LC3_INT error_report; /* corrected errors in last frame or -1 on error */ + + LC3_INT imdct_memLen; + LC3_INT imdct_winLen; + LC3_INT imdct_laZeros; + const LC3_FLOAT* imdct_win; + + LC3_INT yLen; + LC3_INT W_size; + LC3_INT la_zeroes; + LC3_INT bands_number; + LC3_INT ltpf_mem_x_len; + LC3_INT ltpf_mem_y_len; + LC3_INT BW_cutoff_bits; + LC3_INT tilt; + + LC3_INT hrmode; + LC3_INT specflip; + + const LC3_INT* bands_offsetPLC; + LC3_INT n_bandsPLC; + + LC3_INT32 rframe; + int plcMeth; /* PLC method for all channels */ + LC3_INT16 n_pccw; + LC3_INT16 be_bp_left; + LC3_INT16 be_bp_right; + LC3_INT16 n_pc; + LC3_INT16 m_fec; + int epmr; + LC3_INT16 combined_channel_coding; + int last_error; +}; + +#endif diff --git a/lib_lc3plus/setup_enc_lc3plus.c b/lib_lc3plus/setup_enc_lc3plus.c new file mode 100644 index 0000000000000000000000000000000000000000..80bd909ab3268179e74cc61bf9c09e5223c570dc --- /dev/null +++ b/lib_lc3plus/setup_enc_lc3plus.c @@ -0,0 +1,610 @@ +/****************************************************************************** +* ETSI TS 103 634 V1.5.1 * +* Low Complexity Communication Codec Plus (LC3plus) * +* * +* Copyright licence is solely granted through ETSI Intellectual Property * +* Rights Policy, 3rd April 2019. No patent licence is granted by implication, * +* estoppel or otherwise. * +******************************************************************************/ + +#include "options.h" +#include "wmc_auto.h" +#include "setup_enc_lc3plus.h" +#include "functions.h" +#include + +/* if encoder is null only size is reported */ +int alloc_encoder(LC3PLUS_Enc* encoder, int channels) +{ + int ch = 0; + size_t size = sizeof(LC3PLUS_Enc); + + for (ch = 0; ch < channels; ch++) { + EncSetup* setup = balloc(encoder, &size, sizeof(EncSetup)); + if (encoder) { + encoder->channel_setup[ch] = setup; + } + } + + return (int)size; +} + +LC3PLUS_Error FillEncSetup(LC3PLUS_Enc* encoder, int samplerate, int channels + , int hrmode + , int32_t lfe_channel_array[] +) +{ + int ch = 0; + memset(encoder, 0, lc3plus_enc_get_size(samplerate, channels)); + alloc_encoder(encoder, channels); + + encoder->fs = CODEC_FS(samplerate); + encoder->fs_in = samplerate; + encoder->fs_idx = FS2FS_IDX(encoder->fs); + encoder->frame_dms = 100; + + if (encoder->fs_idx > 4) { + encoder->fs_idx = 5; + } + + encoder->hrmode = hrmode != 0; + + encoder->channels = channels; + encoder->frame_ms = 10; + encoder->envelope_bits = 38; + encoder->global_gain_bits = 8; + encoder->noise_fac_bits = 3; + encoder->BW_cutoff_bits = BW_cutoff_bits_all[encoder->fs_idx]; + + encoder->r12k8_mem_in_len = 2 * 8 * encoder->fs / 12800; + encoder->r12k8_mem_out_len = 24; + + if (lfe_channel_array != NULL) + { + for (ch = 0; ch < encoder->channels; ch++) + { + encoder->channel_setup[ch]->lfe = lfe_channel_array[ch] != 0; + } + } + + encoder->bw_ctrl_active = 0; + encoder->bandwidth = encoder->fs / 2; + encoder->bandwidth_preset = encoder->fs / 2; + + + if (encoder->fs == 8000) { + encoder->tilt = 14; + } else if (encoder->fs == 16000) { + encoder->tilt = 18; + } else if (encoder->fs == 24000) { + encoder->tilt = 22; + } else if (encoder->fs == 32000) { + encoder->tilt = 26; + } else if (encoder->fs == 48000) { + encoder->tilt = 30; + } + else if (encoder->fs == 96000) { + encoder->tilt = 34; + } + + set_enc_frame_params(encoder); + return LC3PLUS_OK; +} + +/* set frame config params */ +void set_enc_frame_params(LC3PLUS_Enc* encoder) +{ + int ch = 0; + EncSetup* setup; + + encoder->frame_length = ceil(encoder->fs * 10 / 1000); /* fs * 0.01*2^6 */ + if (encoder->hrmode == 1) + { + encoder->yLen = encoder->frame_length; + } + else + { + encoder->yLen = MIN(MAX_BW, encoder->frame_length); + encoder->sns_damping = 0.85; + } + + encoder->stEnc_mdct_mem_len = encoder->frame_length - encoder->la_zeroes; + encoder->bands_number = 64; + encoder->nSubdivisions = 3; + encoder->near_nyquist_index = encoder->bands_number - 2; + encoder->near_nyquist_flag = 0; + encoder->ltpf_mem_in_len = LTPF_MEMIN_LEN; + + if (encoder->fs_idx == 5) + { + encoder->hrmode = 1; + } + + if (encoder->hrmode) + { + encoder->BW_cutoff_bits = 0; + } + else + { + encoder->BW_cutoff_bits = BW_cutoff_bits_all[encoder->fs_idx]; + } + + if (encoder->frame_ms == 10) { + encoder->la_zeroes = MDCT_la_zeroes[encoder->fs_idx]; + if (encoder->hrmode) + { + encoder->bands_offset = ACC_COEFF_PER_BAND_HR[encoder->fs_idx]; + } + else + { + encoder->bands_offset = ACC_COEFF_PER_BAND[encoder->fs_idx]; + } + encoder->cutoffBins = BW_cutoff_bin_all; + + encoder->attdec_nblocks = 4; + encoder->attdec_damping = 0.5; + encoder->attdec_hangover_thresh = 2; + } + else if (encoder->frame_ms == 7.5) { + if (encoder->hrmode) + { + encoder->bands_offset = ACC_COEFF_PER_BAND_7_5ms_HR[encoder->fs_idx]; + } + else + { + encoder->bands_offset = ACC_COEFF_PER_BAND_7_5ms[encoder->fs_idx]; + } + encoder->la_zeroes = MDCT_la_zeroes_7_5ms[encoder->fs_idx]; + encoder->cutoffBins = BW_cutoff_bin_all_7_5ms; + encoder->attdec_nblocks = 3; + encoder->attdec_damping = 0.3; + encoder->attdec_hangover_thresh = 1; + + encoder->frame_length = (encoder->frame_length >> 2) * 3; + encoder->yLen = (encoder->yLen >> 2) * 3; + + encoder->stEnc_mdct_mem_len = encoder->frame_length - encoder->la_zeroes; + if (encoder->hrmode) + { + encoder->bands_number = bands_number_7_5ms_HR[encoder->fs_idx]; + } + else + { + encoder->bands_number = bands_number_7_5ms[encoder->fs_idx]; + } + encoder->nSubdivisions = 3; + encoder->near_nyquist_index = encoder->bands_number - 4; + encoder->r12k8_mem_out_len = ceil(2.0 * ((LC3_FLOAT) encoder->frame_length / 2.0 - (LC3_FLOAT) encoder->la_zeroes) * 12800.0 / (LC3_FLOAT) encoder->fs - 8.0); + } + else if (encoder->frame_ms == 5) { + encoder->frame_length = encoder->frame_length >> 1; + encoder->yLen /= 2; + encoder->stEnc_mdct_mem_len = encoder->frame_length - encoder->la_zeroes; + encoder->bands_number = bands_number_5ms[encoder->fs_idx]; + encoder->nSubdivisions = 2; + encoder->near_nyquist_index = encoder->bands_number - 3; + encoder->la_zeroes = MDCT_la_zeroes_5ms[encoder->fs_idx]; + if (encoder->hrmode) + { + encoder->bands_offset = ACC_COEFF_PER_BAND_5ms_HR[encoder->fs_idx]; + } + else + { + encoder->bands_offset = ACC_COEFF_PER_BAND_5ms[encoder->fs_idx]; + } + encoder->cutoffBins = BW_cutoff_bin_all_5ms; + } + else if (encoder->frame_ms == 2.5) { + encoder->la_zeroes = MDCT_la_zeroes_2_5ms[encoder->fs_idx]; + if (encoder->hrmode) + { + encoder->bands_offset = ACC_COEFF_PER_BAND_2_5ms_HR[encoder->fs_idx]; + } + else + { + encoder->bands_offset = ACC_COEFF_PER_BAND_2_5ms[encoder->fs_idx]; + } + encoder->cutoffBins = BW_cutoff_bin_all_2_5ms; + encoder->frame_length = encoder->frame_length >> 2; + encoder->yLen /= 4; + encoder->stEnc_mdct_mem_len = encoder->frame_length - encoder->la_zeroes; + if (encoder->hrmode) + { + encoder->bands_number = bands_number_2_5ms_HR[encoder->fs_idx]; + } + else + { + encoder->bands_number = bands_number_2_5ms[encoder->fs_idx]; + } + + encoder->nSubdivisions = 2; + encoder->near_nyquist_index = encoder->bands_number - 2; + encoder->ltpf_mem_in_len = LTPF_MEMIN_LEN + (LEN_12K8 >> 2); + } + + for (ch = 0; ch < encoder->channels; ch++) { + setup = encoder->channel_setup[ch]; + + setup->olpa_mem_pitch = 17; + setup->pitch_flag = 0; + if (setup->mdctStruct.mem != NULL) { + mdct_free(&setup->mdctStruct); + mdct_init(&setup->mdctStruct, encoder->frame_length, encoder->frame_dms, encoder->fs_idx, encoder->hrmode); + + dct2_free(&setup->dct2StructSNS); + dct2_init(&setup->dct2StructSNS, M); + } + else + { + mdct_init(&setup->mdctStruct, encoder->frame_length, encoder->frame_dms, encoder->fs_idx, encoder->hrmode); + dct2_init(&setup->dct2StructSNS, M); + } + } +} + +/* change encoder bitrate */ +LC3PLUS_Error update_enc_bitrate(LC3PLUS_Enc* encoder, int bitrate) +{ + int ch = 0, bitsTmp = 0, minBR = 0, maxBR = 0, totalBytes = 0; + LC3_INT channel_bytes = 0, max_bytes = 0; + +#ifdef ENABLE_HR_MODE_FL + if (encoder->hrmode) + { + switch (encoder->frame_dms) + { + case 25: + maxBR = 672000; + if (encoder->fs == 48000) {minBR = MIN_BR_25MS_48KHZ_HR;} + else if (encoder->fs == 96000) {minBR = MIN_BR_25MS_96KHZ_HR;} + else { return LC3PLUS_HRMODE_ERROR;} + break; + case 50: + maxBR = 600000; + if (encoder->fs == 48000) {minBR = MIN_BR_50MS_48KHZ_HR;} + else if (encoder->fs == 96000) {minBR = MIN_BR_50MS_96KHZ_HR;} + else { return LC3PLUS_HRMODE_ERROR;} + break; + case 75: + maxBR = 500000; + if (encoder->fs == 48000) {minBR = MIN_BR_075DMS_48KHZ_HR;} + else if (encoder->fs == 96000) {minBR = MIN_BR_075DMS_96KHZ_HR;} + else {return LC3PLUS_HRMODE_ERROR;} + break; + case 100: + maxBR = 500000; + if (encoder->fs == 48000) {minBR = MIN_BR_100MS_48KHZ_HR;} + else if (encoder->fs == 96000) {minBR = MIN_BR_100MS_96KHZ_HR;} + else { return LC3PLUS_HRMODE_ERROR;} + break; + default: + return LC3PLUS_HRMODE_ERROR; + } + } + else +#endif /* ENABLE_HR_MODE_FL */ + { + minBR = (MIN_NBYTES << 3); + maxBR = MAX_BR; + + switch (encoder->frame_dms) + { + case 25: + minBR = MIN_BR_025DMS; + maxBR = MAX_BR; + break; + case 50: + minBR = MIN_BR_050DMS; + maxBR = MAX_BR; + /* have additional limitations for 5.0ms */ + switch (encoder->fs_in) + { + case 8000: maxBR = MAX_BR_050DMS_NB; break; + default: break; + } + break; + case 75: + minBR = MIN_BR_075DMS; + maxBR = MAX_BR_075DMS; + /* have additional limitations for 7.5ms */ + switch (encoder->fs_in) + { + case 8000: maxBR = MAX_BR_075DMS_NB ; break; + case 16000: maxBR = MAX_BR_075DMS_WB ; break; + case 24000: maxBR = MAX_BR_075DMS_SSWB; break; + default: break; + } + break; + case 100: + /* have additional limitations for 10ms */ + minBR = MIN_BR_100DMS; + maxBR = MAX_BR; + switch (encoder->fs_in) + { + case 8000: maxBR = MAX_BR_100DMS_NB ; break; + case 16000: maxBR = MAX_BR_100DMS_WB ; break; + case 24000: maxBR = MAX_BR_100DMS_SSWB; break; + default: maxBR = MAX_BR; break; + } + break; + default: return LC3PLUS_FRAMEMS_ERROR; + } + maxBR *= (encoder->fs_in == 44100 ? 441. / 480 : 1); + } + minBR *= encoder->channels; + maxBR *= encoder->channels; + + encoder->combined_channel_coding = 0; + + if (encoder->channels > 1 && encoder->epmode) + { + if (encoder->bitrate * encoder->frame_length / (8 * encoder->fs_in) <= 160) + { + encoder->combined_channel_coding = 1; + } + } + + if (encoder->epmode > 0) + { + max_bytes = bitrate * encoder->frame_length / (8 * encoder->fs_in * encoder->channels); + if (max_bytes < FEC_SLOT_BYTES_MIN || max_bytes > FEC_SLOT_BYTES_MAX) + { + encoder->lc3_br_set = 0; + return LC3PLUS_BITRATE_ERROR; + } + } + + if (encoder->combined_channel_coding) + { + totalBytes = fec_get_data_size(encoder->epmode, encoder->combined_channel_coding, + bitrate * encoder->frame_length / (8 * encoder->fs_in)); + + encoder->channel_setup[0]->n_pccw = + fec_get_n_pccw(bitrate * encoder->frame_length / (8 * encoder->fs_in), encoder->epmode, + encoder->combined_channel_coding); + + encoder->channel_setup[0]->n_pc = fec_get_n_pc(encoder->epmode, encoder->channel_setup[0]->n_pccw, + bitrate * encoder->frame_length / (8 * encoder->fs_in)); + } + else + { + totalBytes = bitrate * encoder->frame_length / (8 * encoder->fs_in); + } + + if (encoder->frame_dms <= 50) + { + encoder->tnsMaxOrder = 4; + } else { + encoder->tnsMaxOrder = 8; + } + + if (bitrate < minBR || bitrate > maxBR) { + return LC3PLUS_BITRATE_ERROR; + } + + encoder->lc3_br_set = 1; + for (ch = 0; ch < encoder->channels; ch++) { + + EncSetup* setup = encoder->channel_setup[ch]; + + setup->targetBytes = totalBytes / encoder->channels + (ch < (totalBytes % encoder->channels)); + channel_bytes = totalBytes / encoder->channels + (ch < (totalBytes % encoder->channels)); + + if (encoder->combined_channel_coding) + { + setup->targetBytes = channel_bytes; + } + else + { + setup->targetBytes = fec_get_data_size(encoder->epmode, encoder->combined_channel_coding, channel_bytes); + setup->n_pccw = fec_get_n_pccw(channel_bytes, encoder->epmode, encoder->combined_channel_coding); + setup->n_pc = fec_get_n_pc(encoder->epmode, setup->n_pccw, channel_bytes); + } + // reduce bandwith to 12kHz if bitrate is low + if (encoder->frame_dms == 100 && + ((setup->targetBytes < 40 && encoder->fs == 48000) || + (setup->targetBytes < 36 && encoder->fs == 32000))) + { + encoder->bandwidth = MIN(12000, encoder->bandwidth_preset); + } + else + { + /* channel with highest index has lowest bitrate. + For a second channel with lower targetBytes, bandwidth is overwritten */ + encoder->bandwidth = encoder->bandwidth_preset; + } + encoder->bw_ctrl_cutoff_bin = encoder->bandwidth * encoder->frame_dms / 5000; + encoder->bw_index = (encoder->bandwidth / 4000) - 1; + setup->total_bits = setup->targetBytes << 3; + setup->targetBitsInit = setup->total_bits - encoder->envelope_bits - encoder->global_gain_bits - + encoder->noise_fac_bits - encoder->BW_cutoff_bits - + ceil(LC3_LOGTWO(encoder->frame_length / 2)) - 2 - 1; + + if (setup->total_bits > 1280) { + setup->targetBitsInit = setup->targetBitsInit - 1; + } + if (setup->total_bits > 2560) { + setup->targetBitsInit = setup->targetBitsInit - 1; + } + + if (encoder->hrmode) + { + setup->targetBitsInit -= 1; + } + + setup->targetBitsAri = setup->total_bits; + setup->enable_lpc_weighting = setup->total_bits < 480; + + if (encoder->frame_ms == 7.5) { + setup->enable_lpc_weighting = setup->total_bits < 360; + } + if (encoder->frame_ms == 5) { + setup->enable_lpc_weighting = setup->total_bits < 240; + } + if (encoder->frame_ms == 2.5) { + setup->enable_lpc_weighting = setup->total_bits < 120; + } + + setup->quantizedGainOff = + -(MIN(115, setup->total_bits / (10 * (encoder->fs_idx + 1))) + 105 + 5 * (encoder->fs_idx + 1)); + + if (encoder->hrmode && encoder->fs_idx == 5) + { + setup->quantizedGainOff = MAX(setup->quantizedGainOff, -181); + } + + if (encoder->frame_ms == 10 && ((encoder->fs_in >= 44100 && setup->targetBytes >= 100) || + (encoder->fs_in == 32000 && setup->targetBytes >= 81)) && setup->targetBytes < 340 && encoder->hrmode == 0) { + setup->attack_handling = 1; + + } + else if (encoder->frame_dms == 75 && ((encoder->fs_in >= 44100 && setup->targetBytes >= 75) || + (encoder->fs_in == 32000 && setup->targetBytes >= 61)) && setup->targetBytes < 150 && encoder->hrmode == 0) + { + setup->attack_handling = 1; + } + else + { + /* reset for bitrate switching */ + setup->attack_handling = 0; + + setup->attdec_filter_mem[0] = 0; + setup->attdec_filter_mem[1] = 0; + + setup->attdec_detected = 0; + setup->attdec_position = 0; + setup->attdec_acc_energy = 0; + } + + bitsTmp = setup->total_bits; + if (encoder->frame_ms == 2.5) { + bitsTmp = bitsTmp * 4.0 * (1.0 - 0.4); + } + if (encoder->frame_ms == 5) { + bitsTmp = bitsTmp * 2 - 160; + } + if (encoder->frame_ms == 7.5) { + bitsTmp = round(bitsTmp * 10 / 7.5); + } + + if (bitsTmp < 400 + (encoder->fs_idx - 1) * 80) { + setup->ltpf_enable = 1; + } else if (bitsTmp < 480 + (encoder->fs_idx - 1) * 80) { + setup->ltpf_enable = 1; + } else if (bitsTmp < 560 + (encoder->fs_idx - 1) * 80) { + setup->ltpf_enable = 1; + } else if (bitsTmp < 640 + (encoder->fs_idx - 1) * 80) { + setup->ltpf_enable = 1; + } else { + setup->ltpf_enable = 0; + } + if (encoder->hrmode) { + setup->ltpf_enable = 0; + } + + /* turn down SNS shaping for higher rates */ + if (encoder->hrmode == 0) { + encoder->sns_damping = 0.85; + } else { + encoder->sns_damping = 0.6; + if (encoder->fs_idx >= 4) { + if (encoder->frame_ms == 10) + { + if (setup->total_bits > 4400) { + encoder->sns_damping = 6881.0/32768.0; + } + } + if (encoder->frame_ms == 7.5) + { + if (setup->total_bits > 3*4400/4) { + encoder->sns_damping = 5898.0/32768.0; + } + } + if (encoder->frame_ms == 5) + { + if (setup->total_bits > 4600/2) { + encoder->sns_damping = 4915.0/32768.0; + } + } + if (encoder->frame_ms == 2.5) + { + if (setup->total_bits > 4600/4) { + encoder->sns_damping = 4915.0/32768.0; + } + } + } + } + + if (encoder->hrmode && encoder->fs_idx >= 4) + { + int real_rate = setup->targetBytes * 8000 / encoder->frame_ms; + setup->regBits = real_rate / 12500; + + if (encoder->fs_idx == 5) + { + if (encoder->frame_ms == 10) + { + setup->regBits +=2; + } + if (encoder->frame_ms == 7.5) + { + setup->regBits +=1; + } + if (encoder->frame_ms == 2.5) + { + setup->regBits -= 6; + } + } + else + { + if (encoder->frame_ms == 2.5) + { + setup->regBits -= 6; + } + else if (encoder->frame_ms == 5) + { + setup->regBits += 0; + } + if (encoder->frame_ms == 7.5) + { + setup->regBits +=2; + } + if (encoder->frame_ms == 10) + { + setup->regBits += 5; + } + } + if (setup->regBits < 6) + { + setup->regBits = 6; + } + if (setup->regBits > 23) + { + setup->regBits = 23; + } + } + else + { + setup->regBits = -1; + } + } + + encoder->bitrate = bitrate; + + return LC3PLUS_OK; +} + +void update_enc_bandwidth(LC3PLUS_Enc* encoder, int bandwidth) +{ + int index = 0; + + if (bandwidth >= encoder->fs_in) { + encoder->bandwidth = 0; + } + else + { + encoder->bandwidth = bandwidth; + index = FS2FS_IDX(bandwidth); + encoder->bw_ctrl_cutoff_bin = encoder->cutoffBins[index]; + } +} diff --git a/lib_lc3plus/setup_enc_lc3plus.h b/lib_lc3plus/setup_enc_lc3plus.h new file mode 100644 index 0000000000000000000000000000000000000000..7947a0e649dc352909a54ff500c9165082f02763 --- /dev/null +++ b/lib_lc3plus/setup_enc_lc3plus.h @@ -0,0 +1,121 @@ +/****************************************************************************** +* ETSI TS 103 634 V1.5.1 * +* Low Complexity Communication Codec Plus (LC3plus) * +* * +* Copyright licence is solely granted through ETSI Intellectual Property * +* Rights Policy, 3rd April 2019. No patent licence is granted by implication, * +* estoppel or otherwise. * +******************************************************************************/ + +#ifndef SETUP_ENC_LC3_FL_H +#define SETUP_ENC_LC3_FL_H + +#include "options.h" +#include "wmc_auto.h" +#include "constants.h" + +/* Channel state and bitrate-derived values go in this struct */ +typedef struct { + LC3_FLOAT targetBitsOff; + LC3_FLOAT ltpf_mem_normcorr; + LC3_FLOAT ltpf_mem_mem_normcorr; + LC3_FLOAT attdec_filter_mem[2]; + LC3_FLOAT attdec_acc_energy; + LC3_FLOAT r12k8_mem_50[2]; + LC3_FLOAT r12k8_mem_in[120]; + LC3_FLOAT r12k8_mem_out[44]; + LC3_FLOAT olpa_mem_s12k8[3]; + LC3_FLOAT olpa_mem_s6k4[LEN_6K4 + MAX_PITCH_6K4 + 16]; + LC3_FLOAT ltpf_mem_in[LTPF_MEMIN_LEN + LEN_12K8 + 1]; + LC3_FLOAT s_in_scaled[MAX_LEN]; + LC3_FLOAT s_12k8[LEN_12K8 + 1]; + LC3_FLOAT ener[MAX_BANDS_NUMBER]; + LC3_FLOAT scf_q[M]; + LC3_FLOAT scf[M]; + LC3_FLOAT int_scf[MAX_BANDS_NUMBER]; + LC3_FLOAT ltpf_mem_pitch; + + LC3_INT targetBytes; + LC3_INT total_bits; + LC3_INT targetBitsInit; + LC3_INT targetBitsAri; + LC3_INT enable_lpc_weighting; + LC3_INT ltpf_enable; + LC3_INT quantizedGainOff; + LC3_INT tns_bits; + LC3_INT targetBitsQuant; + LC3_INT olpa_mem_pitch; + LC3_INT pitch_flag; + LC3_INT ltpf_mem_ltpf_on; + LC3_INT mem_targetBits; + LC3_INT mem_specBits; + LC3_INT attack_handling; /* flag to enable attack handling */ + LC3_INT attdec_detected; + LC3_INT attdec_position; + LC3_INT ltpf_param[3]; + LC3_INT L_scf_idx[SCF_MAX_PARAM]; + LC3_INT codingdata[3 * MAX_LEN]; + uint8_t resBits[MAX_RESBITS_LEN]; + LC3_INT regBits; + + LC3_INT16 n_pc; + LC3_INT16 n_pccw; + LC3_INT16 be_bp_left; + LC3_INT16 be_bp_right; + + Mdct mdctStruct; + Dct2 dct2StructSNS; + + LC3_INT lfe; +} EncSetup; + +/* Constants and sampling rate derived values go in this struct */ +struct LC3PLUS_Enc { + EncSetup* channel_setup[MAX_CHANNELS]; + const LC3_INT* W_fx; + const LC3_INT* bands_offset; + const LC3_INT* cutoffBins; + + LC3_INT fs; /* encoder sampling rate 44.1 -> 48 */ + LC3_INT fs_in; /* input sampling rate */ + LC3_INT bitrate; /* global bitrate */ + LC3_INT fs_idx; /* sampling rate index */ + LC3_INT frame_length; /* audio samples / frame */ + LC3_INT channels; /* number of channels */ + LC3_INT epmode; /* error protection mode */ + LC3_FLOAT frame_ms; /* frame length in ms (wrong for 44.1) */ + LC3_INT frame_dms; /* frame length in ms * 10 (wrong for 44.1) */ + LC3_INT tilt; + LC3_INT lc3_br_set; + LC3_INT yLen; + LC3_INT W_size; + LC3_INT la_zeroes; + LC3_INT stEnc_mdct_mem_len; + LC3_INT bands_number; + LC3_INT nSubdivisions; + LC3_INT ltpf_mem_in_len; + LC3_INT envelope_bits; + LC3_INT global_gain_bits; + LC3_INT noise_fac_bits; + LC3_INT BW_cutoff_bits; + LC3_INT r12k8_mem_in_len; + LC3_INT r12k8_mem_out_len; + LC3_INT16 near_nyquist_index; + LC3_INT16 near_nyquist_flag; + LC3_INT tnsMaxOrder; + LC3_INT hrmode; + LC3_INT bandwidth; + LC3_INT bandwidth_preset; + LC3_INT bw_ctrl_active; + LC3_INT bw_ctrl_cutoff_bin; + LC3_INT bw_index; + LC3_FLOAT sns_damping; + LC3_INT attdec_nblocks; + LC3_FLOAT attdec_damping; + LC3_INT attdec_hangover_thresh; + + LC3_INT16 combined_channel_coding; + LC3_INT16 epmr; +}; + +#endif diff --git a/lib_rend/ivas_objectRenderer.c b/lib_rend/ivas_objectRenderer.c index ed4fb71c423b538609cc173125c6ff82fdf56933..6e836e141c2ad7cb2a44c8318899b353925e1cc7 100644 --- a/lib_rend/ivas_objectRenderer.c +++ b/lib_rend/ivas_objectRenderer.c @@ -534,13 +534,16 @@ ivas_error TDREND_Update_object_positions( const ISM_METADATA_HANDLE *hIsmMetaData /* i : Input metadata for ISM objects */ ) { +#ifndef NONBE_1377_REND_DIRATT_CONF TDREND_DirAtten_t *DirAtten_p; +#endif int16_t nS; float Pos[3]; float Dir[3]; ivas_error error; - +#ifndef NONBE_1377_REND_DIRATT_CONF DirAtten_p = hBinRendererTd->DirAtten_p; +#endif /* For each source, write the frame data to the source object*/ for ( nS = 0; nS < num_src; nS++ ) @@ -557,11 +560,12 @@ ivas_error TDREND_Update_object_positions( return error; } +#ifndef NONBE_1377_REND_DIRATT_CONF if ( ( error = TDREND_MIX_SRC_SetDirAtten( hBinRendererTd, nS, DirAtten_p ) ) != IVAS_ERR_OK ) { return error; } - +#endif if ( ( error = TDREND_MIX_SRC_SetGain( hBinRendererTd, nS, hIsmMetaData[nS]->gain ) ) != IVAS_ERR_OK ) { return error; @@ -675,13 +679,22 @@ ivas_error ivas_td_binaural_open_ext( AUDIO_CONFIG inConfig, RENDER_CONFIG_DATA *hRendCfg, /* i : Renderer configuration */ LSSETUP_CUSTOM_STRUCT *customLsInput, +#ifdef NONBE_1377_REND_DIRATT_CONF + const int32_t outFs, /* i: output sampling rate */ + const IVAS_REND_InputId id /* i: ISM ID */ +) +#else const int32_t outFs ) +#endif { int16_t nchan_transport; AUDIO_CONFIG transport_config; IVAS_FORMAT ivas_format; IVAS_OUTPUT_SETUP hTransSetup; ivas_error error; +#ifdef NONBE_1377_REND_DIRATT_CONF + int16_t ism_number; +#endif float *distAtt = NULL; float *directivity = NULL; @@ -712,7 +725,12 @@ ivas_error ivas_td_binaural_open_ext( if ( NULL != hRendCfg ) { +#ifdef NONBE_1377_REND_DIRATT_CONF + ism_number = id & 0x00FF; /* Exctract ISM number from ID */ + directivity = hRendCfg->directivity + 3 * ism_number; +#else directivity = hRendCfg->directivity; +#endif distAtt = hRendCfg->distAtt; } diff --git a/lib_rend/ivas_omasa_ana.c b/lib_rend/ivas_omasa_ana.c index 95d67ee4fe130c0b5bd45d9068f77f1c5f723328..e7f58262edb660d75478f5e9c25733bb752f9487 100644 --- a/lib_rend/ivas_omasa_ana.c +++ b/lib_rend/ivas_omasa_ana.c @@ -482,7 +482,6 @@ static void ivas_omasa_dmx( float g1, g2; float data_out_f[MASA_MAX_TRANSPORT_CHANNELS][L_FRAME48k]; - for ( i = 0; i < nchan_transport; i++ ) { set_zero( data_out_f[i], input_frame ); @@ -490,24 +489,31 @@ static void ivas_omasa_dmx( for ( i = 0; i < nchan_ism; i++ ) { - azimuth = ism_azimuth[i]; - elevation = ism_elevation[i]; + if ( nchan_transport == 1 ) + { + v_add( data_out_f[0], data_in_f[i], data_out_f[0], input_frame ); + } + else + { + azimuth = ism_azimuth[i]; + elevation = ism_elevation[i]; - ivas_ism_get_stereo_gains( azimuth, elevation, &gains[0], &gains[1] ); + ivas_ism_get_stereo_gains( azimuth, elevation, &gains[0], &gains[1] ); - /* Downmix using the panning gains */ - for ( j = 0; j < nchan_transport; j++ ) - { - if ( fabsf( gains[j] ) > 0.0 || fabsf( prev_gains[i][j] ) > 0.0f ) + /* Downmix using the panning gains */ + for ( j = 0; j < nchan_transport; j++ ) { - for ( k = 0; k < input_frame; k++ ) + if ( fabsf( gains[j] ) > 0.0 || fabsf( prev_gains[i][j] ) > 0.0f ) { - g1 = interpolator[k]; - g2 = 1.0f - g1; - data_out_f[j][k] += ( g1 * gains[j] + g2 * prev_gains[i][j] ) * data_in_f[i][k]; + for ( k = 0; k < input_frame; k++ ) + { + g1 = interpolator[k]; + g2 = 1.0f - g1; + data_out_f[j][k] += ( g1 * gains[j] + g2 * prev_gains[i][j] ) * data_in_f[i][k]; + } } + prev_gains[i][j] = gains[j]; } - prev_gains[i][j] = gains[j]; } } diff --git a/lib_rend/ivas_output_init.c b/lib_rend/ivas_output_init.c index 560f9f66618709e0f7b59a0d53d04a7a495582dd..01e1d77231ff06fc84f35a4ca20448a53e8b2729 100644 --- a/lib_rend/ivas_output_init.c +++ b/lib_rend/ivas_output_init.c @@ -368,36 +368,67 @@ int16_t ivas_get_nchan_buffers_dec( *-------------------------------------------------------------------*/ ivas_error ivas_output_buff_dec( - float *p_output_f[], /* i/o: output audio buffers */ - const int16_t nchan_out_buff_old, /* i : previous frame number of output channels */ - const int16_t nchan_out_buff /* i : number of output channels */ + float *p_output_f[], /* i/o: output audio buffers */ + const int16_t nchan_out_buff, /* i : number of output channels */ + const int16_t Opt_tsm, /* i : TSM option flag */ + DECODER_TC_BUFFER_HANDLE hTcBuffer /* i : TSM buffer handle */ ) { - int16_t ch; + int16_t ch, nchan_tc_jbm, nsamp_to_allocate, n_samp_full, offset; - if ( nchan_out_buff > nchan_out_buff_old ) + for ( ch = 0; ch < MAX_OUTPUT_CHANNELS + MAX_NUM_OBJECTS; ch++ ) { - for ( ch = nchan_out_buff_old; ch < nchan_out_buff; ch++ ) + p_output_f[ch] = NULL; + } + + if ( hTcBuffer->tc_buffer2 != NULL ) + { + free( hTcBuffer->tc_buffer2 ); + hTcBuffer->tc_buffer2 = NULL; + } + + nchan_tc_jbm = 0; + if ( Opt_tsm ) + { + /* JBM decoding: output audio buffers are shared with audio buffers from 'hTcBuffer->tc[]' */ + nchan_tc_jbm = max( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full ); + } + + if ( nchan_out_buff <= nchan_tc_jbm && !Opt_tsm ) + { + for ( ch = 0; ch < nchan_out_buff; ch++ ) + { + p_output_f[ch] = hTcBuffer->tc[ch]; + } + } + else + { + for ( ch = 0; ch < nchan_tc_jbm; ch++ ) + { + p_output_f[ch] = hTcBuffer->tc[ch]; + } + + /* non-JBM decoding: allocate output audio buffers */ + /* JBM decoding: when not enough audio buffers 'hTcBuffer->tc[]', allocate additional buffers */ + n_samp_full = ( 48000 / FRAMES_PER_SEC ); + nsamp_to_allocate = ( nchan_out_buff - nchan_tc_jbm ) * n_samp_full; + + if ( nsamp_to_allocate > 0 ) { -#ifdef DEBUGGING - if ( p_output_f[ch] != NULL ) - { - return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Memory for floating-point output audio buffer is already allocated!\n" ) ); - } -#endif /* note: these are intra-frame heap memories */ - if ( ( p_output_f[ch] = (float *) malloc( ( 48000 / FRAMES_PER_SEC ) * sizeof( float ) ) ) == NULL ) + if ( ( hTcBuffer->tc_buffer2 = (float *) malloc( nsamp_to_allocate * sizeof( float ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for floating-point output audio buffer!\n" ) ); } + + set_zero( hTcBuffer->tc_buffer2, nsamp_to_allocate ); } - } - else - { - for ( ch = nchan_out_buff; ch < nchan_out_buff_old; ch++ ) + + offset = 0; + for ( ; ch < nchan_out_buff; ch++ ) { - free( p_output_f[ch] ); - p_output_f[ch] = NULL; + p_output_f[ch] = &hTcBuffer->tc_buffer2[offset]; + offset += n_samp_full; } } diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index bb936d4b14b85a1eac27874a27c08884f57de35b..2617bae683233d35cf5ae7b5be9f0d259f6c4170 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -661,7 +661,12 @@ ivas_error ivas_td_binaural_open_ext( const AUDIO_CONFIG inConfig, RENDER_CONFIG_DATA *hRendCfg, /* i : Renderer configuration */ LSSETUP_CUSTOM_STRUCT *customLsInput, +#ifdef NONBE_1377_REND_DIRATT_CONF + const int32_t outFs, /* i: output sampling rate */ + const IVAS_REND_InputId id /* i: ISM ID */ +#else const int32_t output_Fs +#endif ); void ivas_td_binaural_close( @@ -945,8 +950,7 @@ ivas_error ivas_binaural_reverb_init( const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *roomAcoustics, /* i/o: room acoustics parameters */ const int32_t sampling_rate, /* i : sampling rate */ const float *defaultTimes, /* i : default reverberation times */ - const float *defaultEne /* i : default reverberation energies */ - , + const float *defaultEne, /* i : default reverberation energies */ float *earlyEne /* i/o: Early part energies to be modified */ ); @@ -1582,6 +1586,40 @@ void ivas_rend_closeCldfbRend( CLDFB_REND_WRAPPER *pCldfbRend ); +/*----------------------------------------------------------------------------------* + * Time domain ring buffer prototypes + *----------------------------------------------------------------------------------*/ + +ivas_error ivas_TD_RINGBUF_Open( + TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */ + const uint32_t capacity_per_channel, /* i : Number of samples stored per channel */ + const uint16_t num_channels /* i : Number of channels */ +); + +void ivas_TD_RINGBUF_Close( + TD_RINGBUF_HANDLE *ph /* i/o: Ring buffer handle */ +); + +void ivas_TD_RINGBUF_Push( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *data, /* i : Input data */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to store */ +); + +void ivas_TD_RINGBUF_PushZeros( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const uint32_t num_samples_per_channel /* i : Number of zeros per channel to store */ +); + +void ivas_TD_RINGBUF_Pop( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + float *data, /* i : Output data */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to retrieve*/ +); + +uint32_t ivas_TD_RINGBUF_Size( + const TD_RINGBUF_HANDLE h /* i : Ring buffer handle */ +); /* clang-format on */ diff --git a/lib_rend/ivas_reverb.c b/lib_rend/ivas_reverb.c index 2811a3c4d03ec644555e7daa56eca3dd233f1638..b4adf013fb5c0386553b76a7001425770d34ab62 100644 --- a/lib_rend/ivas_reverb.c +++ b/lib_rend/ivas_reverb.c @@ -79,10 +79,10 @@ #define MAX_NR_OUTPUTS ( 2 ) -const int16_t init_loop_delay[IVAS_REV_MAX_NR_BRANCHES] = { 37, 31, 29, 23, 19, 17, 13, 11 }; -const int16_t default_loop_delay_48k[IVAS_REV_MAX_NR_BRANCHES] = { 2309, 1861, 1523, 1259, 1069, 919, 809, 719 }; -const int16_t default_loop_delay_32k[IVAS_REV_MAX_NR_BRANCHES] = { 1531, 1237, 1013, 839, 709, 613, 541, 479 }; -const int16_t default_loop_delay_16k[IVAS_REV_MAX_NR_BRANCHES] = { 769, 619, 509, 421, 353, 307, 269, 239 }; +static const int16_t init_loop_delay[IVAS_REV_MAX_NR_BRANCHES] = { 37, 31, 29, 23, 19, 17, 13, 11 }; +static const int16_t default_loop_delay_48k[IVAS_REV_MAX_NR_BRANCHES] = { 2309, 1861, 1523, 1259, 1069, 919, 809, 719 }; +static const int16_t default_loop_delay_32k[IVAS_REV_MAX_NR_BRANCHES] = { 1531, 1237, 1013, 839, 709, 613, 541, 479 }; +static const int16_t default_loop_delay_16k[IVAS_REV_MAX_NR_BRANCHES] = { 769, 619, 509, 421, 353, 307, 269, 239 }; /*------------------------------------------------------------------------------------------* * Local Struct definition @@ -682,8 +682,6 @@ static ivas_error initialize_reverb_filters( { ivas_error error; - error = IVAS_ERR_OK; - /* init correlation and coloration filters */ if ( ( error = ivas_reverb_t2f_f2t_init( &hReverb->fft_filter_ols, hReverb->fft_size, hReverb->fft_subblock_size ) ) != IVAS_ERR_OK ) { @@ -710,7 +708,7 @@ static ivas_error initialize_reverb_filters( return error; } - return error; + return IVAS_ERR_OK; } @@ -1060,7 +1058,6 @@ ivas_error ivas_reverb_open( int16_t fft_hist_size, transition_start, transition_length; int16_t nr_fc_input, nr_fc_fft_filter; - error = IVAS_ERR_OK; output_frame = (int16_t) ( output_Fs / FRAMES_PER_SEC ); subframe_len = output_frame / MAX_PARAM_SPATIAL_SUBFRAMES; predelay_bf_len = output_frame; @@ -1240,7 +1237,7 @@ ivas_error ivas_reverb_open( *hReverb = pState; - return error; + return IVAS_ERR_OK; } @@ -1859,12 +1856,13 @@ static ivas_error ivas_binaural_reverb_open( return IVAS_ERR_OK; } + /*------------------------------------------------------------------------- * ivas_binaural_reverb_init() * - * Allocate and initialize binaural room reverberator handle - * for CLDFB renderers + * Initialize binaural room reverberator handle for FastConv renderer *------------------------------------------------------------------------*/ + ivas_error ivas_binaural_reverb_init( REVERB_STRUCT_HANDLE *hReverbPr, /* i/o: binaural reverb handle */ const HRTFS_STATISTICS_HANDLE hHrtfStatistics, /* i : HRTF statistics handle */ @@ -1873,9 +1871,8 @@ ivas_error ivas_binaural_reverb_init( const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *roomAcoustics, /* i/o: room acoustics parameters */ const int32_t sampling_rate, /* i : sampling rate */ const float *defaultTimes, /* i : default reverberation times */ - const float *defaultEne /* i : default reverberation energies */ - , - float *earlyEne /* i/o: Early part energies to be modified */ + const float *defaultEne, /* i : default reverberation energies */ + float *earlyEne /* i/o: Early part energies to be modified */ ) { ivas_error error; @@ -1883,24 +1880,23 @@ ivas_error ivas_binaural_reverb_init( float revTimes[CLDFB_NO_CHANNELS_MAX]; float revEne[CLDFB_NO_CHANNELS_MAX]; - error = IVAS_ERR_OK; - if ( roomAcoustics != NULL ) { - - if ( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics, - hHrtfStatistics, - sampling_rate, - revTimes, - revEne ) ) != IVAS_ERR_OK ) + if ( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics, hHrtfStatistics, sampling_rate, revTimes, revEne ) ) != IVAS_ERR_OK ) { return error; } - preDelay = (int16_t) roundf( 48000.0f * roomAcoustics->acousticPreDelay / CLDFB_NO_CHANNELS_MAX ); + + /* Convert preDelay from seconds to CLDFB slots as needed by binaural reverb */ + preDelay = (int16_t) roundf( roomAcoustics->acousticPreDelay * CLDFB_SLOTS_PER_SECOND ); } else { +#ifdef FIX_1995_REVERB_INIT + for ( bin = 0; bin < numBins; bin++ ) +#else for ( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ ) +#endif { revTimes[bin] = defaultTimes[bin]; revEne[bin] = defaultEne[bin]; @@ -1908,7 +1904,11 @@ ivas_error ivas_binaural_reverb_init( preDelay = 10; } +#ifdef FIX_1995_REVERB_INIT + for ( bin = 0; bin < numBins; bin++ ) +#else for ( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ ) +#endif { /* Adjust the room effect parameters when the reverberation time is less than a threshold value, to avoid spectral artefacts with the synthetic reverberator. */ @@ -1924,13 +1924,17 @@ ivas_error ivas_binaural_reverb_init( energyModifier = ( adjustedRevTime - revTimes[bin] ) / adjustedRevTime; /* Adjust early and late energies, by moving late energy to early energy */ - adjustedEarlyEne = earlyEne[bin] + revEne[bin] * energyModifier; + if ( earlyEne != NULL ) + { + adjustedEarlyEne = earlyEne[bin] + revEne[bin] * energyModifier; + earlyEne[bin] = adjustedEarlyEne; /* Store already here */ + } + adjustedLateEne = revEne[bin] * ( 1.0f - energyModifier ); /* Store adjusted room effect parameters to be used in reverb processing */ revTimes[bin] = adjustedRevTime; revEne[bin] = adjustedLateEne; - earlyEne[bin] = adjustedEarlyEne; } } @@ -1939,6 +1943,7 @@ ivas_error ivas_binaural_reverb_init( return error; } + /*------------------------------------------------------------------------- * ivas_binaural_reverb_close() * diff --git a/lib_rend/ivas_rom_rend.c b/lib_rend/ivas_rom_rend.c index b14a5303a0f40b052ce7224d39247b7346f6abec..3f4b906bd6fdaa8159f22abe9ed3fb2686c3fd6e 100644 --- a/lib_rend/ivas_rom_rend.c +++ b/lib_rend/ivas_rom_rend.c @@ -163,15 +163,9 @@ const float ap_lattice_coeffs_3[DIRAC_DECORR_FILTER_LEN_3*DIRAC_MAX_NUM_DECORR_F const float * const ap_lattice_coeffs[DIRAC_DECORR_NUM_SPLIT_BANDS] = { -#ifdef CODE_IMPROVEMENTS ap_lattice_coeffs_1, ap_lattice_coeffs_2, ap_lattice_coeffs_3, -#else - &ap_lattice_coeffs_1[0], - &ap_lattice_coeffs_2[0], - &ap_lattice_coeffs_3[0], -#endif }; const float ap_split_frequencies[DIRAC_DECORR_NUM_SPLIT_BANDS + 1] = @@ -183,11 +177,13 @@ const int16_t sba_map_tc[11] = { 0, 1, 2, 3, 4, 8, 9, 15, 5, 6, 7 }; + const int16_t sba_map_tc_512[11] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15 }; + /*----------------------------------------------------------------------------------* * FASTCONV and PARAMETRIC binaural renderer ROM tables *----------------------------------------------------------------------------------*/ @@ -386,6 +382,7 @@ const float ivas_reverb_default_DSR[IVAS_REVERB_DEFAULT_N_BANDS] = 6.2001e-08f, 2.8483e-08f, 2.6267e-08f }; + /*----------------------------------------------------------------------------------* * Renderer SBA & MC enc/dec matrices *----------------------------------------------------------------------------------*/ @@ -394,6 +391,7 @@ const float ivas_reverb_default_DSR[IVAS_REVERB_DEFAULT_N_BANDS] = const float ls_azimuth_CICP1[1] = { 0.0f }; const float ls_elevation_CICP1[1] = { 0.0f }; + /*----------------------------------------------------------------------------------* * EFAP ROM tables *----------------------------------------------------------------------------------*/ diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index e990c336f69e0d8c2e45520c92754ff21f3a992d..69fcb30fb803f590f19fb50517892a98ecc97f9c 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -1371,6 +1371,22 @@ typedef struct } CLDFB_REND_WRAPPER; +/*----------------------------------------------------------------------------------* + * Time domain ring buffer structure + *----------------------------------------------------------------------------------*/ + +typedef struct +{ + float *data; /* samples in interleaved layout */ + uint32_t capacity; + uint16_t num_channels; + uint32_t write_pos; + uint32_t read_pos; + int16_t is_full; + +} TD_RINGBUF_DATA, *TD_RINGBUF_HANDLE; + + /*----------------------------------------------------------------------------------* * MASA external renderer structure *----------------------------------------------------------------------------------*/ diff --git a/lib_rend/ivas_td_ring_buffer.c b/lib_rend/ivas_td_ring_buffer.c new file mode 100644 index 0000000000000000000000000000000000000000..5c9c6089bbc41150c6469cd8240a1df3741b38ce --- /dev/null +++ b/lib_rend/ivas_td_ring_buffer.c @@ -0,0 +1,288 @@ +/****************************************************************************************************** + + (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include +#include "ivas_error_utils.h" +#include "ivas_prot_rend.h" +#include "options.h" +#include "wmc_auto.h" + + +/*-----------------------------------------------------------------------* + * Local function prototypes + *-----------------------------------------------------------------------*/ + +static uint32_t ivas_td_ringbuf_total_size( + TD_RINGBUF_HANDLE h ) +{ + if ( h->is_full ) + { + return h->capacity; + } + + if ( h->read_pos <= h->write_pos ) + { + return h->write_pos - h->read_pos; + } + /* else wrap around */ + return h->write_pos + h->capacity - h->read_pos; +} + + +static int16_t ivas_td_ringbuf_has_space_for_num_samples( + TD_RINGBUF_HANDLE h, + const uint32_t num_samples ) +{ + return (int16_t) ( ivas_td_ringbuf_total_size( h ) + num_samples <= h->capacity ); +} + + +/*-----------------------------------------------------------------------* + * Global function definitions + *-----------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Open() + * + * Allocate a ring buffer for TD data with the given capacity of TD samples per channel. + * + * May return IVAS_ERR_FAILED_ALLOC on failed allocation, or IVAS_ERR_OK otherwise. + *---------------------------------------------------------------------*/ + +ivas_error ivas_TD_RINGBUF_Open( + TD_RINGBUF_HANDLE *ph, /* i/o: Ring buffer handle */ + const uint32_t capacity_per_channel, /* i : Number of samples stored per channel */ + const uint16_t num_channels /* i : Number of channels */ +) +{ + TD_RINGBUF_HANDLE h; + uint32_t capacity; + + capacity = capacity_per_channel * num_channels; + + h = malloc( sizeof( TD_RINGBUF_DATA ) ); + if ( h == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for TD ring buffer\n" ); + } + h->data = NULL; + h->capacity = 0; + h->num_channels = num_channels; + h->write_pos = 0; + h->read_pos = 0; + h->is_full = 0; + *ph = h; + + h->data = malloc( capacity * sizeof( float ) ); + if ( h->data == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Failed to allocate memory for TD ring buffer\n" ); + } + h->capacity = capacity; + + return IVAS_ERR_OK; +} + + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Close() + * + * Dellocate TD ring buffer. The given handle will be set to NULL. + + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_Close( + TD_RINGBUF_HANDLE *ph /* i/o: Ring buffer handle */ +) +{ + TD_RINGBUF_HANDLE h; + + if ( ph == NULL ) + { + return; + } + h = *ph; + + if ( h == NULL ) + { + return; + } + + if ( h->data != NULL ) + { + free( h->data ); + } + + free( h ); + *ph = NULL; + + return; +} + + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Push() + * + * Push samples onto the back of the TD ring buffer. + * Returns total number of buffered samples (includes number of channels) + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_Push( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const float *data, /* i : Input data */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to store */ +) +{ + uint32_t s; + uint16_t c; + + assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) ); + + for ( s = 0; s < num_samples_per_channel; ++s ) + { + for ( c = 0; c < h->num_channels; ++c ) + { + h->data[h->write_pos] = *( data + c * num_samples_per_channel + s ); + ++h->write_pos; + + if ( h->write_pos == h->capacity ) + { + h->write_pos = 0; + } + } + } + + if ( h->read_pos == h->write_pos ) + { + h->is_full = 1; + } + + return; +} + + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_PushZeros() + * + * Push zero samples onto the back of the TD ring buffer. + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_PushZeros( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + const uint32_t num_samples_per_channel /* i : Number of zeros per channel to store */ +) +{ + uint32_t s; + uint16_t c; + + assert( ivas_td_ringbuf_has_space_for_num_samples( h, num_samples_per_channel * h->num_channels ) ); + if ( !num_samples_per_channel ) + { + return; + } + + for ( s = 0; s < num_samples_per_channel; ++s ) + { + for ( c = 0; c < h->num_channels; ++c ) + { + h->data[h->write_pos] = 0.f; + ++h->write_pos; + + if ( h->write_pos == h->capacity ) + { + h->write_pos = 0; + } + } + } + + if ( h->read_pos == h->write_pos ) + { + h->is_full = 1; + } + + return; +} + + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Pop() + * + * Pop samples from the front of the TD ring buffer. + *---------------------------------------------------------------------*/ + +void ivas_TD_RINGBUF_Pop( + TD_RINGBUF_HANDLE h, /* i/o: Ring buffer handle */ + float *data, /* i : Output data */ + const uint32_t num_samples_per_channel /* i : Number of samples per channel to retrieve */ +) +{ + uint32_t s; + uint16_t c; + + assert( ivas_td_ringbuf_total_size( h ) >= num_samples_per_channel * h->num_channels ); + + for ( s = 0; s < num_samples_per_channel; ++s ) + { + for ( c = 0; c < h->num_channels; ++c ) + { + *( data + c * num_samples_per_channel + s ) = h->data[h->read_pos]; + ++h->read_pos; + + if ( h->read_pos == h->capacity ) + { + h->read_pos = 0; + } + } + } + + if ( h->is_full ) + { + h->is_full = 0; + } + + return; +} + + +/*---------------------------------------------------------------------* + * ivas_TD_RINGBUF_Size() + * + * Returns number of buffered samples per channel. + *---------------------------------------------------------------------*/ + +uint32_t ivas_TD_RINGBUF_Size( + const TD_RINGBUF_HANDLE h /* i : Ring buffer handle */ +) +{ + return ivas_td_ringbuf_total_size( h ) / (uint32_t) h->num_channels; +} diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index d9866de0506d69dab80fcab91c815c8ec85ada04..4d12d71e39138e721281b15aea5b87c3f4385d03 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -81,6 +81,7 @@ typedef struct typedef struct { const int32_t *pOutSampleRate; + const int32_t *pMaxGlobalDelayNs; const AUDIO_CONFIG *pOutConfig; const LSSETUP_CUSTOM_STRUCT *pCustomLsOut; const EFAP_WRAPPER *pEfapOutWrapper; @@ -97,9 +98,11 @@ typedef struct AUDIO_CONFIG inConfig; IVAS_REND_InputId id; IVAS_REND_AudioBuffer inputBuffer; + TD_RINGBUF_HANDLE delayBuffer; float gain; /* Linear, not in dB */ rendering_context ctx; int32_t numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */ + int32_t delayNumSamples; } input_base; typedef struct @@ -189,6 +192,7 @@ typedef struct hrtf_handles struct IVAS_REND { int32_t sampleRateOut; + int32_t maxGlobalDelayNs; IVAS_LIMITER_HANDLE hLimiter; #ifdef DEBUGGING @@ -204,11 +208,12 @@ struct IVAS_REND AUDIO_CONFIG outputConfig; EFAP_WRAPPER efapOutWrapper; IVAS_LSSETUP_CUSTOM_STRUCT customLsOut; + + int16_t splitRendBFI; SPLIT_REND_WRAPPER *splitRendWrapper; IVAS_REND_AudioBuffer splitRendEncBuffer; IVAS_REND_HeadRotData headRotData; - int16_t splitRendBFI; EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData; COMBINED_ORIENTATION_HANDLE hCombinedOrientationData; @@ -262,6 +267,13 @@ static void freeInputBaseBufferData( return; } +static int16_t latencyNsToSamples( + int32_t sampleRate, + int32_t latency_ns ) +{ + return (int16_t) roundf( (float) ( latency_ns ) * ( sampleRate / 1000000000.f ) ); +} + static ivas_error allocateMcLfeDelayBuffer( float **lfeDelayBuffer, const int16_t data_size ) @@ -369,7 +381,7 @@ static void copyBufferToCLDFBarray( static void accumulateCLDFBArrayToBuffer( float re[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float im[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], - IVAS_REND_AudioBuffer *buffer ) + const IVAS_REND_AudioBuffer *buffer ) { uint32_t smplIdx, slotIdx; uint32_t numCldfbSamples, num_bands; @@ -1162,6 +1174,8 @@ static void initRendInputBase( inputBase->gain = 1.0f; inputBase->ctx = rendCtx; inputBase->numNewSamplesPerChannel = 0; + inputBase->delayNumSamples = 0; + inputBase->delayBuffer = NULL; inputBase->inputBuffer.config.numSamplesPerChannel = 0; inputBase->inputBuffer.config.numChannels = 0; @@ -1210,6 +1224,7 @@ static rendering_context getRendCtx( /* Note: when refactoring this, always take the ADDRESS of a member of the * renderer struct, so that the context stores a POINTER to the member, even * if the member is a pointer or handle itself. */ + ctx.pMaxGlobalDelayNs = &hIvasRend->maxGlobalDelayNs; ctx.pOutConfig = &hIvasRend->outputConfig; ctx.pOutSampleRate = &hIvasRend->sampleRateOut; ctx.pCustomLsOut = &hIvasRend->customLsOut; @@ -1252,6 +1267,272 @@ static bool isIoConfigPairSupported( } +static int32_t getRendInputDelayIsm( + const input_ism *inputIsm, + bool splitPreRendCldfb ) +{ + int32_t latency_ns; + latency_ns = 0; + (void) ( splitPreRendCldfb ); /* unused */ + + /* set the rendering delay in InputBase */ + latency_ns = max( latency_ns, + inputIsm->tdRendWrapper.binaural_latency_ns ); + if ( inputIsm->crendWrapper != NULL ) + { + latency_ns = max( latency_ns, + inputIsm->crendWrapper->binaural_latency_ns ); + } + + return latency_ns; +} + + +static void setRendInputDelayIsm( + void *input, + bool splitPreRendCldfb ) +{ + input_ism *inputIsm; + inputIsm = (input_ism *) input; + + inputIsm->base.delayNumSamples = latencyNsToSamples( *inputIsm->base.ctx.pOutSampleRate, + getRendInputDelayIsm( inputIsm, splitPreRendCldfb ) ); +} + + +static int32_t getRendInputDelayMc( + const input_mc *inputMc, + bool splitPreRendCldfb ) +{ + int32_t latency_ns; + latency_ns = 0; + (void) ( splitPreRendCldfb ); /* unused */ + + latency_ns = max( latency_ns, + inputMc->tdRendWrapper.binaural_latency_ns ); + if ( inputMc->crendWrapper != NULL ) + { + latency_ns = max( latency_ns, + inputMc->crendWrapper->binaural_latency_ns ); + } + + return latency_ns; +} + + +static void setRendInputDelayMc( + void *input, + bool splitPreRendCldfb ) +{ + input_mc *inputMc; + inputMc = (input_mc *) input; + + inputMc->base.delayNumSamples = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, + getRendInputDelayMc( inputMc, splitPreRendCldfb ) ); +} + + +static int32_t getRendInputDelaySba( + const input_sba *inputSba, + bool splitPreRendCldfb ) +{ + int32_t latency_ns; + latency_ns = 0; + + if ( inputSba->cldfbRendWrapper.hCldfbRend != NULL ) + { + latency_ns = max( latency_ns, + inputSba->cldfbRendWrapper.binaural_latency_ns + + ( splitPreRendCldfb ? 0 : IVAS_FB_DEC_DELAY_NS ) ); + } + if ( inputSba->crendWrapper != NULL ) + { + latency_ns = max( latency_ns, + inputSba->crendWrapper->binaural_latency_ns ); + } + + return latency_ns; +} + + +static void setRendInputDelaySba( + void *input, + bool splitPreRendCldfb ) +{ + input_sba *inputSba; + inputSba = (input_sba *) input; + + inputSba->base.delayNumSamples = latencyNsToSamples( *inputSba->base.ctx.pOutSampleRate, + getRendInputDelaySba( inputSba, splitPreRendCldfb ) ); +} + + +static int32_t getRendInputDelayMasa( + const input_masa *inputMasa, + bool splitPreRendCldfb ) +{ + int32_t latency_ns; + + latency_ns = 0; + + if ( ( inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA1 && *inputMasa->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_MONO ) || + ( getAudioConfigType( *inputMasa->base.ctx.pOutConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) ) + { + return 0; /* no delay */ + } + else + { + /* no delay applied for split rendering */ + latency_ns = max( latency_ns, + (int32_t) ( ( splitPreRendCldfb ? 0 : (float) IVAS_FB_DEC_DELAY_NS + 0.5f ) ) ); + } + return latency_ns; +} + + +static void setRendInputDelayMasa( + void *input, + bool splitPreRendCldfb ) +{ + input_masa *inputMasa; + inputMasa = (input_masa *) input; + + inputMasa->base.delayNumSamples = latencyNsToSamples( *inputMasa->base.ctx.pOutSampleRate, + getRendInputDelayMasa( inputMasa, splitPreRendCldfb ) ); +} + + +static int32_t getMaxGlobalDelayNs( IVAS_REND_CONST_HANDLE hIvasRend ) +{ + int16_t i; + int32_t latency_ns; + int32_t max_latency_ns; + bool splitPreRendCldfb; + + max_latency_ns = 0; + /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/ + if ( hIvasRend->hRendererConfig != NULL ) + { + splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD ); + } + else + { + splitPreRendCldfb = false; + } + + /* Compute the maximum delay across all inputs */ + for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ ) + { + if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelayIsm( &hIvasRend->inputsIsm[i], splitPreRendCldfb ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ ) + { + if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelayMc( &hIvasRend->inputsMc[i], splitPreRendCldfb ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ ) + { + if ( hIvasRend->inputsSba[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelaySba( &hIvasRend->inputsSba[i], splitPreRendCldfb ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ ) + { + if ( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + latency_ns = getRendInputDelayMasa( &hIvasRend->inputsMasa[i], splitPreRendCldfb ); + max_latency_ns = max( max_latency_ns, latency_ns ); + } + } + + return max_latency_ns; +} + + +static void setMaxGlobalDelayNs( IVAS_REND_HANDLE hIvasRend ) +{ + hIvasRend->maxGlobalDelayNs = getMaxGlobalDelayNs( (IVAS_REND_CONST_HANDLE) hIvasRend ); +} + +static ivas_error alignInputDelay( + input_base *inputBase, + const IVAS_REND_ReadOnlyAudioBuffer inputAudio, + const int32_t maxGlobalDelayNs, + const int32_t sampleRateOut, + const int16_t cldfb2tdSampleFact, + const bool flushInputs ) +{ + ivas_error error; + input_ism *inputIsm; + int16_t maxGlobalDelaySamples; + int32_t numSamplesToPush, numSamplesToPop; + uint32_t ringBufferSize, preDelay; + + maxGlobalDelaySamples = latencyNsToSamples( sampleRateOut, maxGlobalDelayNs ); + maxGlobalDelaySamples *= cldfb2tdSampleFact; + + /* check if we need to open the delay buffer */ + if ( inputBase->delayBuffer == NULL ) + { + /* buffer has to accomodate maxGlobalDelaySamples + 2 * frameSize */ + ringBufferSize = maxGlobalDelaySamples + 2 * inputAudio.config.numSamplesPerChannel; + + /* pre delay for this input is maximum delay - input delay */ + preDelay = maxGlobalDelaySamples - inputBase->delayNumSamples * cldfb2tdSampleFact; + + if ( preDelay > 0 ) + { + if ( ( error = ivas_TD_RINGBUF_Open( &inputBase->delayBuffer, ringBufferSize, inputAudio.config.numChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* for the first frame we need to push zeros to align the input delay to the global delay + * and then push a frame of actual data */ + ivas_TD_RINGBUF_PushZeros( inputBase->delayBuffer, preDelay ); + + /* for ISM inputs, ensure the metadata sync delay is updated */ + if ( getAudioConfigType( inputBase->inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) + { + inputIsm = (input_ism *) inputBase; + inputIsm->ism_metadata_delay_ms = maxGlobalDelayNs / 1e6f; + } + } + } + + if ( inputBase->delayBuffer != NULL ) + { + /* push in the new input data and pop to retrieve a complete input frame + * if we are flushing the inputs, we don't push in any new data */ + numSamplesToPush = flushInputs ? 0 : inputAudio.config.numSamplesPerChannel; + numSamplesToPop = flushInputs ? ivas_TD_RINGBUF_Size( inputBase->delayBuffer ) : (uint32_t) inputAudio.config.numSamplesPerChannel; + + ivas_TD_RINGBUF_Push( inputBase->delayBuffer, inputAudio.data, numSamplesToPush ); + ivas_TD_RINGBUF_Pop( inputBase->delayBuffer, inputBase->inputBuffer.data, numSamplesToPop ); + } + else + { + /* delay buffer isn't open - we don't need it */ + mvr2r( inputAudio.data, + inputBase->inputBuffer.data, + inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels ); + } + + return IVAS_ERR_OK; +} + static ivas_error initIsmMasaRendering( input_ism *inputIsm, const int32_t inSampleRate ) @@ -1327,7 +1608,11 @@ static ivas_error setRendInputActiveIsm( if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { +#ifdef NONBE_1377_REND_DIRATT_CONF + if ( ( error = ivas_td_binaural_open_ext( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, id ) ) != IVAS_ERR_OK ) +#else if ( ( error = ivas_td_binaural_open_ext( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -1335,7 +1620,11 @@ static ivas_error setRendInputActiveIsm( /* Open TD renderer wrappers */ for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i ) { +#ifdef NONBE_1377_REND_DIRATT_CONF + if ( ( error = ivas_td_binaural_open_ext( &inputIsm->splitTdRendWrappers[i], inConfig, hRendCfg, NULL, *inputIsm->base.ctx.pOutSampleRate, id ) ) != IVAS_ERR_OK ) +#else if ( ( error = ivas_td_binaural_open_ext( &inputIsm->splitTdRendWrappers[i], inConfig, hRendCfg, NULL, *inputIsm->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -1353,7 +1642,11 @@ static ivas_error setRendInputActiveIsm( } else { +#ifdef NONBE_1377_REND_DIRATT_CONF + if ( ( error = ivas_td_binaural_open_ext( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, id ) ) != IVAS_ERR_OK ) +#else if ( ( error = ivas_td_binaural_open_ext( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -1387,6 +1680,8 @@ static void clearInputIsm( rendCtx = inputIsm->base.ctx; freeInputBaseBufferData( &inputIsm->base.inputBuffer.data ); + ivas_TD_RINGBUF_Close( &inputIsm->base.delayBuffer ); + initRendInputBase( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); /* Free input's internal handles */ @@ -2108,7 +2403,11 @@ static ivas_error initMcBinauralRendering( if ( useTDRend && inputMc->tdRendWrapper.hBinRendererTd == NULL ) { +#ifdef NONBE_1377_REND_DIRATT_CONF + if ( ( error = ivas_td_binaural_open_ext( &inputMc->tdRendWrapper, inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, 0 ) ) != IVAS_ERR_OK ) +#else if ( ( error = ivas_td_binaural_open_ext( &inputMc->tdRendWrapper, inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -2118,7 +2417,11 @@ static ivas_error initMcBinauralRendering( /* Open TD renderer wrappers */ for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i ) { +#ifdef NONBE_1377_REND_DIRATT_CONF + if ( ( error = ivas_td_binaural_open_ext( &inputMc->splitTdRendWrappers[i], inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, 0 ) ) != IVAS_ERR_OK ) +#else if ( ( error = ivas_td_binaural_open_ext( &inputMc->splitTdRendWrappers[i], inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate ) ) != IVAS_ERR_OK ) +#endif { return error; } @@ -2157,7 +2460,7 @@ static ivas_error initMcBinauralRendering( /* determine binaural delay ( used for aligning LFE to output signal ) */ binauralDelayNs = max( ( inputMc->crendWrapper != NULL ) ? inputMc->crendWrapper->binaural_latency_ns : 0, inputMc->tdRendWrapper.binaural_latency_ns ); - inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f ); + inputMc->binauralDelaySmp = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, binauralDelayNs ); if ( inputMc->binauralDelaySmp > MAX_BIN_DELAY_SAMPLES ) { @@ -2357,6 +2660,8 @@ static void clearInputMc( freeMcLfeDelayBuffer( &inputMc->lfeDelayBuffer ); freeInputBaseBufferData( &inputMc->bufferData ); + ivas_TD_RINGBUF_Close( &inputMc->base.delayBuffer ); + initRendInputBase( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); /* Free input's internal handles */ @@ -2644,7 +2949,7 @@ static ivas_error setRendInputActiveSba( return error; } - return error; + return IVAS_ERR_OK; } @@ -2656,6 +2961,7 @@ static void clearInputSba( rendCtx = inputSba->base.ctx; freeInputBaseBufferData( &inputSba->bufferData ); + ivas_TD_RINGBUF_Close( &inputSba->base.delayBuffer ); initRendInputBase( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 ); @@ -2735,6 +3041,7 @@ static void clearInputMasa( rendCtx = inputMasa->base.ctx; freeInputBaseBufferData( &inputMasa->bufferData ); + ivas_TD_RINGBUF_Close( &inputMasa->base.delayBuffer ); masaPrerendClose( &inputMasa->hMasaPrerend ); freeMasaExtRenderer( &inputMasa->hMasaExtRend ); @@ -2804,7 +3111,7 @@ ivas_error IVAS_REND_Open( hIvasRend->num_subframes = num_subframes; /* Initialize limiter */ - if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { return error; } @@ -2863,6 +3170,9 @@ ivas_error IVAS_REND_Open( isar_init_split_rend_handles( hIvasRend->splitRendWrapper ); } hIvasRend->splitRendEncBuffer.data = NULL; + hIvasRend->splitRendEncBuffer.config.is_cldfb = 0; + hIvasRend->splitRendEncBuffer.config.numChannels = 0; + hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = 0; for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) { @@ -3058,7 +3368,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( hIvasRend->customLsOut = makeCustomLsSetup( layout ); /* Re-initialize limiter - number of output channels may have changed */ - if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { return error; } @@ -3116,12 +3426,12 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( /*-------------------------------------------------------------------* - * IVAS_REND_NumOutChannels() + * IVAS_REND_GetNumOutChannels() * * *-------------------------------------------------------------------*/ -ivas_error IVAS_REND_NumOutChannels( +ivas_error IVAS_REND_GetNumOutChannels( IVAS_REND_CONST_HANDLE hIvasRend, int16_t *numOutChannels ) { @@ -3291,7 +3601,7 @@ static ivas_error getConstInputById( return IVAS_ERR_OK; } -#ifdef CODE_IMPROVEMENTS + static void *getInputByIndex( void *inputsArray, const size_t index, @@ -3308,61 +3618,39 @@ static void *getInputByIndex( case IVAS_REND_AUDIO_CONFIG_TYPE_MASA: return (input_masa *) inputsArray + index; default: - /* this should be unreachable */ - assert( 0 ); - return NULL; + break; } + + /* this should be unreachable */ + assert( 0 ); + + /* include a final return to make the linter happy and avoid problems with wmc_tool (see #1355) */ + return NULL; } -#endif + static ivas_error findFreeInputSlot( -#ifdef CODE_IMPROVEMENTS void *inputs, const IVAS_REND_AudioConfigType inputType, -#else - const void *inputs, - const int32_t inputStructSize, -#endif const int32_t maxInputs, int32_t *inputIndex ) { -#ifdef CODE_IMPROVEMENTS /* Using a void pointer and a separately provided type is a hack for this function to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa). Assumptions: - input_base is always the first member in the input struct - memory alignments of original input type and input_base are the same */ -#else - /* Using a void pointer and a separately provided size is a hack for this function - to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa). - Assumptions: - - input_base is always the first member in the input struct - - provided size is correct - */ -#endif - int32_t i; bool canAddInput; -#ifndef CODE_IMPROVEMENTS - const uint8_t *pByte; -#endif const input_base *pInputBase; canAddInput = false; /* Find first unused input in array */ -#ifdef CODE_IMPROVEMENTS for ( i = 0; i < maxInputs; ++i ) -#else - for ( i = 0, pByte = inputs; i < maxInputs; ++i, pByte += inputStructSize ) -#endif { -#ifdef CODE_IMPROVEMENTS pInputBase = (const input_base *) getInputByIndex( inputs, i, inputType ); -#else - pInputBase = (const input_base *) pByte; -#endif if ( pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID ) { @@ -3392,10 +3680,15 @@ static int16_t getCldfbRendFlag( const IVAS_REND_AudioConfigType new_configType ) { int16_t i; - int16_t numMasaInputs = 0, numSbaInputs = 0, numIsmInputs = 0, numMcInputs = 0; + int16_t numMasaInputs = 0, numSbaInputs = 0; int16_t isCldfbRend; isCldfbRend = 0; + /* This function is called during three different phases of renderer processing: + * - IVAS_REND_AddInput() + * - IVAS_REND_FeedRenderConfig() + * - IVAS_REND_GetSplitBinauralBitstream() + * Only the last case can assume all inputs are present for the current frame to be rendered */ if ( hIvasRend->hRendererConfig != NULL ) { for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i ) @@ -3406,20 +3699,7 @@ static int16_t getCldfbRendFlag( { numSbaInputs += ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1; } - for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) - { - numIsmInputs += ( hIvasRend->inputsIsm[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) ? 0 : 1; - } - for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i ) - { - numMcInputs += ( hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? 0 : 1; - } - - if ( numIsmInputs > 0 || numMcInputs > 0 ) - { - isCldfbRend = 0; - } - else if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) + if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) { isCldfbRend = 1; } @@ -3429,12 +3709,12 @@ static int16_t getCldfbRendFlag( } /*------------------------------------------------------------------------- - * Function ivas_pre_rend_init() + * Function isar_pre_rend_init() * * *------------------------------------------------------------------------*/ -static ivas_error ivas_pre_rend_init( +static ivas_error isar_pre_rend_init( SPLIT_REND_WRAPPER *pSplitRendWrapper, IVAS_REND_AudioBuffer *pSplitRendEncBuffer, ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config, @@ -3444,10 +3724,20 @@ static ivas_error ivas_pre_rend_init( const int16_t cldfb_in_flag, const int16_t num_subframes ) { + bool realloc; ivas_error error; IVAS_REND_AudioBufferConfig bufConfig; - if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + realloc = false; + + /* only perform init if split rendering output */ + if ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + return IVAS_ERR_OK; + } + + /* these functions should only be called once during initial allocation */ + if ( pSplitRendEncBuffer->data == NULL ) { if ( pSplit_rend_config->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) { @@ -3462,28 +3752,34 @@ static ivas_error ivas_pre_rend_init( { return error; } + } + + /* We may need to change the allocated buffer size if a new input is added. + * If the cldfb_in_flag is different from what was previously allocated for the buffer, change the size */ + if ( pSplitRendEncBuffer->data != NULL && ( cldfb_in_flag != pSplitRendEncBuffer->config.is_cldfb ) ) + { + realloc = true; + } - /*allocate for CLDFB in and change to TD during process if needed*/ - bufConfig.numSamplesPerChannel = MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL; + if ( pSplitRendEncBuffer->data == NULL || realloc ) + { + /* set buffer config */ + bufConfig.is_cldfb = cldfb_in_flag; + bufConfig.numSamplesPerChannel = cldfb_in_flag ? MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL : L_FRAME_MAX; bufConfig.numChannels = BINAURAL_CHANNELS * pSplitRendWrapper->multiBinPoseData.num_poses; - bufConfig.is_cldfb = 1; pSplitRendEncBuffer->config = bufConfig; + /* allocate memory */ + if ( realloc ) + { + free( pSplitRendEncBuffer->data ); + } + if ( ( pSplitRendEncBuffer->data = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( float ) ) ) == NULL ) { return IVAS_ERR_FAILED_ALLOC; } } - else - { - IVAS_REND_AudioBufferConfig bufConfig2; - - bufConfig2.numSamplesPerChannel = 0; - bufConfig2.numChannels = 0; - bufConfig2.is_cldfb = 0; - pSplitRendEncBuffer->config = bufConfig2; - pSplitRendEncBuffer->data = NULL; - } return IVAS_ERR_OK; } @@ -3504,13 +3800,13 @@ ivas_error IVAS_REND_AddInput( ivas_error error; int32_t maxNumInputsOfType; void *inputsArray; -#ifdef CODE_IMPROVEMENTS IVAS_REND_AudioConfigType inputType; -#else - int32_t inputStructSize; -#endif ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA *, hrtf_handles * ); + void ( *setInputDelay )( void *, bool ); int32_t inputIndex; + bool splitPreRendCldfb; + + splitPreRendCldfb = false; /* Validate function arguments */ if ( hIvasRend == NULL || inputId == NULL ) @@ -3518,80 +3814,75 @@ ivas_error IVAS_REND_AddInput( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) && hIvasRend->splitRendEncBuffer.data == NULL && hIvasRend->hRendererConfig != NULL ) + if ( hIvasRend->hRendererConfig != NULL ) { int16_t cldfb_in_flag; cldfb_in_flag = getCldfbRendFlag( hIvasRend, getAudioConfigType( inConfig ) ); - if ( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper, + &hIvasRend->splitRendEncBuffer, + &hIvasRend->hRendererConfig->split_rend_config, + hIvasRend->headRotData, + hIvasRend->sampleRateOut, + hIvasRend->outputConfig, + cldfb_in_flag, + hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) { return error; } + + /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/ + splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD ); } -#ifdef CODE_IMPROVEMENTS inputType = getAudioConfigType( inConfig ); switch ( inputType ) -#else - switch ( getAudioConfigType( inConfig ) ) -#endif { case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED: maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS; inputsArray = hIvasRend->inputsIsm; -#ifndef CODE_IMPROVEMENTS - inputStructSize = sizeof( *hIvasRend->inputsIsm ); -#endif activateInput = setRendInputActiveIsm; + setInputDelay = setRendInputDelayIsm; break; case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED: maxNumInputsOfType = RENDERER_MAX_MC_INPUTS; inputsArray = hIvasRend->inputsMc; -#ifndef CODE_IMPROVEMENTS - inputStructSize = sizeof( *hIvasRend->inputsMc ); -#endif activateInput = setRendInputActiveMc; + setInputDelay = setRendInputDelayMc; break; case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS: maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS; inputsArray = hIvasRend->inputsSba; -#ifndef CODE_IMPROVEMENTS - inputStructSize = sizeof( *hIvasRend->inputsSba ); -#endif activateInput = setRendInputActiveSba; + setInputDelay = setRendInputDelaySba; break; case IVAS_REND_AUDIO_CONFIG_TYPE_MASA: maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS; inputsArray = hIvasRend->inputsMasa; -#ifndef CODE_IMPROVEMENTS - inputStructSize = sizeof( *hIvasRend->inputsMasa ); -#endif activateInput = setRendInputActiveMasa; + setInputDelay = setRendInputDelayMasa; break; default: return IVAS_ERR_INVALID_INPUT_FORMAT; } - /* Find first free input in array corresponding to input type */ -#ifdef CODE_IMPROVEMENTS + /* Find first free input in array corresponding to input type */ if ( ( error = findFreeInputSlot( inputsArray, inputType, maxNumInputsOfType, &inputIndex ) ) != IVAS_ERR_OK ) -#else - if ( ( error = findFreeInputSlot( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ) != IVAS_ERR_OK ) -#endif { return error; } *inputId = makeInputId( inConfig, inputIndex ); -#ifdef CODE_IMPROVEMENTS if ( ( error = activateInput( getInputByIndex( inputsArray, inputIndex, inputType ), inConfig, *inputId, hIvasRend->hRendererConfig, &hIvasRend->hHrtfs ) ) != IVAS_ERR_OK ) -#else - if ( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, hIvasRend->hRendererConfig, &hIvasRend->hHrtfs ) ) != IVAS_ERR_OK ) -#endif { return error; } + setInputDelay( getInputByIndex( inputsArray, inputIndex, inputType ), splitPreRendCldfb ); + + /* set global maximum delay after adding an input */ + setMaxGlobalDelayNs( hIvasRend ); + return IVAS_ERR_OK; } @@ -3844,6 +4135,9 @@ ivas_error IVAS_REND_RemoveInput( return IVAS_ERR_INVALID_INPUT_FORMAT; } + /* set global maximum delay after removing an input */ + setMaxGlobalDelayNs( hIvasRend ); + return IVAS_ERR_OK; } @@ -3920,11 +4214,6 @@ ivas_error IVAS_REND_GetDelay( int32_t *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */ ) { - /* TODO tmu : this function only returns the maximum delay across all inputs - * Ideally each input has its own delay buffer and everything is aligned (binaural and LFE filtering delays are nonuniform) - */ - int16_t i; - int32_t latency_ns; int32_t max_latency_ns; /* Validate function arguments */ @@ -3933,76 +4222,16 @@ ivas_error IVAS_REND_GetDelay( return IVAS_ERR_UNEXPECTED_NULL_POINTER; } - *timeScale = hIvasRend->sampleRateOut; *nSamples = 0; - max_latency_ns = 0; - - /* Compute the maximum delay across all inputs */ - for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ ) - { - if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = max( ( hIvasRend->inputsIsm[i].crendWrapper != NULL ) ? hIvasRend->inputsIsm[i].crendWrapper->binaural_latency_ns : 0, - hIvasRend->inputsIsm[i].tdRendWrapper.binaural_latency_ns ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - - for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ ) - { - if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = max( ( hIvasRend->inputsMc[i].crendWrapper != NULL ) ? hIvasRend->inputsMc[i].crendWrapper->binaural_latency_ns : 0, - hIvasRend->inputsMc[i].tdRendWrapper.binaural_latency_ns ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - - for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ ) - { - if ( hIvasRend->inputsSba[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - if ( hIvasRend->splitRendWrapper != NULL && hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL ) - { - if ( hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) - { - latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns; - } - else - { - latency_ns = ( hIvasRend->inputsSba[i].crendWrapper != NULL ) ? hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns : 0; - } - max_latency_ns = max( max_latency_ns, latency_ns ); - } - else if ( hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend != NULL ) - { - latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns; - latency_ns += IVAS_FB_DEC_DELAY_NS; - max_latency_ns = max( max_latency_ns, latency_ns ); - } - else - { - latency_ns = ( hIvasRend->inputsSba[i].crendWrapper != NULL ) ? hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns : 0; - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } - } + *timeScale = hIvasRend->sampleRateOut; - for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ ) - { - if ( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - latency_ns = (int32_t) ( (float) IVAS_FB_DEC_DELAY_NS + 0.5f ); - max_latency_ns = max( max_latency_ns, latency_ns ); - } - } + max_latency_ns = getMaxGlobalDelayNs( hIvasRend ); - *nSamples = (int16_t) roundf( (float) max_latency_ns * *timeScale / 1000000000.f ); + *nSamples = latencyNsToSamples( hIvasRend->sampleRateOut, max_latency_ns ); return IVAS_ERR_OK; } - /*-------------------------------------------------------------------* * IVAS_REND_FeedInputAudio() * @@ -4010,9 +4239,10 @@ ivas_error IVAS_REND_GetDelay( *-------------------------------------------------------------------*/ ivas_error IVAS_REND_FeedInputAudio( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - const IVAS_REND_InputId inputId, /* i : ID of the input */ - const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + const IVAS_REND_InputId inputId, /* i : ID of the input */ + const IVAS_REND_ReadOnlyAudioBuffer inputAudio, /* i : buffer with input audio */ + const bool flushInputs /* i : flush input audio */ ) { ivas_error error; @@ -4068,9 +4298,16 @@ ivas_error IVAS_REND_FeedInputAudio( } inputBase->inputBuffer.config = inputAudio.config; - - mvr2r( inputAudio.data, inputBase->inputBuffer.data, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels ); - + if ( ( error = alignInputDelay( + inputBase, + inputAudio, + hIvasRend->maxGlobalDelayNs, + hIvasRend->sampleRateOut, + cldfb2tdSampleFact, + flushInputs ) ) != IVAS_ERR_OK ) + { + return error; + } inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel / cldfb2tdSampleFact; return IVAS_ERR_OK; @@ -4378,6 +4615,7 @@ ivas_error IVAS_REND_FeedRenderConfig( if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL ) { ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb ); + if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, @@ -4395,6 +4633,7 @@ ivas_error IVAS_REND_FeedRenderConfig( if ( pMasaInput->hMasaExtRend->hReverb != NULL ) { ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hReverb ); + if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, @@ -4427,6 +4666,7 @@ ivas_error IVAS_REND_FeedRenderConfig( return error; } } + if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL ) { if ( ( error = ivas_reverb_open( &pMcInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK ) @@ -4477,6 +4717,7 @@ ivas_error IVAS_REND_FeedRenderConfig( { int16_t cldfb_in_flag; cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); + if ( hIvasRend->splitRendWrapper != NULL ) { ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer ); @@ -4484,7 +4725,7 @@ ivas_error IVAS_REND_FeedRenderConfig( hIvasRend->splitRendWrapper = NULL; } - if ( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) + if ( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK ) { return error; } @@ -5213,7 +5454,7 @@ static ivas_error renderIsmToBinaural( push_wmops( "renderIsmToBinaural" ); /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); + ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000.f / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); copyBufferTo2dArray( ismInput->base.inputBuffer, tmpTDRendBuffer ); if ( ( error = ivas_td_binaural_renderer_ext( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, ism_md_subframe_update_ext, @@ -5417,7 +5658,7 @@ static ivas_error renderIsmToBinauralReverb( push_wmops( "renderIsmToBinauralRoom" ); /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); + ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000.f / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); copyBufferTo2dArray( ismInput->base.inputBuffer, tmpRendBuffer ); @@ -5583,8 +5824,10 @@ static ivas_error renderIsmToSplitBinaural( const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData; const SPLIT_REND_WRAPPER *pSplitRendWrapper; IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES]; - int16_t i; + int16_t i, ch, slot_idx, num_bands; float tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; + float tmpBinaural_CldfbRe[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + float tmpBinaural_CldfbIm[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; int16_t output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel; COMBINED_ORIENTATION_HANDLE pCombinedOrientationData; int16_t ism_md_subframe_update_ext; @@ -5595,7 +5838,7 @@ static ivas_error renderIsmToSplitBinaural( pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData; /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */ - ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); + ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / ( 1000.f / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); pCombinedOrientationData = *ismInput->base.ctx.pCombinedOrientationData; @@ -5651,10 +5894,29 @@ static ivas_error renderIsmToSplitBinaural( return error; } - /* Copy rendered audio to tmp storage buffer. Copying directly to output would - * overwrite original audio, which is still needed for rendering next head pose. */ - mvr2r( tmpProcessing[0], tmpBinaural[2 * pos_idx], output_frame ); - mvr2r( tmpProcessing[1], tmpBinaural[2 * pos_idx + 1], output_frame ); + if ( outAudio.config.is_cldfb ) + { + /* Perform CLDFB analysis on rendered audio, since the output buffer is CLDFB domain */ + num_bands = (int16_t) ( ( BINAURAL_MAXBANDS * *ismInput->base.ctx.pOutSampleRate ) / 48000 ); + for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) + { + for ( slot_idx = 0; slot_idx < IVAS_CLDFB_NO_COL_MAX; slot_idx++ ) + { + cldfbAnalysis_ts( &tmpProcessing[ch][num_bands * slot_idx], + &tmpBinaural_CldfbRe[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0], + &tmpBinaural_CldfbIm[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0], + num_bands, + ismInput->base.ctx.pSplitRendWrapper->hCldfbHandles->cldfbAna[pos_idx + ch] ); + } + } + } + else + { + /* Copy rendered audio to tmp storage buffer. Copying directly to output would + * overwrite original audio, which is still needed for rendering next head pose. */ + mvr2r( tmpProcessing[0], tmpBinaural[BINAURAL_CHANNELS * pos_idx], output_frame ); + mvr2r( tmpProcessing[1], tmpBinaural[BINAURAL_CHANNELS * pos_idx + 1], output_frame ); + } /* Overwrite processing buffer with original input audio again */ copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing ); @@ -5666,7 +5928,14 @@ static ivas_error renderIsmToSplitBinaural( pCombinedOrientationData->Quaternions[i] = originalHeadRot[i]; } - accumulate2dArrayToBuffer( tmpBinaural, &outAudio ); + if ( outAudio.config.is_cldfb ) + { + accumulateCLDFBArrayToBuffer( tmpBinaural_CldfbRe, tmpBinaural_CldfbIm, &outAudio ); + } + else + { + accumulate2dArrayToBuffer( tmpBinaural, &outAudio ); + } pop_wmops(); /* Encoding to split rendering bitstream done at a higher level */ @@ -5701,11 +5970,13 @@ static ivas_error renderInputIsm( { ivas_error error; IVAS_REND_AudioBuffer inAudio; + int16_t cldfb2tdSampleFact; error = IVAS_ERR_OK; inAudio = ismInput->base.inputBuffer; - if ( ismInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel ) + cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1; + if ( ismInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != outAudio.config.numSamplesPerChannel ) { return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" ); } @@ -5830,8 +6101,7 @@ static ivas_error renderLfeToBinaural( num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp; num_cpy_smpl_cur_frame = frame_size - num_cpy_smpl_prev_frame; - /* Assuming LFE should be delayed by less that the duration of one frame */ - assert( mcInput->binauralDelaySmp < frame_size ); + assert( mcInput->binauralDelaySmp <= MAX_BIN_DELAY_SAMPLES ); /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */ v_multc( mcInput->lfeDelayBuffer, gain, tmpLfeBuffer, num_cpy_smpl_prev_frame ); @@ -7409,15 +7679,13 @@ ivas_error IVAS_REND_SetIsmMetadataDelay( *-------------------------------------------------------------------*/ static ivas_error getSamplesInternal( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */ - IVAS_REND_BitstreamBuffer *hBits /*i/o: buffer for input/output bitstream. Needed in split rendering mode*/ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ ) { ivas_error error; int16_t numOutChannels; int16_t cldfb2tdSampleFact; - IVAS_REND_AudioBuffer outAudioOrig; /* Validate function arguments */ if ( hIvasRend == NULL || outAudio.data == NULL ) @@ -7477,34 +7745,21 @@ static ivas_error getSamplesInternal( } } - if ( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK ) { return error; } - if ( numOutChannels != outAudio.config.numChannels && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + if ( numOutChannels != outAudio.config.numChannels && + hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && + hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) { return IVAS_ERR_WRONG_NUM_CHANNELS; } - /* Clear original output buffer */ + /* Clear output buffer */ set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); - outAudioOrig = outAudio; - /* Use internal buffer if outputting split rendering bitstream */ - if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || - ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) - { - int16_t num_poses_orig; - num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; - outAudio = hIvasRend->splitRendEncBuffer; - ISAR_PRE_REND_GetMultiBinPoseData( &hIvasRend->hRendererConfig->split_rend_config, &hIvasRend->splitRendWrapper->multiBinPoseData, hIvasRend->headRotData.sr_pose_pred_axis ); - assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" ); - - /* Clear output buffer for split rendering bitstream */ - set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); - } - if ( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ) != IVAS_ERR_OK ) { return error; @@ -7525,73 +7780,26 @@ static ivas_error getSamplesInternal( return error; } - if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) - { - ISAR_SPLIT_REND_BITS_DATA bits; - int16_t cldfb_in_flag; - float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; - float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; - int16_t ch; - int16_t i, ro_md_flag; - float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; - - for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ ) - { - tmpBinaural[ch] = tmpBinaural_buff[ch]; - } - - if ( outAudio.config.is_cldfb == 1 ) - { - cldfb_in_flag = 1; - copyBufferToCLDFBarray( outAudio, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural ); - } - else - { - cldfb_in_flag = 0; - copyBufferTo2dArray( outAudio, tmpBinaural_buff ); - } - - /* Encode split rendering bitstream */ - convertBitsBufferToInternalBitsBuff( *hBits, &bits ); - - ro_md_flag = 0; - for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) - { - if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) - { - ro_md_flag = 1; - break; - } - } + return IVAS_ERR_OK; +} - if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, - hIvasRend->headRotData.headPositions[0], - hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, - hIvasRend->hRendererConfig->split_rend_config.codec, - hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms, - hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms, - &bits, - Cldfb_RealBuffer_Binaural, - Cldfb_ImagBuffer_Binaural, - ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), - tmpBinaural, - 1, - cldfb_in_flag, - ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, - ro_md_flag ) ) != IVAS_ERR_OK ) - { - return error; - } - convertInternalBitsBuffToBitsBuffer( hBits, bits ); +/*-------------------------------------------------------------------* + * IVAS_REND_GetSamples() + * + * + *-------------------------------------------------------------------*/ - /* reset to outAudioOrig in case of PCM output */ - outAudio = outAudioOrig; +ivas_error IVAS_REND_GetSamples( + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ +) +{ + ivas_error error; - if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) - { - accumulate2dArrayToBuffer( tmpBinaural_buff, &outAudio ); - } + if ( ( error = getSamplesInternal( hIvasRend, outAudio ) ) != IVAS_ERR_OK ) + { + return error; } if ( outAudio.config.is_cldfb == 0 ) @@ -7611,22 +7819,6 @@ static ivas_error getSamplesInternal( } -/*-------------------------------------------------------------------* - * IVAS_REND_GetSamples() - * - * - *-------------------------------------------------------------------*/ - -ivas_error IVAS_REND_GetSamples( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */ -) -{ - - return getSamplesInternal( hIvasRend, outAudio, NULL ); -} - - /*-------------------------------------------------------------------* * IVAS_REND_GetSplitBinauralBitstream() * @@ -7639,23 +7831,121 @@ ivas_error IVAS_REND_GetSplitBinauralBitstream( IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */ ) { + ivas_error error; + int16_t ch; int16_t cldfb_in_flag; + int16_t i, ro_md_flag; + int16_t num_poses_orig; + float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; + float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + IVAS_REND_AudioBufferConfig *pSplitEncBufConfig; + ISAR_SPLIT_REND_CONFIG_HANDLE pSplitRendConfig; + ISAR_SPLIT_REND_BITS_DATA bits; + + for ( ch = 0; ch < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ch++ ) + { + tmpBinaural[ch] = tmpBinaural_buff[ch]; + } cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN ); - hIvasRend->splitRendEncBuffer.config.is_cldfb = cldfb_in_flag; - if ( hIvasRend->hRendererConfig->split_rend_config.dof == 0 || hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) + pSplitEncBufConfig = &hIvasRend->splitRendEncBuffer.config; + pSplitRendConfig = &hIvasRend->hRendererConfig->split_rend_config; + + /* 0 DoF / No pose correction retains frame size */ + pSplitEncBufConfig->is_cldfb = cldfb_in_flag; + if ( pSplitRendConfig->dof == 0 || pSplitRendConfig->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) { - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = outAudio.config.numSamplesPerChannel; + pSplitEncBufConfig->numSamplesPerChannel = outAudio.config.numSamplesPerChannel; } + /* Pose correction requires 20ms */ else { - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC ); + pSplitEncBufConfig->numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC ); } - hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel *= cldfb_in_flag ? 2 : 1; + pSplitEncBufConfig->numSamplesPerChannel *= cldfb_in_flag ? 2 : 1; + + num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses; + ISAR_PRE_REND_GetMultiBinPoseData( pSplitRendConfig, + &hIvasRend->splitRendWrapper->multiBinPoseData, + hIvasRend->headRotData.sr_pose_pred_axis ); + assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" ); - /* hIvasRend->splitRendEncBuffer used for BINAURAL_SPLIT_CODED output - outAudio used for BINAURAL_SPLIT_PCM output */ - return getSamplesInternal( hIvasRend, outAudio, hBits ); + /* hIvasRend->splitRendEncBuffer contains multi-pose data for BINAURAL_SPLIT_CODED output + outAudio used later for main pose BINAURAL_SPLIT_PCM output */ + if ( ( error = getSamplesInternal( hIvasRend, hIvasRend->splitRendEncBuffer ) ) != IVAS_ERR_OK ) + { + return error; + } + + /* copy outputs */ + if ( hIvasRend->splitRendEncBuffer.config.is_cldfb == 1 ) + { + cldfb_in_flag = 1; + copyBufferToCLDFBarray( hIvasRend->splitRendEncBuffer, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural ); + } + else + { + cldfb_in_flag = 0; + copyBufferTo2dArray( hIvasRend->splitRendEncBuffer, tmpBinaural_buff ); + } + + /* Encode split rendering bitstream */ + convertBitsBufferToInternalBitsBuff( *hBits, &bits ); + + ro_md_flag = 0; + for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i ) + { + if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID ) + { + ro_md_flag = 1; + break; + } + } + + if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, + hIvasRend->headRotData.headPositions[0], + pSplitRendConfig->splitRendBitRate, + pSplitRendConfig->codec, + pSplitRendConfig->isar_frame_size_ms, + pSplitRendConfig->codec_frame_size_ms, + &bits, + Cldfb_RealBuffer_Binaural, + Cldfb_ImagBuffer_Binaural, + ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), + tmpBinaural, + 1, + cldfb_in_flag, + ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, + ro_md_flag ) ) != IVAS_ERR_OK ) + { + return error; + } + + convertInternalBitsBuffToBitsBuffer( hBits, bits ); + + /* copy over first pose data to outAudio */ + if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + /* set outAudio to zero - getSamplesInternal only cleared splitRendEncBuffer */ + set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel ); + accumulate2dArrayToBuffer( tmpBinaural_buff, &outAudio ); + } + + if ( outAudio.config.is_cldfb == 0 ) + { +#ifndef DISABLE_LIMITER +#ifdef DEBUGGING + hIvasRend->numClipping += +#endif + limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD ); +#endif + } + + /* update global cominbed orientation start index */ + ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel ); + + return IVAS_ERR_OK; } diff --git a/lib_rend/lib_rend.h b/lib_rend/lib_rend.h index 194bca0165ca3f22a16af67ac4a7b9c795d8d91b..ac9516521d0486dcc9224b2f3f6af10e918b81fa 100644 --- a/lib_rend/lib_rend.h +++ b/lib_rend/lib_rend.h @@ -114,15 +114,15 @@ typedef enum _IVAS_REND_COMPLEXITY_LEVEL /* Functions to be called before rendering */ ivas_error IVAS_REND_Open( - IVAS_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */ - const int32_t outputSampleRate, /* i : output sampling rate */ - const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */ - const bool asHrtfBinary, /* i : load hrtf binary file */ - const int16_t nonDiegeticPan, /* i : non-diegetic object flag */ - const float nonDiegeticPanGain, /* i : non-diegetic panning gain */ - const int16_t Opt_Headrotation, /* i : indicates whether head-rotation is used */ - const int16_t Opt_ExternalOrientation, /* i : indicates whether external orientations are used */ - const int16_t num_subframes /* i : number of subframes */ + IVAS_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */ + const int32_t outputSampleRate, /* i : output sampling rate */ + const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */ + const bool asHrtfBinary, /* i : load hrtf binary file */ + const int16_t nonDiegeticPan, /* i : non-diegetic object flag */ + const float nonDiegeticPanGain, /* i : non-diegetic panning gain */ + const int16_t Opt_Headrotation, /* i : indicates whether head-rotation is used */ + const int16_t Opt_ExternalOrientation, /* i : indicates whether external orientations are used */ + const int16_t num_subframes /* i : number of subframes */ ); /* Note: this will reset custom LFE routings set for any MC input */ @@ -134,7 +134,7 @@ ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout( /* Functions to be called before/during rendering */ -ivas_error IVAS_REND_NumOutChannels( +ivas_error IVAS_REND_GetNumOutChannels( IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */ int16_t *numOutChannels /* o : number of output channels */ ); @@ -212,16 +212,17 @@ ivas_error IVAS_REND_GetHrtfParamBinHandle( ); ivas_error IVAS_REND_GetHrtfStatisticsHandle( - IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ - IVAS_DEC_HRTF_STATISTICS_HANDLE **hHrtfStatistics /* o : HRTF statistics handle */ + IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */ + IVAS_DEC_HRTF_STATISTICS_HANDLE **hHrtfStatistics /* o : HRTF statistics handle */ ); /* Functions to be called during rendering */ ivas_error IVAS_REND_FeedInputAudio( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - const IVAS_REND_InputId inputId, /* i : ID of the input */ - const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + const IVAS_REND_InputId inputId, /* i : ID of the input */ + const IVAS_REND_ReadOnlyAudioBuffer inputAudio, /* i : buffer with input audio */ + const bool flushInputs /* i : flush input audio */ ); ivas_error IVAS_REND_FeedInputObjectMetadata( @@ -382,7 +383,7 @@ ivas_error IVAS_REND_GetSamples( /* Functions to be called after rendering */ void IVAS_REND_Close( - IVAS_REND_HANDLE* phIvasRend /* i/o: Pointer to renderer handle */ + IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */ ); diff --git a/lib_util/mime_io.c b/lib_util/mime_io.c index ee2a9c12a5695cb469962508449e0101fcc4794f..1ecd603b32a752b4f819a3636bdedfd1179c4209 100644 --- a/lib_util/mime_io.c +++ b/lib_util/mime_io.c @@ -305,7 +305,9 @@ MIME_ERROR MIME_Writer_Close( } -static bool readByte( FILE *file, uint8_t *value ) +static bool readByte( + FILE *file, + uint8_t *value ) { if ( fread( value, 1, 1, file ) != 1U ) { @@ -314,14 +316,13 @@ static bool readByte( FILE *file, uint8_t *value ) return true; } -static bool readLong( FILE *file, uint16_t *value ) +static bool readLong( + FILE *file, + uint16_t *value ) { char buffer[4] = { 0 }; -#ifdef CODE_IMPROVEMENTS + if ( fread( buffer, 1, 4, file ) != 1U ) -#else - if ( fread( buffer, 4, 1, file ) != 1U ) -#endif { return false; } @@ -346,7 +347,10 @@ static bool readLong( FILE *file, uint16_t *value ) * to the serial bitstream. *-------------------------------------------------------------------*/ -static void byteToSerialReordered( uint8_t byte, uint16_t *serial, const int16_t *sort_indices ) +static void byteToSerialReordered( + uint8_t byte, + uint16_t *serial, + const int16_t *sort_indices ) { for ( uint32_t i = 0; i < 8; ++i ) { @@ -360,8 +364,11 @@ static void byteToSerialReordered( uint8_t byte, uint16_t *serial, const int16_t byte <<= 1; } + + return; } + /*-------------------------------------------------------------------* * byteToSerial() * @@ -369,18 +376,25 @@ static void byteToSerialReordered( uint8_t byte, uint16_t *serial, const int16_t * to the given serial bitstream array. *-------------------------------------------------------------------*/ -static void byteToSerial( uint8_t byte, uint16_t *serial ) +static void byteToSerial( + uint8_t byte, + uint16_t *serial ) { const int16_t indices[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + byteToSerialReordered( byte, serial, indices ); + + return; } -static MIME_ERROR readHeader( MIME_HANDLE hMIME ) + +static MIME_ERROR readHeader( + MIME_HANDLE hMIME ) { const char id[] = "#!EVS_MC1.0\n"; const uint16_t num_char_id = sizeof( id ) - 1; - char buffer[sizeof( id )] = { 0 }; + if ( fread( buffer, sizeof( char ), num_char_id, hMIME->file ) != num_char_id ) { return MIME_READ_ERROR; @@ -398,13 +412,17 @@ static MIME_ERROR readHeader( MIME_HANDLE hMIME ) return MIME_NO_ERROR; } + + /*-------------------------------------------------------------------* * MIME_Reader_Open_filename() * * Open MIME reader *-------------------------------------------------------------------*/ -MIME_ERROR MIME_Reader_Open_filename( MIME_HANDLE *phMIME, const char *filename ) +MIME_ERROR MIME_Reader_Open_filename( + MIME_HANDLE *phMIME, + const char *filename ) { MIME_ERROR error = MIME_NO_ERROR; @@ -440,7 +458,8 @@ MIME_ERROR MIME_Reader_Open_filename( MIME_HANDLE *phMIME, const char *filename * Rewind currently opened file to beginning *-------------------------------------------------------------------*/ -MIME_ERROR MIME_Reader_Rewind( MIME_HANDLE hMIME ) +MIME_ERROR MIME_Reader_Rewind( + MIME_HANDLE hMIME ) { if ( !hMIME || !hMIME->file ) { @@ -455,7 +474,13 @@ MIME_ERROR MIME_Reader_Rewind( MIME_HANDLE hMIME ) return MIME_NO_ERROR; } -static MIME_ERROR readEvsFrame( FILE *file, uint8_t ToC, uint16_t *serial, int16_t *num_bits, int16_t *bfi ) + +static MIME_ERROR readEvsFrame( + FILE *file, + uint8_t ToC, + uint16_t *serial, + int16_t *num_bits, + int16_t *bfi ) { switch ( ToC & 0x0f ) { @@ -524,7 +549,13 @@ static MIME_ERROR readEvsFrame( FILE *file, uint8_t ToC, uint16_t *serial, int16 return MIME_NO_ERROR; } -static MIME_ERROR readAmrWbFrame( FILE *file, uint8_t ToC, uint16_t *serial, int16_t *num_bits, int16_t *bfi ) + +static MIME_ERROR readAmrWbFrame( + FILE *file, + uint8_t ToC, + uint16_t *serial, + int16_t *num_bits, + int16_t *bfi ) { const uint8_t mode = ToC & 0x0f; @@ -595,12 +626,18 @@ static MIME_ERROR readAmrWbFrame( FILE *file, uint8_t ToC, uint16_t *serial, int return MIME_NO_ERROR; } + /*-------------------------------------------------------------------* * MIME_ReadFrame_short() * * Read MIME frame to serial bitstream *-------------------------------------------------------------------*/ -MIME_ERROR MIME_ReadFrame_short( MIME_HANDLE hMIME, uint16_t *serial, int16_t *num_bits, int16_t *bfi ) + +MIME_ERROR MIME_ReadFrame_short( + MIME_HANDLE hMIME, + uint16_t *serial, + int16_t *num_bits, + int16_t *bfi ) { if ( !hMIME ) { @@ -637,12 +674,16 @@ MIME_ERROR MIME_ReadFrame_short( MIME_HANDLE hMIME, uint16_t *serial, int16_t *n return MIME_NO_ERROR; } + + /*-------------------------------------------------------------------* * MIME_Reader_Close() * * Close MIME reader *-------------------------------------------------------------------*/ -MIME_ERROR MIME_Reader_Close( MIME_HANDLE *phMIME ) + +MIME_ERROR MIME_Reader_Close( + MIME_HANDLE *phMIME ) { if ( phMIME == NULL || *phMIME == NULL ) { diff --git a/lib_util/rotation_file_reader.c b/lib_util/rotation_file_reader.c index 024b0837374c9ccbefd5519817ba00dd7e4981ba..cbf36e42ba56ae54f35834971d6bcae38d81d100 100644 --- a/lib_util/rotation_file_reader.c +++ b/lib_util/rotation_file_reader.c @@ -175,6 +175,12 @@ ivas_error ExternalOrientationFileReading( ( externalOrientationReader->frameCounter )++; + /* Only Quaternion orientations are supported, raise an error if Euler angles are detected in the input */ + if ( w == -3.0f ) + { + return IVAS_ERR_EXTERNAL_ORIENTATION_INVALID_FORMAT; + } + pQuaternion->w = w; pQuaternion->x = x; pQuaternion->y = y; diff --git a/lib_util/rtpdump.c b/lib_util/rtpdump.c index ac143bb8f622da3759734c8e9e693d3d747595b2..9b25633a9385f57d14922a659a9bfe932a5dd1d4 100644 --- a/lib_util/rtpdump.c +++ b/lib_util/rtpdump.c @@ -80,11 +80,7 @@ static unsigned char *parseByte( unsigned char *buffer, unsigned char *value ) static int readLong( FILE *file, unsigned int *value ) { char buffer[4] = { 0 }; -#ifdef CODE_IMPROVEMENTS if ( fread( buffer, 1, 4, file ) != 1U ) -#else - if ( fread( buffer, 4, 1, file ) != 1U ) -#endif { return -1; } diff --git a/lib_util/tinywavein_c.h b/lib_util/tinywavein_c.h index 179c676a81b274098fabbe5050c2c977572c82ec..1ff6f26bb78438b2fbb835e483f99c1d46128dce 100644 --- a/lib_util/tinywavein_c.h +++ b/lib_util/tinywavein_c.h @@ -54,22 +54,14 @@ #define __TWI_SUCCESS ( 0 ) #define __TWI_ERROR ( -1 ) -#ifdef CODE_IMPROVEMENTS typedef struct tinyWaveInHandle -#else -typedef struct __tinyWaveInHandle -#endif { FILE *theFile; fpos_t dataChunkPos; uint32_t position; uint32_t length; uint32_t bps; -#ifdef CODE_IMPROVEMENTS } tinyWaveInHandle, WAVEFILEIN; -#else -} __tinyWaveInHandle, WAVEFILEIN; -#endif typedef struct { diff --git a/lib_util/tinywaveout_c.h b/lib_util/tinywaveout_c.h index e7d568dc83c48adf46dc0fcbb3dff7f20fdcaa5c..190bc5eb50ccf2cd1904dec576fe1af9d423e585 100644 --- a/lib_util/tinywaveout_c.h +++ b/lib_util/tinywaveout_c.h @@ -70,27 +70,15 @@ #endif #endif -#ifdef CODE_IMPROVEMENTS typedef struct tinyWaveOutHeader -#else -typedef struct __tinyWaveOutHeader -#endif { uint32_t riffType; /* 'RIFF' */ uint32_t riffSize; /* file size */ uint32_t waveType; /* 'WAVE' */ -#ifdef CODE_IMPROVEMENTS } tinyWaveOutHeader; -#else -} __tinyWaveOutHeader; -#endif -#ifdef CODE_IMPROVEMENTS typedef struct tinyWaveOutFmtChunk -#else -typedef struct __tinyWaveOutFmtChunk -#endif { uint32_t formatType; uint32_t formatSize; @@ -103,31 +91,15 @@ typedef struct __tinyWaveOutFmtChunk uint16_t bitsPerSample; /* wav fmt ext hdr here */ -#ifdef CODE_IMPROVEMENTS } tinyWaveOutFmtChunk; -#else -} __tinyWaveOutFmtChunk; -#endif -#ifdef CODE_IMPROVEMENTS -typedef struct tinyWaveOutDataChunk -#else typedef struct tinyWaveOutDataChunk -#endif { uint32_t dataType; uint32_t dataSize; -#ifdef CODE_IMPROVEMENTS } tinyWaveOutDataChunk; -#else -} __tinyWaveOutDataChunk; -#endif -#ifdef CODE_IMPROVEMENTS typedef struct tinyWaveOutHandle -#else -typedef struct __tinyWaveOutHandle -#endif { FILE *theFile; uint32_t dataSize; @@ -136,11 +108,7 @@ typedef struct __tinyWaveOutHandle uint32_t dataChunkOffset; uint32_t bps; uint32_t clipCount; -#ifdef CODE_IMPROVEMENTS } tinyWaveOutHandle, WAVEFILEOUT; -#else -} __tinyWaveOutHandle, WAVEFILEOUT; -#endif /*--- local protos --------------------------------------------------*/ static __inline uint32_t BigEndian32( char, char, char, char ); @@ -163,15 +131,9 @@ static WAVEFILEOUT *CreateBWF( /* ,const uint32_t writeWaveExt */ ) { WAVEFILEOUT *self; -#ifdef CODE_IMPROVEMENTS tinyWaveOutHeader whdr; tinyWaveOutFmtChunk wfch; tinyWaveOutDataChunk wdch; -#else - __tinyWaveOutHeader whdr; - __tinyWaveOutFmtChunk wfch; - __tinyWaveOutDataChunk wdch; -#endif uint32_t blockAlignment = 0; uint32_t ByteCnt = 0; /* Byte counter for fwrite */ diff --git a/scripts/config/self_test.prm b/scripts/config/self_test.prm index 91f8c5e88daaf9bf96d0e25687bf0f0247b0fb99..aa0413a8913d928841e02d5834f2a0c1060378c7 100644 --- a/scripts/config/self_test.prm +++ b/scripts/config/self_test.prm @@ -2014,9 +2014,9 @@ networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_5.dat bit ../IVAS_cod -ism_masa 2 2 testv/stvISM1.csv testv/stvISM2.csv testv/stv2MASA2TC48c.met ../scripts/switchPaths/sw_13k2_512k_2fr_start_48k_omasatechs_2ism.bin 48 testv/stvOMASA_2ISM_2MASA2TC48c.wav bit ../IVAS_dec -obj_edit ../scripts/object_edit/combined_edit.txt BINAURAL 48 bit testv/stvOMASA_2ISM_2MASA2TC48c.wav_BINAURAL_sw_48-48_OE.tst -// OSBA 3OA 4ISM at 256 kbps, 48kHz in, 48kHz out, BINAURAL out, object editing, DISC +// OSBA 3OA 4ISM at 256 kbps, 48kHz in, 48kHz out, BINAURAL_ROOM_IR out, object editing, DISC ../IVAS_cod -ism_sba 4 3 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv testv/stvISM4.csv 256000 48 testv/stvOSBA_4ISM_3OA48c.wav bit -../IVAS_dec -obj_edit ../scripts/object_edit/combined_edit.txt BINAURAL 48 bit testv/stvOSBA_4ISM_3OA48c.wav_BINAURAL_256000_48-48_OE.tst +../IVAS_dec -obj_edit ../scripts/object_edit/combined_edit.txt BINAURAL_ROOM_IR 48 bit testv/stvOSBA_4ISM_3OA48c.wav_BINAURAL_ROOM_IR_256000_48-48_OE.tst // OSBA 2OA 3ISM at 128 kbps, 48kHz in, 48kHz out, FOA out, object editing, JBM Prof 5, DISC ../IVAS_cod -ism_sba 3 2 testv/stvISM1.csv testv/stvISM2.csv testv/stvISM3.csv 128000 48 testv/stvOSBA_3ISM_2OA48c.wav bit diff --git a/scripts/config/self_test_ltv.prm b/scripts/config/self_test_ltv.prm index 7cd4b5a8bb689361fe59e51597bc64ddf06bbb5a..6f924103ebbdbbb8f8db89fafa01c5b2da9f12ea 100644 --- a/scripts/config/self_test_ltv.prm +++ b/scripts/config/self_test_ltv.prm @@ -2014,9 +2014,9 @@ networkSimulator_g192 ../scripts/dly_error_profiles/dly_error_profile_5.dat bit ../IVAS_cod -ism_masa 2 2 testv/ltv48_OMASA_2ISM_2TC_ISM1.csv testv/ltv48_OMASA_2ISM_2TC_ISM2.csv testv/ltv48_OMASA_2ISM_2TC.met ../scripts/switchPaths/sw_13k2_512k_2fr_start_48k_omasatechs_2ism.bin 48 testv/ltv48_OMASA_2ISM_2TC.wav bit ../IVAS_dec -obj_edit ../scripts/object_edit/combined_edit.txt BINAURAL 48 bit testv/ltv48_OMASA_2ISM_2TC.wav_BINAURAL_sw_48-48_OE.tst -// OSBA 3OA 4ISM at 256 kbps, 48kHz in, 48kHz out, BINAURAL out, object editing, DISC +// OSBA 3OA 4ISM at 256 kbps, 48kHz in, 48kHz out, BINAURAL_ROOM_IR out, object editing, DISC ../IVAS_cod -ism_sba 4 3 testv/ltv48_OSBA_4ISM_HOA3_ISM1.csv testv/ltv48_OSBA_4ISM_HOA3_ISM2.csv testv/ltv48_OSBA_4ISM_HOA3_ISM3.csv testv/ltv48_OSBA_4ISM_HOA3_ISM4.csv 256000 48 testv/ltv48_OSBA_4ISM_HOA3.wav bit -../IVAS_dec -obj_edit ../scripts/object_edit/combined_edit.txt BINAURAL 48 bit testv/ltv48_OSBA_4ISM_HOA3.wav_BINAURAL_256000_48-48_OE.tst +../IVAS_dec -obj_edit ../scripts/object_edit/combined_edit.txt BINAURAL_ROOM_IR 48 bit testv/ltv48_OSBA_4ISM_HOA3.wav_BINAURAL_ROOM_IR_256000_48-48_OE.tst // OSBA 2OA 3ISM at 128 kbps, 48kHz in, 48kHz out, FOA out, object editing, JBM Prof 5, DISC ../IVAS_cod -ism_sba 3 2 testv/ltv48_OSBA_3ISM_HOA2_ISM1.csv testv/ltv48_OSBA_3ISM_HOA2_ISM2.csv testv/ltv48_OSBA_3ISM_HOA2_ISM3.csv 128000 48 testv/ltv48_OSBA_3ISM_HOA2.wav bit diff --git a/scripts/find_regressions_from_logs.py b/scripts/find_regressions_from_logs.py new file mode 100644 index 0000000000000000000000000000000000000000..67a7447ddfd1c4d3cf0257fe587892e5b7b086c7 --- /dev/null +++ b/scripts/find_regressions_from_logs.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 + +import argparse +from pathlib import Path +import pandas as pd + +def main(logs_dir, output_filename, measure, days, all_results, diff_thr, ratio_thr, curr_value_thr): + + input_path = Path(logs_dir) + logs = [f for f in input_path.iterdir() if f.is_dir()] + + # Build dict of scores + formatdict = {} + sha = {} + logdict = {} + for log in logs: + date = log.name + logdict[date] = {} + formatdict[date] = {} + for logfile in log.glob("*.csv"): + tmp = logfile.name.split("-") + job = "-".join(tmp[3:-4]) + sha[date] = tmp[-1].split(".")[0] + data = pd.read_csv(logfile, usecols=["testcase", measure, "format"]) + logdict[date][job] = {} + formatdict[date][job] = {} + + for testcase, value, format in zip( + data["testcase"], data[measure], data["format"] + ): + formatdict[date][job][testcase] = format + logdict[date][job][testcase] = value + + # Restructure dict + csv_rows = [] + formats = [] + for date, jobs in logdict.items(): + for job, testcases in jobs.items(): + for testcase, value in testcases.items(): + csv_rows.append((job, testcase, date, value)) + formats.append((job, testcase, date, formatdict[date][job][testcase])) + + result = pd.DataFrame(csv_rows, columns=["job", "testcase", "date", "value"]) + result = result.pivot( + index=["job", "testcase"], columns="date", values="value" + ).reset_index() + + f = pd.DataFrame(formats, columns=["job", "testcase", "date", "format"]) + f = f.pivot( + index=["job", "testcase"], columns="date", values="format" + ).reset_index() + + if days != -1: + len_history = len(result.columns) - 2 + if len_history < days: + print(f"*** Warning: Requested number of days exceeds the number of days in the logs. Will use all {len_history} available days.") + if len_history > days: + remove_days = len_history - days + result = result.drop(result.columns[2:2+remove_days], axis=1) + + values = result.iloc[:, 2:] + last_date = values.columns[-1] + + result.insert(2, "format", f[last_date]) + result.insert(3, "min_date", values.idxmin(axis=1)) + result.insert(4, "min_sha", result["min_date"].map(sha)) + result.insert(5, "curr_value", values[last_date]) + result.insert(6, "min_value", values.min(axis=1)) + result.insert(7, "diff", result["curr_value"] - result["min_value"]) + result.insert(8, "ratio", result["curr_value"] / result["min_value"]) + result.loc[result["min_value"] == 0, "ratio"] = ( + 1 # Set ratio to 1 for denominator 0 + ) + + if not all_results: + # Filter out test cases above thresholds + result = result[result["diff"] > diff_thr] + result = result[result["ratio"] > ratio_thr] + result = result[result["curr_value"] > curr_value_thr] + + result["min_sha"] = "'" + result["min_sha"] # Add apostrophy to prevent Excel reading this as a number + + result.to_csv(output_filename, sep=";", index=False) + + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="logs dir") + parser.add_argument( + "logs_dir", + type=str, + help="Logs dir, e.g. logs", + ) + parser.add_argument( + "output_filename", + type=str, + help="Filename of the combined csv file. e.g mld.csv", + ) + parser.add_argument( + "--measure", + type=str, + help="Measure for summary, one of MLD MIN_SSNR MAX_ABS_DIFF MIN_ODG, (default: MLD)", + default="MLD", + ) + parser.add_argument( + "--days", + type=int, + help="Number of days in history, (default: whole history)", + default=-1, + ) + parser.add_argument( + "--all_results", + action="store_true", + help="Output all results, including cases without regression (default: off)", + default=False, + ) + parser.add_argument( + "--diff_thr", + type=float, + help="Include test cases with diff above diff_thr, (default: 0.0)", + default=0.0, + ) + parser.add_argument( + "--ratio_thr", + type=float, + help="Include test cases with ratio above ratio_thr, (default: 1.0)", + default=1.0, + ) + parser.add_argument( + "--curr_value_thr", + type=float, + help="Include test cases with curr_value above curr_value_thr, (default: 0.0)", + default=0.0, + ) + + args = parser.parse_args() + + main(args.logs_dir, args.output_filename, args.measure, args.days, args.all_results, args.diff_thr, args.ratio_thr, args.curr_value_thr) + diff --git a/scripts/generate_scripts_from_regressions.py b/scripts/generate_scripts_from_regressions.py new file mode 100644 index 0000000000000000000000000000000000000000..4487f844804902bf53727ed2ec20f178c5988416 --- /dev/null +++ b/scripts/generate_scripts_from_regressions.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 + +import argparse +import pandas as pd + +REPRODUCE_REGRESSION_SCRIPT_TMPL = """ +#!/bin/bash -x + +SCRIPTS_DIR=/usr/local/scripts +LTV_DIR=/usr/local/ltv + +MIN_DATE={min_date} +MIN_SHA={min_sha} +LEVEL_SCALING={level_scaling} +TESTCASE="{testcase}" + +REF_ENC1={REF_ENC1} +REF_DEC1={REF_DEC1} +DUT_ENC1={DUT_ENC1} +DUT_DEC1={DUT_DEC1} + +REF_ENC2={REF_ENC2} +REF_DEC2={REF_DEC2} +DUT_ENC2={DUT_ENC2} +DUT_DEC2={DUT_DEC2} + +INV_LEVEL_SCALING=$(awk "BEGIN {{print 1.0 / $LEVEL_SCALING}}") + +# Obtain executables from past reference +git checkout `git rev-list -1 --before="$MIN_DATE 22:00:00" ivas-float-update` +echo "ivas_float_update, min version: `git rev-parse HEAD`" > versions.txt +make clean +make -j +mv IVAS_cod IVAS_cod_ref_1 +mv IVAS_dec IVAS_dec_ref_1 +mv IVAS_rend IVAS_rend_ref_1 + +git checkout $MIN_SHA +echo "main, min version: `git rev-parse HEAD`" >> versions.txt +make clean +make -j +mv IVAS_cod IVAS_cod_1 +mv IVAS_dec IVAS_dec_1 +mv IVAS_rend IVAS_rend_1 + +# Obtain latest executables +git checkout ivas-float-update +git pull +echo "ivas-float-update, current version: `git rev-parse HEAD`" >> versions.txt +make clean +make -j +mv IVAS_cod IVAS_cod_ref_2 +mv IVAS_dec IVAS_dec_ref_2 +mv IVAS_rend IVAS_rend_ref_2 + +git checkout main +git pull +echo "main, current version: `git rev-parse HEAD`" >> versions.txt +make clean +make -j +mv IVAS_cod IVAS_cod_2 +mv IVAS_dec IVAS_dec_2 +mv IVAS_rend IVAS_rend_2 + +# Get fresh copy of scripts, tests and ci +cp -r $SCRIPTS_DIR/{{scripts,tests,ci,pytest.ini}} . +rm -rf tests/ref tests/dut tests/renderer/ref tests/renderer/cut +python3 ci/remove_unsupported_testcases.py scripts/config/self_test.prm scripts/config/self_test_ltv.prm + +# Get LTVs +cp $LTV_DIR/* scripts/testv + +# Apply level scaling +tests/scale_pcm.py ./scripts/testv/ "$LEVEL_SCALING" + +# Run tests +cp IVAS_rend_ref_1 IVAS_rend_ref +cp IVAS_rend_1 IVAS_rend +python3 -m pytest "$TESTCASE" -n 1 --update_ref 1 --create_ref --param_file scripts/config/self_test_ltv.prm --use_ltv --ref_encoder_path $REF_ENC1 --ref_decoder_path $REF_DEC1 +python3 -m pytest "$TESTCASE" -n 1 --create_cut --param_file scripts/config/self_test_ltv.prm --use_ltv --dut_encoder_path $DUT_ENC1 --dut_decoder_path $DUT_DEC1 --mld --ssnr --odg --scalefac $INV_LEVEL_SCALING --junit-xml=report1.xml --html=report1.html --self-contained-html +python3 scripts/parse_xml_report.py report1.xml report1.csv + +# Store results from first run +mkdir -p tests1/renderer +cp -r tests/ref tests/dut tests1 +cp -r tests/renderer/ref tests1/renderer +cp -r tests/renderer/cut tests1/renderer + +cp IVAS_rend_ref_2 IVAS_rend_ref +cp IVAS_rend_2 IVAS_rend +python3 -m pytest "$TESTCASE" -n 1 --update_ref 1 --create_ref --param_file scripts/config/self_test_ltv.prm --use_ltv --ref_encoder_path $REF_ENC2 --ref_decoder_path $REF_DEC2 +python3 -m pytest "$TESTCASE" -n 1 --create_cut --param_file scripts/config/self_test_ltv.prm --use_ltv --dut_encoder_path $DUT_ENC2 --dut_decoder_path $DUT_DEC2 --mld --ssnr --odg --scalefac $INV_LEVEL_SCALING --junit-xml=report2.xml --html=report2.html --self-contained-html +python3 scripts/parse_xml_report.py report2.xml report2.csv + +""" + + +def main(critical_list): + + critical = pd.read_csv(critical_list, sep=";") + + for row_counter, row in critical.iterrows(): + + # Find level + level_scaling = 1.0 + if "lev+10" in row["job"]: + level_scaling = 3.162 + if "lev-10" in row["job"]: + level_scaling = 0.3162 + + # Find executables setup + REF_ENC1 = "IVAS_cod_ref_1" + REF_DEC1 = "IVAS_dec_ref_1" + DUT_ENC1 = "IVAS_cod_1" + DUT_DEC1 = "IVAS_dec_1" + REF_ENC2 = "IVAS_cod_ref_2" + REF_DEC2 = "IVAS_dec_ref_2" + DUT_ENC2 = "IVAS_cod_2" + DUT_DEC2 = "IVAS_dec_2" + + if "dec" in row["job"]: + DUT_ENC1 = "IVAS_cod_ref_1" + DUT_ENC2 = "IVAS_cod_ref_2" + if "enc" in row["job"]: + DUT_DEC1 = "IVAS_dec_ref_1" + DUT_DEC2 = "IVAS_dec_ref_2" + + script_content = REPRODUCE_REGRESSION_SCRIPT_TMPL.format( + min_date=row["min_date"], + min_sha=row["min_sha"][1:], + level_scaling=level_scaling, + testcase=row["testcase"], + REF_ENC1=REF_ENC1, + REF_DEC1=REF_DEC1, + DUT_ENC1=DUT_ENC1, + DUT_DEC1=DUT_DEC1, + REF_ENC2=REF_ENC2, + REF_DEC2=REF_DEC2, + DUT_ENC2=DUT_ENC2, + DUT_DEC2=DUT_DEC2, + ) + + script_filename = f"regression_{row_counter+2:03d}.bash" + with open(script_filename, "w") as f: + f.write(script_content) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Generate bash scripts to reproduce test cases from critical testcase csv list") + parser.add_argument( + "critical_list", + type=str, + help="critical file list, e.g. critical.csv", + ) + args = parser.parse_args() + main(args.critical_list)