diff --git a/apps/decoder.c b/apps/decoder.c index 0da70053d045c74ebd9a7a9f694adf8a5c7ac360..d9333726e47ea1b74f57304ceea671a63ac12b66 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -1717,7 +1717,12 @@ static ivas_error initOnFirstGoodFrame( for ( int16_t j = 0; j < numInitialBadFrames; ++j ) { +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + float delayMs = (float) ( pFullDelayNumSamples[0] ) / (float) ( *delayTimeScale ); + if ( ( error = MasaFileWriter_writeFrame( *ppMasaWriter, hMasaExtOutMeta, &delayMs ) ) != IVAS_ERR_OK ) +#else if ( ( error = MasaFileWriter_writeFrame( *ppMasaWriter, hMasaExtOutMeta ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError writing MASA metadata to file: %s\n", MasaFileWriter_getFilePath( *ppMasaWriter ) ); return error; @@ -2101,13 +2106,28 @@ static ivas_error decodeG192( if ( bsFormat == IVAS_DEC_BS_MASA || bsFormat == IVAS_DEC_BS_MASA_ISM ) { IVAS_MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + int16_t fullDelayNumSamples[3]; + float delayMs; + + /* delayNumSamples is zeroed, and delayNumSamples_orig is updated only on first good frame, so need to re-fetch delay info */ + if ( ( error = IVAS_DEC_GetDelay( hIvasDec, fullDelayNumSamples, &delayTimeScale ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nUnable to get delay of decoder: %s\n", ivas_error_to_string( error ) ); + } +#endif if ( ( error = IVAS_DEC_GetMasaMetadata( hIvasDec, &hMasaExtOutMeta, 0 ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_DEC_GetMasaMetadata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + delayMs = (float) ( fullDelayNumSamples[0] ) / (float) ( delayTimeScale ); + if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta, &delayMs ) ) != IVAS_ERR_OK ) +#else if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError writing MASA metadata to file: %s\n", MasaFileWriter_getFilePath( masaWriter ) ); goto cleanup; @@ -2233,13 +2253,27 @@ static ivas_error decodeG192( if ( bsFormat == IVAS_DEC_BS_MASA || bsFormat == IVAS_DEC_BS_MASA_ISM ) { IVAS_MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + int16_t fullDelayNumSamples[3]; + float delayMs; + + if ( ( error = IVAS_DEC_GetDelay( hIvasDec, fullDelayNumSamples, &delayTimeScale ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nUnable to get delay of decoder: %s\n", ivas_error_to_string( error ) ); + } +#endif if ( ( error = IVAS_DEC_GetMasaMetadata( hIvasDec, &hMasaExtOutMeta, 0 ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_DEC_GetMasaMetadata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + delayMs = (float) ( fullDelayNumSamples[0] ) / (float) ( delayTimeScale ); + if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta, &delayMs ) ) != IVAS_ERR_OK ) +#else if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError writing MASA metadata to file: %s\n", MasaFileWriter_getFilePath( masaWriter ) ); goto cleanup; @@ -2785,13 +2819,28 @@ static ivas_error decodeVoIP( if ( bsFormat == IVAS_DEC_BS_MASA || bsFormat == IVAS_DEC_BS_MASA_ISM ) { IVAS_MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + int16_t fullDelayNumSamples[3]; + float delayMs; + + /* delayNumSamples_orig is fetched only for the first good frame, but here the delay can change between frames, so need to re-fetch */ + if ( ( error = IVAS_DEC_GetDelay( hIvasDec, fullDelayNumSamples, &delayTimeScale ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nUnable to get delay of decoder: %s\n", ivas_error_to_string( error ) ); + } +#endif if ( ( error = IVAS_DEC_GetMasaMetadata( hIvasDec, &hMasaExtOutMeta, 1 ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_DEC_GetMasaMetadata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + delayMs = (float) ( fullDelayNumSamples[0] ) / (float) ( delayTimeScale ); + if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta, &delayMs ) ) != IVAS_ERR_OK ) +#else if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError writing MASA metadata to file: %s\n", MasaFileWriter_getFilePath( masaWriter ) ); goto cleanup; diff --git a/apps/renderer.c b/apps/renderer.c index 13d68cdef50278ec7f59b00bceedb49a05d072a4..4d976c76e79d52e1e727581d9b3cf9affc90b1e6 100644 --- a/apps/renderer.c +++ b/apps/renderer.c @@ -1987,8 +1987,11 @@ int main( } } } - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMetaOutput, NULL ) ) != IVAS_ERR_OK ) /* NULL -> use default metadata delay settings */ +#else if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMetaOutput ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nError writing MASA metadata to file: %s\n", MasaFileWriter_getFilePath( masaWriter ) ); } diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index 5b1d54265c66aac7c75a5d8a85cb0712387044fc..a94ab1fbb7bfaa8cdd4da6754e0fece1e10779c2 100644 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -147,7 +147,13 @@ typedef enum RENDERER_NON_DIEGETIC_DOWNMIX, RENDERER_OSBA_STEREO, RENDERER_OSBA_AMBI, +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + RENDERER_OSBA_LS, + RENDERER_OMASA_OBJECT_EXT, + RENDERER_OMASA_MIX_EXT +#else RENDERER_OSBA_LS +#endif } RENDERER_TYPE; #define MAX_FREQUENCY_BANDS 64 diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index 510a9067de037845973169a4986c25fb273a14cf..6486d68c390e929b340ec3349945844c7f970f9b 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -156,6 +156,33 @@ void ivas_omasa_rearrange_channels_fx( const Word16 output_frame /* i : output frame length per channel */ ); +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT +ivas_error ivas_omasa_combine_separate_ism_with_masa_open_fx( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +); + +void ivas_omasa_combine_separate_ism_with_masa_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + Word32 *output[], /* o : output synthesis signal */ + Word16 *output_q, /* i/o: output Q value */ + const int16_t nchan_ism, /* i : number of ISMs */ + const int16_t output_frame /* i : output frame length per channel */ +); + +ivas_error ivas_omasa_render_objects_from_mix_open_fx( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +); + +void ivas_omasa_render_objects_from_mix_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + Word32 *output[], /* o : output synthesis signal */ + const int16_t nchan_ism, /* i : number of ISMs */ + const int16_t output_frame, /* i : output frame length per channel */ + Word16 *output_q /* i/o: output Q value */ +); + +#endif + ivas_error ivas_omasa_ism_metadata_dec_fx( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ const Word32 ism_total_brate, /* i : ISM total bitrate */ @@ -3906,7 +3933,7 @@ void ivas_omasa_decode_masa_to_total_fx( ivas_error ivas_td_binaural_open_fx( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ Word16 *SrcInd, /*Temporarily used to store the updated value of SrcInd*/ - Word16 *num_src + Word16 *num_src ); ivas_error ivas_td_binaural_renderer_sf_fx( @@ -6471,7 +6498,7 @@ Word16 ivas_qmetadata_dec_sid_decode( UWord16 ivas_qmetadata_reorder_generic_fx( - const Word16 signed_value + const Word16 signed_value ); void ivas_sba_set_cna_cng_flag( @@ -6605,9 +6632,9 @@ void ivas_map_prior_coeffs_quant( const Word16 nB ); -void ivas_clear_band_coeff_idx( - ivas_band_coeffs_ind_t *pband_coeff_idx, - const UWord16 num_bands +void ivas_clear_band_coeff_idx( + ivas_band_coeffs_ind_t *pband_coeff_idx, + const UWord16 num_bands ); @@ -6715,7 +6742,7 @@ ivas_error ivas_create_lfe_enc_fx( const Word32 input_Fs /* i : input sampling rate */ ); -void ivas_lfe_enc_close_fx( +void ivas_lfe_enc_close_fx( LFE_ENC_HANDLE *hLFE /* i/o: LFE encoder handle */ ); diff --git a/lib_com/options.h b/lib_com/options.h index 5257a5d6a276d9489f951ea7a5dbbf28aa138ef1..fba3ebf3a5a663d663dc1fb1a706b98c26c4539d 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -155,12 +155,12 @@ #ifdef NONBE_FIX_1058_DECODER_ERROR_WITH_REVERB_ROOM #endif +#define NONBE_FIX_984_OMASA_EXT_OUTPUT /* Nokia: issue #984: complete the OMASA EXT output implementation */ + #define USE_NEW_HRTF_BINARY_FILE_FORMAT /* Orange: to activate when decided to change the hrtf binary file format */ #define FIX_WARNING_RENDER_CONFIG /* Orange: fix warning on windows build */ - - #define NONBE_FIX_991_PARAMBIN_BINARY_HRTF /* Nokia: issue #991: fix using of binary file HRTF in ParamBin (to activate when USE_NEW_HRTF_BINARY_FILE_FORMAT and FIX_777_COMBI_RENDER_CONFIG_FILE are on ) */ #define FIX_1741_REVERB_TIMES_Q_FORMAT /* Philips: reverberation times in Q26 format instead of Q31 */ diff --git a/lib_dec/ivas_init_dec_fx.c b/lib_dec/ivas_init_dec_fx.c index 40bf1ccf59028449e7c7bf86401afcc52a969846..80cad2c96a8f5f364015ad4be30307e67fd29997 100644 --- a/lib_dec/ivas_init_dec_fx.c +++ b/lib_dec/ivas_init_dec_fx.c @@ -386,6 +386,26 @@ ivas_error ivas_dec_setup( st_ivas->nchan_transport = 1; move16(); } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + /* this should be non-zero if original input format was MASA_ISM_FORMAT */ + st_ivas->nchan_ism = add( st_ivas->bit_stream[L_sub( res_dec, 3 )], shl( st_ivas->bit_stream[L_sub( res_dec, 2 )], 1 ) ); + + IF( GT_16( st_ivas->nchan_ism, 0 ) ) + { + /* the input_ivas_format should be MASA_ISM_FORMAT, but we cannot initialize it now */ + test(); + IF( EQ_16( st_ivas->nchan_transport, 2 ) && EQ_16( st_ivas->nchan_ism, 3 ) ) + { + st_ivas->nchan_ism = 4; + move16(); + } + /* for MASA_ISM_FORMAT at input the number of MASA transport channels is always 2 */ + st_ivas->nchan_transport = 2; + element_mode_flag = 1; + move16(); + move16(); + } +#endif IF( st_ivas->ini_frame > 0 ) { @@ -1232,6 +1252,9 @@ ivas_error ivas_init_decoder_fx( IF( EQ_32( output_config, IVAS_AUDIO_CONFIG_EXTERNAL ) ) { +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); +#endif IF( EQ_32( st_ivas->ivas_format, SBA_ISM_FORMAT ) ) { hDecoderConfig->nchan_out = audioCfg2channels( IVAS_AUDIO_CONFIG_HOA3 ); @@ -1239,7 +1262,11 @@ ivas_error ivas_init_decoder_fx( hDecoderConfig->nchan_out = add( hDecoderConfig->nchan_out, st_ivas->nchan_ism ); move16(); } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + ELSE IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) || EQ_32( st_ivas->ivas_format, MASA_FORMAT ) ) +#else ELSE IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) +#endif { hDecoderConfig->nchan_out = add( st_ivas->nchan_transport, st_ivas->nchan_ism ); move16(); @@ -2391,7 +2418,39 @@ ivas_error ivas_init_decoder_fx( return error; } } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_OBJECT_EXT ) ) + { + /* Allocate 'hIsmRendererData' handle and memory for delay buffer within 'hMasaIsmData' */ + error = ivas_omasa_render_objects_from_mix_open_fx( st_ivas ); + move32(); + + IF( NE_32( error, IVAS_ERR_OK ) ) + { + return error; + } + + error = ivas_spat_hSpatParamRendCom_config_fx( &st_ivas->hSpatParamRendCom, DIRAC_OPEN, 0, + st_ivas->ivas_format, st_ivas->mc_mode, output_Fs, 0, 0 ); + move32(); + IF( NE_32( error, IVAS_ERR_OK ) ) + { + return error; + } + } + + IF( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_MIX_EXT ) ) + { + /* Allocate 'hIsmRendererData' handle */ + error = ivas_omasa_combine_separate_ism_with_masa_open_fx( st_ivas ); + move32(); + IF( NE_32( error, IVAS_ERR_OK ) ) + { + return error; + } + } +#endif test(); test(); test(); @@ -3360,6 +3419,19 @@ void ivas_init_dec_get_num_cldfb_instances( move16(); } BREAK; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + case RENDERER_OMASA_OBJECT_EXT: + *numCldfbAnalyses = st_ivas->nchan_transport; + *numCldfbSyntheses = st_ivas->hDecoderConfig->nchan_out; + move16(); + move16(); + break; + case RENDERER_OMASA_MIX_EXT: + *numCldfbAnalyses = add( st_ivas->nchan_transport, 1 ); + *numCldfbSyntheses = 0; + move16(); + break; +#endif default: assert( 0 && "Renderer not handled for CLDFB reservation." ); } @@ -3621,6 +3693,19 @@ void ivas_init_dec_get_num_cldfb_instances_ivas_fx( move16(); } BREAK; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + case RENDERER_OMASA_OBJECT_EXT: + *numCldfbAnalyses = st_ivas->nchan_transport; + *numCldfbSyntheses = st_ivas->hDecoderConfig->nchan_out; + move16(); + move16(); + break; + case RENDERER_OMASA_MIX_EXT: + *numCldfbAnalyses = add( st_ivas->nchan_transport, 1 ); + *numCldfbSyntheses = 0; + move16(); + break; +#endif default: assert( 0 && "Renderer not handled for CLDFB reservation." ); } @@ -3777,6 +3862,7 @@ static ivas_error doSanityChecks_IVAS( } } +#ifndef NONBE_FIX_984_OMASA_EXT_OUTPUT IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) ) { test(); @@ -3786,7 +3872,7 @@ static ivas_error doSanityChecks_IVAS( return IVAS_ERROR( IVAS_ERR_INVALID_OUTPUT_FORMAT, "Incorrect output configuration specified for combined MASA and ISM format" ); } } - +#endif return IVAS_ERR_OK; } diff --git a/lib_dec/ivas_jbm_dec_fx.c b/lib_dec/ivas_jbm_dec_fx.c index bcca2a71d79ea7ed669bd7ca8d66522aeb4eeb62..48264d70fb7cb3dd87229a603e510fa7d4c1a798 100644 --- a/lib_dec/ivas_jbm_dec_fx.c +++ b/lib_dec/ivas_jbm_dec_fx.c @@ -668,6 +668,20 @@ ivas_error ivas_jbm_dec_tc_fx( { Scale_sig32( p_output_fx[i], output_frame, negate( q_shift ) ); } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); + /* external output */ + IF( EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_EXTERNAL ) && + EQ_32( st_ivas->hMasa->config.input_ivas_format, MASA_ISM_FORMAT ) ) + { + FOR( n = 0; n < st_ivas->nchan_ism; n++ ) + { + set_zero_fx( p_output_fx[add( st_ivas->nchan_transport, n )], output_frame ); + } + + ivas_omasa_rearrange_channels_fx( p_output_fx, st_ivas->nchan_ism, output_frame ); + } +#endif } ELSE IF( EQ_16( st_ivas->ivas_format, SBA_FORMAT ) && ( EQ_16( st_ivas->renderer_type, RENDERER_BINAURAL_PARAMETRIC ) || EQ_16( st_ivas->renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) ) ) { @@ -792,6 +806,22 @@ ivas_error ivas_jbm_dec_tc_fx( } ELSE IF( EQ_32( output_config, IVAS_AUDIO_CONFIG_EXTERNAL ) ) { +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) + { + ivas_omasa_rearrange_channels_fx( p_output_fx, nchan_transport_ism, output_frame ); + } + ELSE IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) + { + /* Convert separate object to MASA, combine with the original MASA, and output combined MASA + empty objects. */ + ivas_omasa_combine_separate_ism_with_masa_fx( st_ivas, p_output_fx, &output_q, st_ivas->nchan_ism, output_frame ); + } + ELSE IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) ) + { + /* Extract objects from MASA, output MASA + all objects (i.e., extracted and separated objects) */ + ivas_omasa_render_objects_from_mix_fx( st_ivas, p_output_fx, st_ivas->nchan_ism, output_frame, &output_q ); + } +#else /* sanity check in case of bitrate switching */ IF( NE_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) { @@ -799,9 +829,7 @@ ivas_error ivas_jbm_dec_tc_fx( } ivas_omasa_rearrange_channels_fx( p_output_fx, nchan_transport_ism, output_frame ); - - output_q = 11; - move16(); +#endif ivas_jbm_dec_copy_masa_meta_to_buffer( st_ivas ); } @@ -1706,29 +1734,42 @@ void ivas_jbm_dec_feed_tc_to_renderer_fx( } ELSE IF( EQ_16( st_ivas->ivas_format, MASA_ISM_FORMAT ) ) { +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT test(); - IF( EQ_16( st_ivas->renderer_type, RENDERER_BINAURAL_PARAMETRIC ) && EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) + IF( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_MIX_EXT ) || EQ_32( st_ivas->renderer_type, RENDERER_OMASA_OBJECT_EXT ) ) { - n_render_timeslots = i_mult( n_render_timeslots, idiv1616( st_ivas->hTcBuffer->n_samples_granularity, st_ivas->hSpatParamRendCom->slot_size ) ); + ivas_jbm_dec_td_renderers_adapt_subframes( st_ivas ); + ivas_jbm_masa_sf_to_slot_map( st_ivas, n_render_timeslots ); } - - IF( st_ivas->hSCE[0] ) + ELSE { - Word16 shift = getScaleFactor32( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevel, FFTCLDFBLEN ); - if ( LT_16( sub( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp, shift ), 4 ) ) +#endif + test(); + IF( EQ_16( st_ivas->renderer_type, RENDERER_BINAURAL_PARAMETRIC ) && EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) { - shift = sub( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp, 4 ); + n_render_timeslots = i_mult( n_render_timeslots, idiv1616( st_ivas->hTcBuffer->n_samples_granularity, st_ivas->hSpatParamRendCom->slot_size ) ); } - scale_sig32( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevel, FFTCLDFBLEN, shift ); // Q(31- (st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp - shift) - st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp = sub( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp, shift ); - move16(); - } - ivas_sba_dec_digest_tc_fx( st_ivas, n_render_timeslots, st_ivas->hTcBuffer->n_samples_available ); - IF( EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) - { - ivas_ism_dec_digest_tc_fx( st_ivas ); + IF( st_ivas->hSCE[0] ) + { + Word16 shift = getScaleFactor32( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevel, FFTCLDFBLEN ); + if ( LT_16( sub( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp, shift ), 4 ) ) + { + shift = sub( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp, 4 ); + } + scale_sig32( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevel, FFTCLDFBLEN, shift ); // Q(31- (st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp - shift) + st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp = sub( st_ivas->hSCE[0]->hCoreCoder[0]->hFdCngDec->hFdCngCom->cngNoiseLevelExp, shift ); + move16(); + } + ivas_sba_dec_digest_tc_fx( st_ivas, n_render_timeslots, st_ivas->hTcBuffer->n_samples_available ); + + IF( EQ_16( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) + { + ivas_ism_dec_digest_tc_fx( st_ivas ); + } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT } +#endif if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_DIRAC ) { @@ -2110,6 +2151,9 @@ ivas_error ivas_jbm_dec_render_fx( move16(); test(); test(); +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); +#endif IF( EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_PARAMETRIC ) || EQ_32( st_ivas->renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) || EQ_32( st_ivas->renderer_type, RENDERER_STEREO_PARAMETRIC ) ) { test(); @@ -2129,6 +2173,14 @@ ivas_error ivas_jbm_dec_render_fx( { ivas_omasa_dirac_rend_jbm_fx( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, nchan_remapped, p_output_fx ); } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + ELSE IF( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_OBJECT_EXT ) || + EQ_32( st_ivas->renderer_type, RENDERER_OMASA_MIX_EXT ) ) + { + ivas_jbm_dec_tc_buffer_playout_fx( st_ivas, nSamplesAskedLocal, nSamplesRendered, p_output_fx ); + ivas_omasa_rearrange_channels_fx( p_output_fx, st_ivas->nchan_ism, *nSamplesRendered ); + } +#endif } ELSE IF( EQ_32( st_ivas->ivas_format, SBA_ISM_FORMAT ) ) { @@ -3927,6 +3979,10 @@ TC_BUFFER_MODE ivas_jbm_dec_get_tc_buffer_mode( case RENDERER_PARAM_ISM: case RENDERER_BINAURAL_MIXER_CONV: case RENDERER_BINAURAL_MIXER_CONV_ROOM: +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + case RENDERER_OMASA_OBJECT_EXT: + case RENDERER_OMASA_MIX_EXT: +#endif case RENDERER_OSBA_AMBI: case RENDERER_OSBA_LS: buffer_mode = TC_BUFFER_MODE_RENDERER; diff --git a/lib_dec/ivas_masa_dec_fx.c b/lib_dec/ivas_masa_dec_fx.c index 3133c8c57752b90884c94727cab98a97abffa2b7..f669707103cb2e903cd3de398d3e58e092475a2e 100644 --- a/lib_dec/ivas_masa_dec_fx.c +++ b/lib_dec/ivas_masa_dec_fx.c @@ -320,7 +320,33 @@ ivas_error ivas_masa_decode_fx( } } } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + + /* read 2 bits: + '00' - MASA format at the encoder + '01' - MASA_ISM_FORMAT at the encoder, with 1 object + '10' - MASA_ISM_FORMAT at the encoder, with 2 objects + '11' - MASA_ISM_FORMAT at the encoder, with 3 or 4 objects + reading if 3 or 4 object is performed later + */ + byteBuffer = st->bit_stream[st->next_bit_pos]; + move16(); + st->next_bit_pos = sub( st->next_bit_pos, 1 ); + byteBuffer = add( byteBuffer, shl( st->bit_stream[st->next_bit_pos], 1 ) ); + st->next_bit_pos = sub( st->next_bit_pos, 1 ); + test(); + IF( EQ_16( byteBuffer, 0 ) && EQ_32( ivas_format, MASA_FORMAT ) ) + { + hMasa->config.input_ivas_format = MASA_FORMAT; + move32(); + } + ELSE + { + hMasa->config.input_ivas_format = MASA_ISM_FORMAT; + move32(); + } +#else /* read the MASA_ISM_FORMAT bit */ byteBuffer = st->bit_stream[( st->next_bit_pos )--]; move16(); @@ -337,6 +363,7 @@ ivas_error ivas_masa_decode_fx( /* reserved bit */ byteBuffer = st->bit_stream[( st->next_bit_pos )--]; move16(); +#endif *nb_bits_read = add( *nb_bits_read, MASA_HEADER_BITS ); /* read number of directions */ @@ -418,8 +445,9 @@ ivas_error ivas_masa_decode_fx( { IF( st_ivas->hDirAC != NULL ) { - *nb_bits_read = add( *nb_bits_read, ivas_decode_masaism_metadata_fx( hQMetaData, st_ivas->hMasa, st_ivas->hMasaIsmData, st_ivas->nchan_ism, st->bit_stream, &st->next_bit_pos, - st_ivas->hMasaIsmData->idx_separated_ism, ism_imp, st_ivas->hSpatParamRendCom->dirac_bs_md_write_idx, st_ivas->hSpatParamRendCom->dirac_md_buffer_length ) ); + *nb_bits_read = add( *nb_bits_read, + ivas_decode_masaism_metadata_fx( hQMetaData, st_ivas->hMasa, st_ivas->hMasaIsmData, st_ivas->nchan_ism, st->bit_stream, &st->next_bit_pos, + st_ivas->hMasaIsmData->idx_separated_ism, ism_imp, st_ivas->hSpatParamRendCom->dirac_bs_md_write_idx, st_ivas->hSpatParamRendCom->dirac_md_buffer_length ) ); move16(); FOR( obj = 0; obj <= st_ivas->nchan_ism; obj++ ) { @@ -439,6 +467,14 @@ ivas_error ivas_masa_decode_fx( } } } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + ELSE IF( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_OBJECT_EXT ) ) + { + *nb_bits_read = add( *nb_bits_read, ivas_decode_masaism_metadata_fx( hQMetaData, st_ivas->hMasa, st_ivas->hMasaIsmData, + st_ivas->nchan_ism, st->bit_stream, &st->next_bit_pos, + st_ivas->hMasaIsmData->idx_separated_ism, ism_imp, st_ivas->hSpatParamRendCom->dirac_bs_md_write_idx, st_ivas->hSpatParamRendCom->dirac_md_buffer_length ) ); + } +#endif ELSE { *nb_bits_read = add( *nb_bits_read, ivas_decode_masaism_metadata_fx( hQMetaData, st_ivas->hMasa, st_ivas->hMasaIsmData, st_ivas->nchan_ism, st->bit_stream, &st->next_bit_pos, @@ -587,7 +623,19 @@ ivas_error ivas_masa_decode_fx( ivas_qmetadata_to_dirac_fx( hQMetaData, st_ivas->hDirAC, hMasa, st_ivas->hSpatParamRendCom, ivas_total_brate, ivas_format, 0, 0 ); } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + ELSE IF( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_OBJECT_EXT ) ) + { + Word16 index = add( st_ivas->hSpatParamRendCom->dirac_bs_md_write_idx, MAX_PARAM_SPATIAL_SUBFRAMES ); + IF( GE_16( index, st_ivas->hSpatParamRendCom->dirac_md_buffer_length ) ) + { + index = sub( index, st_ivas->hSpatParamRendCom->dirac_md_buffer_length ); + } + st_ivas->hSpatParamRendCom->dirac_bs_md_write_idx = index; + move16(); + } +#endif IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) ) { IF( hQMetaData->q_direction == NULL ) @@ -743,7 +791,18 @@ ivas_error ivas_masa_dec_open_fx( ism_total_brate = 0; move32(); - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + /* ISM metadata */ + test(); + test(); + if ( EQ_32( st_ivas->ivas_format, MASA_FORMAT ) && + st_ivas->hIsmMetaData[0] != NULL && + EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_EXTERNAL ) ) + { + /* these are not needed -> clean. EXT metafile writer in OMASA needs only the number of ISMs and writes default null-data */ + ivas_ism_metadata_close( st_ivas->hIsmMetaData, 0 ); + } +#endif test(); test(); test(); @@ -826,7 +885,10 @@ ivas_error ivas_masa_dec_open_fx( nchan_transport = ivas_jbm_dec_get_num_tc_channels_fx( st_ivas ); nchan_to_allocate = nchan_transport; move16(); - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); + test(); +#endif test(); test(); IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) && EQ_32( st_ivas->renderer_type, RENDERER_MONO_DOWNMIX ) ) @@ -836,6 +898,15 @@ ivas_error ivas_masa_dec_open_fx( nchan_to_allocate = 1; move16(); } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + ELSE IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) && + ( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_MIX_EXT ) || + EQ_32( st_ivas->renderer_type, RENDERER_OMASA_OBJECT_EXT ) ) ) + { + nchan_transport = add( st_ivas->nchan_transport, st_ivas->nchan_ism ); + nchan_to_allocate = add( st_ivas->nchan_transport, st_ivas->nchan_ism ); + } +#endif ELSE IF( EQ_16( st_ivas->nchan_transport, 1 ) && EQ_32( st_ivas->renderer_type, RENDERER_DIRAC ) ) { /* addtl channel for CNG */ @@ -1830,8 +1901,18 @@ ivas_error ivas_masa_dec_reconfigure_fx( IF( EQ_32( st_ivas->ivas_format, MASA_FORMAT ) ) { +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( NE_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_EXTERNAL ) ) + { + move16(); + st_ivas->nchan_ism = 0; /* Initialization if it has not been already read from the end of the bitstream at the same time + with reading of the format: nchan_ism is needed in MASA format because for the EXT output in + MASA-only (pre-rendering mode of OMASA) the number of ISMs to output correct number of empty objects is needed */ + } +#else st_ivas->nchan_ism = 0; move16(); +#endif st_ivas->ism_mode = ISM_MODE_NONE; move16(); } @@ -1854,6 +1935,10 @@ ivas_error ivas_masa_dec_reconfigure_fx( test(); test(); test(); +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); + test(); +#endif IF( EQ_16( st_ivas->renderer_type, RENDERER_BINAURAL_PARAMETRIC ) || EQ_16( st_ivas->renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) || EQ_16( st_ivas->renderer_type, RENDERER_STEREO_PARAMETRIC ) ) { IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) ) @@ -1894,7 +1979,15 @@ ivas_error ivas_masa_dec_reconfigure_fx( /* addtl channel for CNG */ tc_nchan_to_allocate = add( tc_nchan_to_allocate, 1 ); } - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + ELSE IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) && + ( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_MIX_EXT ) || + EQ_32( st_ivas->renderer_type, RENDERER_OMASA_OBJECT_EXT ) ) ) + { + tc_nchan_transport = add( st_ivas->nchan_transport, st_ivas->nchan_ism ); + tc_nchan_to_allocate = add( st_ivas->nchan_transport, st_ivas->nchan_ism ); + } +#endif test(); test(); IF( NE_16( tc_nchan_transport, st_ivas->hTcBuffer->nchan_transport_jbm ) || NE_16( tc_nchan_to_allocate, st_ivas->hTcBuffer->nchan_transport_internal ) || NE_16( buffer_mode_new, st_ivas->hTcBuffer->tc_buffer_mode ) ) @@ -3332,6 +3425,14 @@ static Word16 ivas_decode_masaism_metadata_fx( hMasaIsmData->energy_ratio_ism_fx[dir][meta_write_index][b] = energy_ratio_ism_fx[i][band][dir]; move32(); } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( hMasaIsmData->hExtData != NULL ) + { + hMasaIsmData->hExtData->masa_render_masa_to_total[meta_write_index][b] = + hMasaIsmData->masa_to_total_energy_ratio_fx[i][band]; + move32(); + } +#endif } } } diff --git a/lib_dec/ivas_omasa_dec_fx.c b/lib_dec/ivas_omasa_dec_fx.c index 35f4f1c4b9841352f3f2aad314e047ab8b82ed71..642e9af40d805a4e0129dab6bd00afe0980360b4 100644 --- a/lib_dec/ivas_omasa_dec_fx.c +++ b/lib_dec/ivas_omasa_dec_fx.c @@ -32,6 +32,9 @@ #include "options.h" #include +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT +#include +#endif #include "ivas_cnst.h" #include "ivas_prot_fx.h" #include "prot_fx.h" @@ -45,6 +48,223 @@ * Local constants *------------------------------------------------------------------------*/ +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + +#define EXT_RENDER_IIR_FAC 0.95f +#define MULT_17_DIV_20_Q15 ( Word16 )( ( 17.0 / 20.0f ) * pow( 2, 15 ) + 0.5f ) +#define MULT_1_DIV_CLDFB_NO_COL_MAX_Q15 ( Word16 )( ( 1.0 / CLDFB_NO_COL_MAX ) * pow( 2, 15 ) + 0.5f ) +#define ONEMINUX_EXT_RENDER_IIR_FAC_Q31 ( Word32 )( ( 1.0f - EXT_RENDER_IIR_FAC ) * pow( 2, 31 ) + 0.5f ) +#define EXT_RENDER_IIR_FAC_Q31 ( Word32 )( EXT_RENDER_IIR_FAC * pow( 2, 31 ) + 0.5f ) + +// Calculated as (Word16)(((1.0f / (50 * MAX_PARAM_SPATIAL_SUBFRAMES)) * pow(2, 15)) + 0.5f) +#define OMASA_DELAYFRAMES_PER_SEC_Q15 (Word16) 164 // Q15 + +static Word16 interpolator_table_48k_q15[] = { + 0, 137, 273, 410, 546, 683, 819, 956, 1092, 1229, + 1365, 1502, 1638, 1775, 1911, 2048, 2185, 2321, 2458, 2594, + 2731, 2867, 3004, 3140, 3277, 3413, 3550, 3686, 3823, 3959, + 4096, 4233, 4369, 4506, 4642, 4779, 4915, 5052, 5188, 5325, + 5461, 5598, 5734, 5871, 6007, 6144, 6281, 6417, 6554, 6690, + 6827, 6963, 7100, 7236, 7373, 7509, 7646, 7782, 7919, 8055, + 8192, 8329, 8465, 8602, 8738, 8875, 9011, 9148, 9284, 9421, + 9557, 9694, 9830, 9967, 10103, 10240, 10377, 10513, 10650, 10786, + 10923, 11059, 11196, 11332, 11469, 11605, 11742, 11878, 12015, 12151, + 12288, 12425, 12561, 12698, 12834, 12971, 13107, 13244, 13380, 13517, + 13653, 13790, 13926, 14063, 14199, 14336, 14473, 14609, 14746, 14882, + 15019, 15155, 15292, 15428, 15565, 15701, 15838, 15974, 16111, 16247, + 16384, 16521, 16657, 16794, 16930, 17067, 17203, 17340, 17476, 17613, + 17749, 17886, 18022, 18159, 18295, 18432, 18569, 18705, 18842, 18978, + 19115, 19251, 19388, 19524, 19661, 19797, 19934, 20070, 20207, 20343, + 20480, 20617, 20753, 20890, 21026, 21163, 21299, 21436, 21572, 21709, + 21845, 21982, 22118, 22255, 22391, 22528, 22665, 22801, 22938, 23074, + 23211, 23347, 23484, 23620, 23757, 23893, 24030, 24166, 24303, 24439, + 24576, 24713, 24849, 24986, 25122, 25259, 25395, 25532, 25668, 25805, + 25941, 26078, 26214, 26351, 26487, 26624, 26761, 26897, 27034, 27170, + 27307, 27443, 27580, 27716, 27853, 27989, 28126, 28262, 28399, 28535, + 28672, 28809, 28945, 29082, 29218, 29355, 29491, 29628, 29764, 29901, + 30037, 30174, 30310, 30447, 30583, 30720, 30857, 30993, 31130, 31266, + 31403, 31539, 31676, 31812, 31949, 32085, 32222, 32358, 32495, 32631 +}; + +static Word16 interpolator_table_32k_q15[] = { + 0, 205, 410, 614, 819, 1024, 1229, 1434, 1638, 1843, + 2048, 2253, 2458, 2662, 2867, 3072, 3277, 3482, 3686, 3891, + 4096, 4301, 4506, 4710, 4915, 5120, 5325, 5530, 5734, 5939, + 6144, 6349, 6554, 6758, 6963, 7168, 7373, 7578, 7782, 7987, + 8192, 8397, 8602, 8806, 9011, 9216, 9421, 9626, 9830, 10035, + 10240, 10445, 10650, 10854, 11059, 11264, 11469, 11674, 11878, 12083, + 12288, 12493, 12698, 12902, 13107, 13312, 13517, 13722, 13926, 14131, + 14336, 14541, 14746, 14950, 15155, 15360, 15565, 15770, 15974, 16179, + 16384, 16589, 16794, 16998, 17203, 17408, 17613, 17818, 18022, 18227, + 18432, 18637, 18842, 19046, 19251, 19456, 19661, 19866, 20070, 20275, + 20480, 20685, 20890, 21094, 21299, 21504, 21709, 21914, 22118, 22323, + 22528, 22733, 22938, 23142, 23347, 23552, 23757, 23962, 24166, 24371, + 24576, 24781, 24986, 25190, 25395, 25600, 25805, 26010, 26214, 26419, + 26624, 26829, 27034, 27238, 27443, 27648, 27853, 28058, 28262, 28467, + 28672, 28877, 29082, 29286, 29491, 29696, 29901, 30106, 30310, 30515, + 30720, 30925, 31130, 31334, 31539, 31744, 31949, 32154, 32358, 32563 +}; + +static Word16 interpolator_table_16k_q15[] = { + 0, 410, 819, 1229, 1638, 2048, 2458, 2867, 3277, 3686, + 4096, 4506, 4915, 5325, 5734, 6144, 6554, 6963, 7373, 7782, + 8192, 8602, 9011, 9421, 9830, 10240, 10650, 11059, 11469, 11878, + 12288, 12698, 13107, 13517, 13926, 14336, 14746, 15155, 15565, 15974, + 16384, 16794, 17203, 17613, 18022, 18432, 18842, 19251, 19661, 20070, + 20480, 20890, 21299, 21709, 22118, 22528, 22938, 23347, 23757, 24166, + 24576, 24986, 25395, 25805, 26214, 26624, 27034, 27443, 27853, 28262, + 28672, 29082, 29491, 29901, 30310, 30720, 31130, 31539, 31949, 32358 +}; + +/** + * Calculate mantissa (Q31) * gain (Q31). + * + * Exponent for the mantissa value is also included as input parameter. + * Adjust the result so that accuracy of the mantissa multiplication is maximixed + * and the corresponding exponent is minimized. + */ +static Word32 mult32_mantissa_fx( Word32 mantissa, Word32 gain, Word16 exp, Word16 *exp_result ) +{ + Word64 mult = W_mult_32_32( mantissa, gain ); // Q31 * Q31 -> Q63 + Word16 norm = W_norm( mult ); + Word32 result = W_extract_h( W_shl( mult, norm ) ); // Q63 -> Q31 + *exp_result = sub( exp, norm ); + + return result; +} + +/** + * Calculate re^2 + im^2 using exponent (Q0) and mantissa (Q31) format. + */ +static Word32 sample_energy_fx( Word32 re_m, Word16 re_e, Word32 im_m, Word16 im_e, Word16 *exp_result ) +{ + Word16 re_exp = add( re_e, re_e ); + Word32 re_mult = mult32_mantissa_fx( re_m, re_m, re_exp, &re_exp ); + move32(); + + Word16 im_exp = add( im_e, im_e ); + Word32 im_mult = mult32_mantissa_fx( im_m, im_m, im_exp, &im_exp ); + move32(); + + return BASOP_Util_Add_Mant32Exp( re_mult, re_exp, im_mult, im_exp, exp_result ); +} + +/** + * Accumulate sum of re^2 + im^2 over the specified length using exponent (Q0) and mantissa (Q31) format. + */ +static void sample_energy_acc_fx( Word32 *re_m, Word16 *re_e, Word32 *im_m, Word16 *im_e, Word32 *out_m, Word16 *out_e, Word16 len ) +{ + Word16 i; + + FOR( i = 0; i < len; i++ ) + { + Word16 exp; + + // energy = re^2 + im^2 + Word32 mantissa = sample_energy_fx( re_m[i], re_e[i], im_m[i], im_e[i], &exp ); + move32(); + + // Accumulate energy + *out_m = BASOP_Util_Add_Mant32Exp( *out_m, *out_e, mantissa, exp, out_e ); + move32(); + } +} + +// Multiplication of vector (comprising of exponent and mantissa parts) by constant value (Q31) +static void v_multc_exp_mantissa_fx( + const Word32 *in_mantissa, + const Word16 *in_exp, + Word32 c, + Word32 *out_mantissa, + Word16 *out_exp, + Word16 len ) +{ + Word16 i; + + FOR( i = 0; i < len; i++ ) + { + out_mantissa[i] = mult32_mantissa_fx( in_mantissa[i], c, in_exp[i], &out_exp[i] ); + move32(); + } +} + +// Multiplication of vector (comprising of exponent and mantissa parts) by constant acumulate to the output +static void v_multc_acc_exp_mantissa_fx( + const Word32 *in_mantissa, + const Word16 *in_exp, + Word32 c, + Word32 *out_mantissa, + Word16 *out_exp, + Word16 len ) +{ + Word16 i; + + FOR( i = 0; i < len; i++ ) + { + Word16 exp; + Word32 mantissa = mult32_mantissa_fx( in_mantissa[i], c, in_exp[i], &exp ); + move32(); + + out_mantissa[i] = BASOP_Util_Add_Mant32Exp( out_mantissa[i], out_exp[i], + mantissa, exp, &out_exp[i] ); + move32(); + } +} + +// Calculate min( 4, sqrtf( target / proto ) ) +// target and proto values are expressed using exponent and mantissa +static Word32 get_processing_gain_fx( Word32 proto_m, Word16 proto_e, Word32 target_m, Word16 target_e, Word16 *exp ) +{ + Word16 b = extract_h( proto_m ); + IF( EQ_16( b, 0 ) ) + { + b = 1; + move16(); + } + + Word16 mantissa; + BASOP_Util_Divide_MantExp( extract_h( target_m ), target_e, b, proto_e, &mantissa, exp ); + + Word32 sqrt_mantissa = Sqrt32( L_shl( mantissa, 16 ), exp ); + + Word16 norm = norm_l( sqrt_mantissa ); + sqrt_mantissa = L_shl( sqrt_mantissa, norm ); + *exp = sub( *exp, norm ); + + test(); + IF( GT_16( *exp, 2 ) && NE_32( sqrt_mantissa, 0 ) ) + { + // (2^3) * (1073741824 / 2^31) == 4.0 + sqrt_mantissa = ONE_IN_Q30; // 0.5 in Q31 + *exp = 3; + move32(); + move16(); + } + + return sqrt_mantissa; +} + +static void mantissa_exp_to_qvalue( Word16 *exp, Word32 *output, Word16 target_exp, Word16 len ) +{ + Word16 bin; + + FOR( bin = 0; bin < len; bin++ ) + { + IF( LT_16( exp[bin], -Q31 ) ) + { + output[bin] = 0; + move32(); + } + ELSE + { + Word16 shift = sub( target_exp, exp[bin] ); + output[bin] = W_sat_l( W_shr( output[bin], shift ) ); + } + } +} + +#endif + /*-------------------------------------------------------------------* * ivas_omasa_data_open() @@ -110,6 +330,51 @@ ivas_error ivas_omasa_data_open_fx( set16_fx( hMasaIsmData->azimuth_separated_ism, 0, MAX_PARAM_SPATIAL_SUBFRAMES + DELAY_MASA_PARAM_DEC_SFR ); set16_fx( hMasaIsmData->elevation_separated_ism, 0, MAX_PARAM_SPATIAL_SUBFRAMES + DELAY_MASA_PARAM_DEC_SFR ); +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + hMasaIsmData->hExtData = NULL; + move32(); + + IF( EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_EXTERNAL ) ) + { + MASA_ISM_EXT_DATA_HANDLE hExtData; + hExtData = (MASA_ISM_EXT_DATA_HANDLE) malloc( sizeof( MASA_ISM_EXT_DATA ) ); + move32(); + + IF( hExtData == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA ISM data\n" ) ); + } + + hExtData->prev_idx_separated_ism = 0; + move16(); + + FOR( ch = 0; ch < MAX_NUM_OBJECTS; ch++ ) + { + set32_fx( hExtData->prev_panning_gains[ch], 0, 2 ); + } + + FOR( ch = 0; ch < MAX_NUM_OBJECTS; ch++ ) + { + set32_fx( hExtData->ism_render_proto_energy_frac[ch], 0, CLDFB_NO_CHANNELS_MAX ); + set16_fx( hExtData->ism_render_proto_energy_exp[ch], 0, CLDFB_NO_CHANNELS_MAX ); + set32_fx( hExtData->ism_render_target_energy_frac[ch], 0, CLDFB_NO_CHANNELS_MAX ); + set16_fx( hExtData->ism_render_target_energy_exp[ch], 0, CLDFB_NO_CHANNELS_MAX ); + } + + set32_fx( hExtData->masa_render_proto_energy_frac, 0, CLDFB_NO_CHANNELS_MAX ); + set16_fx( hExtData->masa_render_proto_energy_exp, 0, CLDFB_NO_CHANNELS_MAX ); + set32_fx( hExtData->masa_render_target_energy_frac, 0, CLDFB_NO_CHANNELS_MAX ); + set16_fx( hExtData->masa_render_target_energy_exp, 0, CLDFB_NO_CHANNELS_MAX ); + + FOR( sf = 0; sf < add( MAX_PARAM_SPATIAL_SUBFRAMES, DELAY_MASA_PARAM_DEC_SFR ); sf++ ) + { + set32_fx( hExtData->masa_render_masa_to_total[sf], 0, CLDFB_NO_CHANNELS_MAX ); + } + + hMasaIsmData->hExtData = hExtData; + move32(); + } +#endif st_ivas->hMasaIsmData = hMasaIsmData; return IVAS_ERR_OK; @@ -143,7 +408,14 @@ void ivas_omasa_data_close_fx( free( ( *hMasaIsmData )->delayBuffer_fx ); ( *hMasaIsmData )->delayBuffer_fx = NULL; } - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( ( *hMasaIsmData )->hExtData != NULL ) + { + free( ( *hMasaIsmData )->hExtData ); + ( *hMasaIsmData )->hExtData = NULL; + move32(); + } +#endif free( *hMasaIsmData ); *hMasaIsmData = NULL; @@ -293,7 +565,59 @@ ivas_error ivas_omasa_dec_config_fx( /* ISM MD reconfig. */ n_MD = 0; move16(); +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_EXTERNAL ) ) + { + /* the full number of hIsmMetaData are needed for EXT output */ + move16(); + n_MD = st_ivas->nchan_ism; + ivas_ism_metadata_close( st_ivas->hIsmMetaData, 0 ); + + error = ivas_ism_metadata_dec_create_fx( st_ivas, st_ivas->nchan_ism, NULL ); + move32(); + IF( NE_32( error, IVAS_ERR_OK ) ) + { + return error; + } + + ivas_ism_metadata_close( st_ivas->hIsmMetaData, n_MD ); + } + ELSE + { + test(); + IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) ) + { + n_MD = 1; + move16(); + + IF( st_ivas->hIsmMetaData[0] == NULL ) + { + error = ivas_ism_metadata_dec_create_fx( st_ivas, 1, NULL ); + move32(); + IF( NE_32( error, IVAS_ERR_OK ) ) + { + return error; + } + } + } + ELSE IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) ) + { + n_MD = st_ivas->nchan_ism; + move16(); + + ivas_ism_metadata_close( st_ivas->hIsmMetaData, 0 ); + error = ivas_ism_metadata_dec_create_fx( st_ivas, st_ivas->nchan_ism, NULL ); + move32(); + IF( NE_32( error, IVAS_ERR_OK ) ) + { + return error; + } + } + + ivas_ism_metadata_close( st_ivas->hIsmMetaData, n_MD ); + } +#else test(); IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) ) { @@ -322,7 +646,7 @@ ivas_error ivas_omasa_dec_config_fx( } ivas_ism_metadata_close( st_ivas->hIsmMetaData, n_MD ); - +#endif st_ivas->hCPE[0]->element_brate = L_sub( ivas_total_brate, ism_total_brate ); /*-----------------------------------------------------------------* @@ -351,8 +675,15 @@ ivas_error ivas_omasa_dec_config_fx( } /* objects renderer reconfig. */ +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); + IF( st_ivas->hMasaIsmData != NULL || st_ivas->hIsmRendererData != NULL ) + { + /* this calls also ivas_ism_renderer_close() closing st_ivas->hIsmRendererData used by the EXT renderers. also cleans st_ivas->hMasaIsmData */ +#else IF( st_ivas->hMasaIsmData != NULL ) { +#endif ivas_omasa_separate_object_renderer_close( st_ivas ); } @@ -414,7 +745,49 @@ ivas_error ivas_omasa_dec_config_fx( ivas_omasa_separate_object_renderer_close( st_ivas ); } } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_MIX_EXT ) ) + { + /* Allocate 'hIsmRendererData' handle */ + error = ivas_omasa_combine_separate_ism_with_masa_open_fx( st_ivas ); + move32(); + IF( NE_32( error, IVAS_ERR_OK ) ) + { + return error; + } + } + + IF( EQ_32( st_ivas->renderer_type, RENDERER_OMASA_OBJECT_EXT ) ) + { + DIRAC_CONFIG_FLAG common_rend_config_flag; + IF( st_ivas->hSpatParamRendCom == NULL ) + { + common_rend_config_flag = DIRAC_OPEN; + } + ELSE + { + common_rend_config_flag = DIRAC_RECONFIGURE; + } + move32(); + /* Allocate 'hIsmRendererData' handle and memory for delay buffer within 'hMasaIsmData' */ + error = ivas_omasa_render_objects_from_mix_open_fx( st_ivas ); + move32(); + IF( NE_32( error, IVAS_ERR_OK ) ) + { + return error; + } + + error = ivas_spat_hSpatParamRendCom_config_fx( &st_ivas->hSpatParamRendCom, + common_rend_config_flag, 0, + st_ivas->ivas_format, st_ivas->mc_mode, st_ivas->hDecoderConfig->output_Fs, 0, 0 ); + move32(); + IF( NE_32( error, IVAS_ERR_OK ) ) + { + return error; + } + } +#endif /*-----------------------------------------------------------------* * TD Decorrelator *-----------------------------------------------------------------*/ @@ -600,7 +973,9 @@ ivas_error ivas_omasa_ism_metadata_dec_fx( *nchan_transport_ism = 1; move16(); } - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); +#endif test(); IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_DISC ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) { @@ -666,6 +1041,37 @@ ivas_error ivas_omasa_ism_metadata_dec_fx( } } } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + ELSE IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) && + EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_EXTERNAL ) ) + { + azimuth_ism = extract_l( L_shr_r( L_abs( st_ivas->hIsmMetaData[0]->azimuth_fx ), 22 ) ); + if ( st_ivas->hIsmMetaData[0]->azimuth_fx < 0 ) + { + azimuth_ism = negate( azimuth_ism ); + } + elevation_ism = extract_l( L_shr_r( L_abs( st_ivas->hIsmMetaData[0]->elevation_fx ), 22 ) ); + if ( st_ivas->hIsmMetaData[0]->elevation_fx < 0 ) + { + elevation_ism = negate( elevation_ism ); + } + + FOR( block = 0; block < 2; block++ ) + { + st_ivas->hMasaIsmData->azimuth_separated_ism[block] = st_ivas->hMasaIsmData->azimuth_separated_ism[add( block, 2 )]; + st_ivas->hMasaIsmData->elevation_separated_ism[block] = st_ivas->hMasaIsmData->elevation_separated_ism[add( block, 2 )]; + move16(); + move16(); + } + FOR( block = 2; block < MAX_PARAM_SPATIAL_SUBFRAMES; block++ ) + { + st_ivas->hMasaIsmData->azimuth_separated_ism[block] = azimuth_ism; + st_ivas->hMasaIsmData->elevation_separated_ism[block] = elevation_ism; + move16(); + move16(); + } + } +#endif } return IVAS_ERR_OK; @@ -865,3 +1271,846 @@ void ivas_omasa_rearrange_channels_fx( return; } + +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + +/*-------------------------------------------------------------------------* + * ivas_omasa_combine_separate_ism_with_masa_open_fx() + * + * Open structures, reserve memory, and init values. + *-------------------------------------------------------------------------*/ + +ivas_error ivas_omasa_combine_separate_ism_with_masa_open_fx( Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +) +{ + Word16 i; + Word16 *tmp; + + st_ivas->hIsmRendererData = (ISM_RENDERER_HANDLE) malloc( sizeof( ISM_RENDERER_DATA ) ); + move32(); + + IF( st_ivas->hIsmRendererData == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for MASA ISM renderer \n" ) ); + } + + FOR( i = 0; i < MAX_NUM_OBJECTS; i++ ) + { + set_zero_fx( st_ivas->hIsmRendererData->prev_gains_fx[i], MAX_OUTPUT_CHANNELS ); + } + + test(); + test(); + IF( EQ_32( st_ivas->hDecoderConfig->output_Fs, 16000 ) || + EQ_32( st_ivas->hDecoderConfig->output_Fs, 32000 ) || + EQ_32( st_ivas->hDecoderConfig->output_Fs, 48000 ) ) + { + IF( EQ_32( st_ivas->hDecoderConfig->output_Fs, 16000 ) ) + { + st_ivas->hIsmRendererData->interpolator_len = 80; + tmp = interpolator_table_16k_q15; + } + ELSE IF( EQ_32( st_ivas->hDecoderConfig->output_Fs, 32000 ) ) + { + st_ivas->hIsmRendererData->interpolator_len = 160; + tmp = interpolator_table_32k_q15; + } + ELSE + { + st_ivas->hIsmRendererData->interpolator_len = 240; + tmp = interpolator_table_48k_q15; + } + move16(); + move32(); + + st_ivas->hIsmRendererData->interpolator_fx = + (Word16 *) malloc( sizeof( Word16 ) * st_ivas->hIsmRendererData->interpolator_len ); + + IF( st_ivas->hIsmRendererData->interpolator_fx == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA ISM renderer interpolator\n" ) ); + } + + FOR( i = 0; i < st_ivas->hIsmRendererData->interpolator_len; i++ ) + { + st_ivas->hIsmRendererData->interpolator_fx[i] = tmp[i]; + move16(); + } + } + ELSE + { + return ( IVAS_ERROR( IVAS_ERR_INVALID_SAMPLING_RATE, "Unsupported output sample rate\n" ) ); + } + + return IVAS_ERR_OK; +} + +/*--------------------------------------------------------------------------* + * ivas_omasa_combine_separate_ism_with_masa_fx() + * + * in case of external rendering, combine separated ISM signal with MASA stream + *--------------------------------------------------------------------------*/ + +void ivas_omasa_combine_separate_ism_with_masa_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + Word32 *output[], /* i/o: output synthesis signal */ + Word16 *output_q, /* i/o: output Q value */ + const int16_t nchan_ism, /* i : number of ISMs */ + const int16_t output_frame /* i : output frame length per channel */ +) +{ + Word16 n, sf, band, k; + MASA_DECODER_EXT_OUT_META_HANDLE masaMetaHandle; + MASA_DECODER_EXT_OUT_META_HANDLE ismMetaHandle; + MASA_DECODER_EXT_OUT_META ismMeta; + Word32 inRe[3][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word32 inIm[3][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + UWord16 directionIndex; + Word16 nchan_in; + Word16 nBins; + Word16 slot; + Word16 mrange[2], brange[2]; + Word16 processing_len, offset; + + Word32 old_panning_gains_fx[2]; + Word32 new_panning_gains_fx[2]; + + Word16 inRe_exp[3][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word16 inIm_exp[3][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word16 out_exp[MASA_MAX_TRANSPORT_CHANNELS + 1][L_FRAME48k]; + + Word16 eneMasa_exp[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + Word32 eneMasa_frac[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + Word16 eneIsm_exp[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + Word32 eneIsm_frac[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS]; + + Word16 old_panning_gains_q15_fx[2]; + Word16 new_panning_gains_q15_fx[2]; + + Word16 exp; + + masaMetaHandle = st_ivas->hMasa->data.extOutMeta; + ismMetaHandle = &ismMeta; + move32(); + move32(); + + /* Compute CLDFB analysis */ + nchan_in = add( st_ivas->nchan_transport, 1 ); + nBins = mult( output_frame, MULT_1_DIV_CLDFB_NO_COL_MAX_Q15 ); // Q15 + FOR( slot = 0; slot < CLDFB_NO_COL_MAX; slot++ ) + { + FOR( n = 0; n < nchan_in; n++ ) + { + Word16 in_q = *output_q; + move16(); + + cldfbAnalysis_ts_fx_var_q( &( output[n][L_mult0( nBins, slot )] ), + inRe[n][slot], + inIm[n][slot], + nBins, st_ivas->cldfbAnaDec[n], &in_q ); + + /* Assign input exponent */ + exp = sub( Q31, in_q ); + set16_fx( inRe_exp[n][slot], exp, nBins ); + set16_fx( inIm_exp[n][slot], exp, nBins ); + } + } + + /* Convert output to exponent+mantissa representation */ + exp = sub( Q31, *output_q ); + FOR( n = 0; n < add( MASA_MAX_TRANSPORT_CHANNELS, 1 ); n++ ) + { + set16_fx( out_exp[n], exp, output_frame ); + } + + FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ ) + { + set16_fx( eneMasa_exp[sf], 0, MASA_FREQUENCY_BANDS ); + set32_fx( eneMasa_frac[sf], 0, MASA_FREQUENCY_BANDS ); + + set16_fx( eneIsm_exp[sf], 0, MASA_FREQUENCY_BANDS ); + set32_fx( eneIsm_frac[sf], 0, MASA_FREQUENCY_BANDS ); + } + + /* Determine energies */ + FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ ) + { + mrange[0] = st_ivas->hMasa->config.block_grouping[sf]; + mrange[1] = st_ivas->hMasa->config.block_grouping[add( sf, 1 )]; + move16(); + move16(); + + FOR( slot = mrange[0]; slot < mrange[1]; slot++ ) + { + FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ ) + { + brange[0] = st_ivas->hMasa->config.band_grouping[band]; + brange[1] = st_ivas->hMasa->config.band_grouping[add( band, 1 )]; + move16(); + move16(); + + IF( GT_16( brange[1], nBins ) ) + { + brange[1] = nBins; + move16(); + } + + Word16 len = sub( brange[1], brange[0] ); + + FOR( n = 0; n < MASA_MAX_TRANSPORT_CHANNELS; n++ ) + { + sample_energy_acc_fx( &inRe[n][slot][brange[0]], + &inRe_exp[n][slot][brange[0]], + &inIm[n][slot][brange[0]], + &inIm_exp[n][slot][brange[0]], + &eneMasa_frac[sf][band], + &eneMasa_exp[sf][band], + len ); + } + + sample_energy_acc_fx( &inRe[MASA_MAX_TRANSPORT_CHANNELS][slot][brange[0]], + &inRe_exp[MASA_MAX_TRANSPORT_CHANNELS][slot][brange[0]], + &inIm[MASA_MAX_TRANSPORT_CHANNELS][slot][brange[0]], + &inIm_exp[MASA_MAX_TRANSPORT_CHANNELS][slot][brange[0]], + &eneIsm_frac[sf][band], + &eneIsm_exp[sf][band], + len ); + } + } + } + + /* Determine MASA metadata for the object */ + ismMetaHandle->descriptiveMeta.numberOfDirections = 0u; + move16(); + + FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ ) + { + Word32 ele, azi; + + ele = st_ivas->hMasaIsmData->elevation_separated_ism[sf]; + azi = st_ivas->hMasaIsmData->azimuth_separated_ism[sf]; + + directionIndex = index_theta_phi_16_fx( &ele, &azi, st_ivas->hMasa->data.sph_grid16 ); + + FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ ) + { + ismMetaHandle->directionIndex[0][sf][band] = directionIndex; + ismMetaHandle->directToTotalRatio[0][sf][band] = UINT8_MAX; + ismMetaHandle->spreadCoherence[0][sf][band] = 0; + ismMetaHandle->surroundCoherence[sf][band] = 0; + ismMetaHandle->diffuseToTotalRatio[sf][band] = 0; + move16(); + move16(); + move16(); + move16(); + move16(); + } + } + + /* Merge MASA metadatas */ + ivas_prerend_merge_masa_metadata_fx( masaMetaHandle, masaMetaHandle, + IVAS_REND_AUDIO_CONFIG_TYPE_MASA, + eneMasa_frac, eneMasa_exp, ismMetaHandle, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED, + eneIsm_frac, eneIsm_exp ); + + /* Mix the separated object audio signal to the MASA audio signals */ + ivas_get_stereo_panning_gains_fx( st_ivas->hMasaIsmData->azimuth_separated_ism[0], + st_ivas->hMasaIsmData->elevation_separated_ism[0], old_panning_gains_q15_fx ); + ivas_get_stereo_panning_gains_fx( st_ivas->hMasaIsmData->azimuth_separated_ism[2], + st_ivas->hMasaIsmData->elevation_separated_ism[2], new_panning_gains_q15_fx ); + + /* Subsequent processing in Q31 format */ + FOR( n = 0; n < MASA_MAX_TRANSPORT_CHANNELS; n++ ) + { + new_panning_gains_fx[n] = L_shl( new_panning_gains_q15_fx[n], Q16 ); + old_panning_gains_fx[n] = L_shl( old_panning_gains_q15_fx[n], Q16 ); + } + + processing_len = shr( output_frame, 1 ); + FOR( n = 0; n < MASA_MAX_TRANSPORT_CHANNELS; n++ ) + { + v_multc_acc_exp_mantissa_fx( output[MASA_MAX_TRANSPORT_CHANNELS], + out_exp[MASA_MAX_TRANSPORT_CHANNELS], + old_panning_gains_fx[n], + output[n], + out_exp[n], + processing_len ); + } + offset = processing_len; + move16(); + + processing_len = shr( output_frame, 2 ); /* divide by MAX_PARAM_SPATIAL_SUBFRAMES; */ + FOR( n = 0; n < MASA_MAX_TRANSPORT_CHANNELS; n++ ) + { + Word32 mantissa; + + /* k == 0->gain == old_panning_gains[n] */ + /* output[n][offset] += gain * output[MASA_MAX_TRANSPORT_CHANNELS][offset]; */ + mantissa = mult32_mantissa_fx( output[MASA_MAX_TRANSPORT_CHANNELS][offset], + old_panning_gains_fx[n], + out_exp[MASA_MAX_TRANSPORT_CHANNELS][offset], &exp ); + + output[n][offset] = BASOP_Util_Add_Mant32Exp( output[n][offset], out_exp[n][offset], + mantissa, exp, &out_exp[n][offset] ); + move32(); + move32(); + + FOR( k = 1; k < processing_len; k++ ) + { + Word16 index = add( k, offset ); + + Word32 g1_fx = L_shl( st_ivas->hIsmRendererData->interpolator_fx[k], Q16 ); + + /* 1.0f - g1 */ + Word32 g2_fx = L_sub( MAX_32, L_sub( g1_fx, 1 ) ); + + /* g1 *new_panning_gains[n] + g2 *old_panning_gains[n] */ + Word32 gain_k = W_extract_h( W_add( W_mult_32_32( g1_fx, new_panning_gains_fx[n] ), + W_mult_32_32( g2_fx, old_panning_gains_fx[n] ) ) ); + + /* output[n][k + offset] += gain_k * output[MASA_MAX_TRANSPORT_CHANNELS][k + offset]; */ + mantissa = mult32_mantissa_fx( output[MASA_MAX_TRANSPORT_CHANNELS][index], gain_k, + out_exp[MASA_MAX_TRANSPORT_CHANNELS][index], &exp ); + output[n][index] = BASOP_Util_Add_Mant32Exp( output[n][index], out_exp[n][index], + mantissa, exp, &out_exp[n][index] ); + move32(); + move32(); + } + } + offset = add( offset, processing_len ); + + FOR( n = 0; n < MASA_MAX_TRANSPORT_CHANNELS; n++ ) + { + v_multc_acc_exp_mantissa_fx( &output[MASA_MAX_TRANSPORT_CHANNELS][offset], + &out_exp[MASA_MAX_TRANSPORT_CHANNELS][offset], + new_panning_gains_fx[n], + &output[n][offset], + &out_exp[n][offset], + processing_len ); + } + + /* Convert output from exponent+mantissa representation to Q11 */ + FOR( n = 0; n < MASA_MAX_TRANSPORT_CHANNELS; n++ ) + { + mantissa_exp_to_qvalue( &out_exp[n][0], &output[n][0], Q20, output_frame ); + } + + /* Zero output object channels */ + FOR( n = 0; n < nchan_ism; n++ ) + { + set_zero_fx( output[add( MASA_MAX_TRANSPORT_CHANNELS, n )], output_frame ); + } +} + + +/*-------------------------------------------------------------------------* + * ivas_omasa_render_objects_from_mix_open_fx() + * + * Open structures, reserve memory, and init values. + *-------------------------------------------------------------------------*/ + +ivas_error ivas_omasa_render_objects_from_mix_open_fx( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +) +{ + Word16 i; + Word32 size; + + st_ivas->hMasaIsmData->delayBuffer_nchan = 1; + move16(); + + st_ivas->hMasaIsmData->delayBuffer_size = extract_l( Mult_32_16( st_ivas->hDecoderConfig->output_Fs, + OMASA_DELAYFRAMES_PER_SEC_Q15 ) ); + + size = L_mult0( st_ivas->hMasaIsmData->delayBuffer_nchan, sizeof( Word16 * ) ); + st_ivas->hMasaIsmData->delayBuffer_fx = (Word32 **) malloc( size ); + move32(); + + IF( st_ivas->hMasaIsmData->delayBuffer_fx == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for MASA ISM delay buffer \n" ) ); + } + + size = L_mult0( st_ivas->hMasaIsmData->delayBuffer_size, sizeof( Word32 ) ); + FOR( i = 0; i < st_ivas->hMasaIsmData->delayBuffer_nchan; i++ ) + { + st_ivas->hMasaIsmData->delayBuffer_fx[i] = (Word32 *) malloc( size ); + move32(); + + IF( st_ivas->hMasaIsmData->delayBuffer_fx[i] == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for MASA ISM delay buffer \n" ) ); + } + set_zero_fx( st_ivas->hMasaIsmData->delayBuffer_fx[i], st_ivas->hMasaIsmData->delayBuffer_size ); + } + + return IVAS_ERR_OK; +} + + +/*--------------------------------------------------------------------------* + * ivas_omasa_render_objects_from_mix() + * + * In case of external rendering, render objects from the transport signal + * mix containing MASA audio and object audio. + *--------------------------------------------------------------------------*/ + +void ivas_omasa_render_objects_from_mix_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + Word32 *output[], /* o : output synthesis signal */ + const int16_t nchan_ism, /* i : number of ISMs */ + const int16_t output_frame, /* i : output frame length per channel */ + Word16 *output_q /* i/o: output Q value */ +) +{ + Word16 n, m, i; + MASA_ISM_EXT_DATA_HANDLE hExtData; + Word32 separated_object[L_FRAME48k]; + Word32 rendered_objects[MAX_NUM_OBJECTS][L_FRAME48k]; + Word16 coding_delay; + Word32 inRe[3][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word32 inIm[3][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word32 outRe[MAX_NUM_OBJECTS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word32 outIm[MAX_NUM_OBJECTS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word16 slot; + Word16 sf; + Word16 bin; + Word16 nchan_transport; + Word16 nBins; + + Word16 inRe_exp[3][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word16 inIm_exp[3][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word16 outRe_exp[MAX_NUM_OBJECTS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word16 outIm_exp[MAX_NUM_OBJECTS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + + Word16 transport_energy_exp[CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + Word32 transport_energy_frac[CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; + + /* Create slot to metadata map */ + slot = 0; + move16(); + FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ ) + { + Word16 index; + + FOR( i = 0; i < CLDFB_SLOTS_PER_SUBFRAME; i++ ) + { + st_ivas->hSpatParamRendCom->render_to_md_map[slot] = st_ivas->hSpatParamRendCom->dirac_read_idx; + move16(); + slot = add( slot, 1 ); + } + + index = add( st_ivas->hSpatParamRendCom->dirac_read_idx, 1 ); + IF( GE_16( index, st_ivas->hSpatParamRendCom->dirac_md_buffer_length ) ) + { + index = 0; + move16(); + } + st_ivas->hSpatParamRendCom->dirac_read_idx = index; + move16(); + } + + /* Move separated object signal and object channels */ + mvl2l( output[CPE_CHANNELS], separated_object, output_frame ); + FOR( n = 0; n < nchan_ism; n++ ) + { + set_zero_fx( output[CPE_CHANNELS + n], output_frame ); + } + + /* Delay the separated object signal by the CLDFB delay */ + delay_signal32_fx( separated_object, output_frame, st_ivas->hMasaIsmData->delayBuffer_fx[0], + st_ivas->hMasaIsmData->delayBuffer_size ); + + /* Set object metadata to the ism struct */ + FOR( n = 0; n < nchan_ism; n++ ) + { + // Q0 -> Q22 + Word32 azi = L_shl( st_ivas->hMasaIsmData->azimuth_ism[n][st_ivas->hSpatParamRendCom->dirac_read_idx], Q22 ); + Word32 ele = L_shl( st_ivas->hMasaIsmData->elevation_ism[n][st_ivas->hSpatParamRendCom->dirac_read_idx], Q22 ); + + st_ivas->hIsmMetaData[n]->azimuth_fx = azi; + st_ivas->hIsmMetaData[n]->elevation_fx = ele; + move16(); + move16(); + } + + /* Move the separated object signal to the correct output channel */ + hExtData = st_ivas->hMasaIsmData->hExtData; + move32(); + coding_delay = mult( output_frame, MULT_17_DIV_20_Q15 ); /* Q15: 17 ms of coding and CLDFB delay */ + mvl2l( separated_object, output[add( CPE_CHANNELS, hExtData->prev_idx_separated_ism )], coding_delay ); + mvl2l( &separated_object[coding_delay], + &output[add( CPE_CHANNELS, st_ivas->hMasaIsmData->idx_separated_ism )][coding_delay], + sub( output_frame, coding_delay ) ); + + /* Compute CLDFB analysis */ + nchan_transport = st_ivas->nchan_transport; + move16(); + nBins = mult( output_frame, MULT_1_DIV_CLDFB_NO_COL_MAX_Q15 ); // Q15 + + FOR( slot = 0; slot < CLDFB_NO_COL_MAX; slot++ ) + { + FOR( n = 0; n < nchan_transport; n++ ) + { + Word16 in_q = *output_q; + move16(); + + cldfbAnalysis_ts_fx_var_q( &( output[n][L_mult0( nBins, slot )] ), + inRe[n][slot], + inIm[n][slot], + nBins, st_ivas->cldfbAnaDec[n], &in_q ); + + /* Assign input exponent */ + Word16 exp = sub( Q31, in_q ); + set16_fx( inRe_exp[n][slot], exp, nBins ); + set16_fx( inIm_exp[n][slot], exp, nBins ); + } + } + + /* Create prototype signals */ + for ( n = 0; n < nchan_ism; n++ ) + { + Word32 panning_gains_fx[2]; + Word16 new_panning_gains_fx[2]; + Word16 azimuth_fx, elevation_fx; + + // Q22 -> Q0 + azimuth_fx = extract_l( L_shr( st_ivas->hIsmMetaData[n]->azimuth_fx, Q22 ) ); + elevation_fx = extract_l( L_shr( st_ivas->hIsmMetaData[n]->elevation_fx, Q22 ) ); + ivas_get_stereo_panning_gains_fx( azimuth_fx, elevation_fx, new_panning_gains_fx ); + + Word16 interpValInc = 0; + move16(); + + // Represents (1.0f - interpVal) value + Word16 interpValDec = extract_l( L_sub( -MIN16B, MULT_1_DIV_CLDFB_NO_COL_MAX_Q15 ) ); + + FOR( slot = 0; slot < sub( CLDFB_NO_COL_MAX, 1 ); slot++ ) + { + interpValInc = add( interpValInc, MULT_1_DIV_CLDFB_NO_COL_MAX_Q15 ); + + FOR( m = 0; m < 2; m++ ) + { + Word32 prev_gain = hExtData->prev_panning_gains[n][m]; + move32(); + + Word32 new_gain = L_shl( new_panning_gains_fx[m], 16 ); // Q15 -> Q31 + + panning_gains_fx[m] = L_add( Mpy_32_16( extract_h( prev_gain ), extract_l( prev_gain ), + interpValDec ), + Mpy_32_16( extract_h( new_gain ), extract_l( new_gain ), + interpValInc ) ); + } + + interpValDec = sub( interpValDec, MULT_1_DIV_CLDFB_NO_COL_MAX_Q15 ); + + v_multc_exp_mantissa_fx( inRe[0][slot], inRe_exp[0][slot], panning_gains_fx[0], + outRe[n][slot], outRe_exp[n][slot], nBins ); + v_multc_exp_mantissa_fx( inIm[0][slot], inIm_exp[0][slot], panning_gains_fx[0], + outIm[n][slot], outIm_exp[n][slot], nBins ); + + v_multc_acc_exp_mantissa_fx( inRe[1][slot], inRe_exp[1][slot], panning_gains_fx[1], + outRe[n][slot], outRe_exp[n][slot], nBins ); + v_multc_acc_exp_mantissa_fx( inIm[1][slot], inIm_exp[1][slot], panning_gains_fx[1], + outIm[n][slot], outIm_exp[n][slot], nBins ); + } + + // Special case where (1.0f - interpVal) = 0 and interpVal = 1 + FOR( m = 0; m < 2; m++ ) + { + panning_gains_fx[m] = L_shl( new_panning_gains_fx[m], 16 ); // Q15 -> Q31 + } + + v_multc_exp_mantissa_fx( inRe[0][slot], inRe_exp[0][slot], panning_gains_fx[0], + outRe[n][slot], outRe_exp[n][slot], nBins ); + v_multc_exp_mantissa_fx( inIm[0][slot], inIm_exp[0][slot], panning_gains_fx[0], + outIm[n][slot], outIm_exp[n][slot], nBins ); + + v_multc_acc_exp_mantissa_fx( inRe[1][slot], inRe_exp[1][slot], panning_gains_fx[1], + outRe[n][slot], outRe_exp[n][slot], nBins ); + v_multc_acc_exp_mantissa_fx( inIm[1][slot], inIm_exp[1][slot], panning_gains_fx[1], + outIm[n][slot], outIm_exp[n][slot], nBins ); + + FOR( m = 0; m < 2; m++ ) + { + hExtData->prev_panning_gains[n][m] = panning_gains_fx[m]; + move32(); + } + } + + /* Determine transport energy */ + FOR( slot = 0; slot < CLDFB_NO_COL_MAX; slot++ ) + { + set_zero_fx( &transport_energy_frac[slot][0], nBins ); + set16_zero_fx( &transport_energy_exp[slot][0], nBins ); + } + FOR( n = 0; n < CPE_CHANNELS; n++ ) + { + FOR( slot = 0; slot < CLDFB_NO_COL_MAX; slot++ ) + { + FOR( bin = 0; bin < nBins; bin++ ) + { + Word16 exp; + + // energy = re^2 + im^2 + Word32 mantissa = sample_energy_fx( inRe[n][slot][bin], inRe_exp[n][slot][bin], + inIm[n][slot][bin], inIm_exp[n][slot][bin], &exp ); + move32(); + + // Accumulate energy + transport_energy_frac[slot][bin] = BASOP_Util_Add_Mant32Exp( transport_energy_frac[slot][bin], + transport_energy_exp[slot][bin], + mantissa, + exp, + &transport_energy_exp[slot][bin] ); + move32(); + } + } + } + + /* Determine temporally smoothed energies and determine gains using them */ + FOR( n = 0; n < nchan_ism; n++ ) + { + FOR( slot = 0; slot < CLDFB_NO_COL_MAX; slot++ ) + { + Word16 md_idx = st_ivas->hSpatParamRendCom->render_to_md_map[slot]; + move16(); + + FOR( bin = 0; bin < nBins; bin++ ) + { + Word16 exp, exp_mult, proto_e, target_e; + Word32 mantissa, proto_m, target_m; + + Word32 ism_target_energy_frac; + Word16 ism_target_energy_exp; + + Word32 ism_proto_energy_frac; + Word16 ism_proto_energy_exp; + + // r1 = transport_energy[slot][bin] * st_ivas->hMasaIsmData->energy_ratio_ism[n][md_idx][bin] + ism_target_energy_frac = mult32_mantissa_fx( transport_energy_frac[slot][bin], + st_ivas->hMasaIsmData->energy_ratio_ism_fx[n][md_idx][bin], + add( transport_energy_exp[slot][bin], 1 ), + &ism_target_energy_exp ); + move32(); + + // r2 = r1 * (1.0 - EXT_RENDER_IIR_FAC) + ism_target_energy_frac = mult32_mantissa_fx( ism_target_energy_frac, + ONEMINUX_EXT_RENDER_IIR_FAC_Q31, + ism_target_energy_exp, + &ism_target_energy_exp ); + move32(); + + // r3 = re^2 + im^2 + mantissa = sample_energy_fx( outRe[n][slot][bin], + outRe_exp[n][slot][bin], + outIm[n][slot][bin], + outIm_exp[n][slot][bin], + &exp ); + move32(); + + // r4 = r3 * (1 - EXT_RENDER_IIR_FAC) + ism_proto_energy_frac = mult32_mantissa_fx( mantissa, ONEMINUX_EXT_RENDER_IIR_FAC_Q31, + exp, &ism_proto_energy_exp ); + move32(); + + + // r5 = ism_render_proto_energy[n][bin] * EXT_RENDER_IIR_FAC + proto_m = mult32_mantissa_fx( hExtData->ism_render_proto_energy_frac[n][bin], EXT_RENDER_IIR_FAC_Q31, + hExtData->ism_render_proto_energy_exp[n][bin], &proto_e ); + move32(); + + // r6 = r5 + r4 + proto_m = BASOP_Util_Add_Mant32Exp( proto_m, proto_e, + ism_proto_energy_frac, + ism_proto_energy_exp, + &proto_e ); + move32(); + + // r7 = ism_render_target_energy[n][bin] * EXT_RENDER_IIR_FAC + target_m = mult32_mantissa_fx( hExtData->ism_render_target_energy_frac[n][bin], EXT_RENDER_IIR_FAC_Q31, + hExtData->ism_render_target_energy_exp[n][bin], &target_e ); + move32(); + + // r8 = r7 + r2 + target_m = BASOP_Util_Add_Mant32Exp( target_m, target_e, + ism_target_energy_frac, + ism_target_energy_exp, + &target_e ); + move32(); + + hExtData->ism_render_proto_energy_frac[n][bin] = proto_m; + hExtData->ism_render_proto_energy_exp[n][bin] = proto_e; + move32(); + move16(); + + hExtData->ism_render_target_energy_frac[n][bin] = target_m; + hExtData->ism_render_target_energy_exp[n][bin] = target_e; + move32(); + move16(); + + // r9 = sqrt(r8 / r6) + mantissa = get_processing_gain_fx( proto_m, proto_e, target_m, target_e, &exp ); + move32(); + + // outRe[n][slot][bin] *= r9 + exp_mult = add( exp, outRe_exp[n][slot][bin] ); + outRe[n][slot][bin] = mult32_mantissa_fx( outRe[n][slot][bin], mantissa, exp_mult, + &outRe_exp[n][slot][bin] ); + move32(); + + // outIm[n][slot][bin] *= r9 + exp_mult = add( exp, outIm_exp[n][slot][bin] ); + outIm[n][slot][bin] = mult32_mantissa_fx( outIm[n][slot][bin], mantissa, exp_mult, + &outIm_exp[n][slot][bin] ); + move32(); + } + } + } + + FOR( slot = 0; slot < CLDFB_NO_COL_MAX; slot++ ) + { + Word16 md_idx = st_ivas->hSpatParamRendCom->render_to_md_map[slot]; + move16(); + + FOR( bin = 0; bin < nBins; bin++ ) + { + Word16 exp, proto_e, target_e, transport_exp; + Word32 mantissa, proto_m, target_m, transport_mantissa; + + Word32 masa_target_energy_frac; + Word16 masa_target_energy_exp; + + // r1 = transport_energy[slot][bin] * hExtData->masa_render_masa_to_total[md_idx][bin] + masa_target_energy_frac = mult32_mantissa_fx( transport_energy_frac[slot][bin], + hExtData->masa_render_masa_to_total[md_idx][bin], + add( transport_energy_exp[slot][bin], 1 ), + &masa_target_energy_exp ); + move32(); + + // r2 = r1 * EXT_RENDER_IIR_FAC + masa_target_energy_frac = mult32_mantissa_fx( masa_target_energy_frac, + ONEMINUX_EXT_RENDER_IIR_FAC_Q31, + masa_target_energy_exp, + &masa_target_energy_exp ); + move32(); + + // r3 = masa_render_proto_energy[bin] * EXT_RENDER_IIR_FAC + proto_m = mult32_mantissa_fx( hExtData->masa_render_proto_energy_frac[bin], EXT_RENDER_IIR_FAC_Q31, + hExtData->masa_render_proto_energy_exp[bin], &proto_e ); + move32(); + + // r4 = transport_energy[slot][bin] * EXT_RENDER_IIR_FAC + transport_mantissa = mult32_mantissa_fx( transport_energy_frac[slot][bin], + ONEMINUX_EXT_RENDER_IIR_FAC_Q31, + transport_energy_exp[slot][bin], &transport_exp ); + move32(); + + // r5 = r3 + r4 + proto_m = BASOP_Util_Add_Mant32Exp( proto_m, proto_e, + transport_mantissa, + transport_exp, + &proto_e ); + move32(); + + // r6 = masa_render_target_energy[bin] * EXT_RENDER_IIR_FAC + target_m = mult32_mantissa_fx( hExtData->masa_render_target_energy_frac[bin], EXT_RENDER_IIR_FAC_Q31, + hExtData->masa_render_target_energy_exp[bin], &target_e ); + move32(); + + // r7 = r6 + r2 + target_m = BASOP_Util_Add_Mant32Exp( target_m, target_e, + masa_target_energy_frac, + masa_target_energy_exp, + &target_e ); + move32(); + + hExtData->masa_render_proto_energy_frac[bin] = proto_m; + hExtData->masa_render_proto_energy_exp[bin] = proto_e; + move16(); + move32(); + + hExtData->masa_render_target_energy_frac[bin] = target_m; + hExtData->masa_render_target_energy_exp[bin] = target_e; + move16(); + move32(); + + // r8 = sqrt(r7 / r5) + mantissa = get_processing_gain_fx( proto_m, proto_e, target_m, target_e, &exp ); + move32(); + + FOR( n = 0; n < MASA_MAX_TRANSPORT_CHANNELS; n++ ) + { + Word16 exp_mult; + + // inRe[n][slot][bin] *= r8 + exp_mult = add( exp, inRe_exp[n][slot][bin] ); + inRe[n][slot][bin] = mult32_mantissa_fx( inRe[n][slot][bin], mantissa, exp_mult, + &inRe_exp[n][slot][bin] ); + move32(); + + // inIm[n][slot][bin] *= r8 + exp_mult = add( exp, inIm_exp[n][slot][bin] ); + inIm[n][slot][bin] = mult32_mantissa_fx( inIm[n][slot][bin], mantissa, exp_mult, + &inIm_exp[n][slot][bin] ); + move32(); + } + } + } + + *output_q = Q11; + + /* Compute CLDFB synthesis */ + FOR( slot = 0; slot < CLDFB_NO_COL_MAX; slot++ ) + { + Word32 *outSlotRePr, *outSlotImPr; + Word32 index = L_mult0( nBins, slot ); + + FOR( n = 0; n < nchan_transport; n++ ) + { + outSlotRePr = &( inRe[n][slot][0] ); + outSlotImPr = &( inIm[n][slot][0] ); + move32(); + move32(); + + FOR( bin = 0; bin < nBins; bin++ ) + { + inRe_exp[n][slot][bin] = sub( inRe_exp[n][slot][bin], Q2 ); + inIm_exp[n][slot][bin] = sub( inIm_exp[n][slot][bin], Q2 ); + } + + mantissa_exp_to_qvalue( &inRe_exp[n][slot][0], &inRe[n][slot][0], Q20, nBins ); + mantissa_exp_to_qvalue( &inIm_exp[n][slot][0], &inIm[n][slot][0], Q20, nBins ); + + cldfbSynthesis_ivas_fx( &outSlotRePr, &outSlotImPr, &output[n][index], + nBins, Q2, 1, st_ivas->cldfbSynDec[n] ); + } + + FOR( n = 0; n < nchan_ism; n++ ) + { + Word32 index2 = add( n, CPE_CHANNELS ); + + outSlotRePr = &( outRe[n][slot][0] ); + outSlotImPr = &( outIm[n][slot][0] ); + move32(); + move32(); + + mantissa_exp_to_qvalue( &outRe_exp[n][slot][0], &outRe[n][slot][0], Q20, nBins ); + mantissa_exp_to_qvalue( &outIm_exp[n][slot][0], &outIm[n][slot][0], Q20, nBins ); + + cldfbSynthesis_ivas_fx( &outSlotRePr, &outSlotImPr, &rendered_objects[n][index], + nBins, 0, 1, st_ivas->cldfbSynDec[index2] ); + } + } + + /* Combine the rendered objects with the separated objects */ + FOR( n = 0; n < nchan_ism; n++ ) + { + Word16 index = add( CPE_CHANNELS, n ); + v_add_32( output[index], rendered_objects[n], output[index], output_frame ); + } + + hExtData->prev_idx_separated_ism = st_ivas->hMasaIsmData->idx_separated_ism; + move16(); +} +#endif diff --git a/lib_dec/ivas_output_config_fx.c b/lib_dec/ivas_output_config_fx.c index bdf7b67bc808ed5cf30f4c1811978ea2a83ccc1a..c5a01180d1cde7832e64b28d8d246052488ae96f 100644 --- a/lib_dec/ivas_output_config_fx.c +++ b/lib_dec/ivas_output_config_fx.c @@ -479,8 +479,26 @@ void ivas_renderer_select( } ELSE IF( EQ_32( output_config, IVAS_AUDIO_CONFIG_EXTERNAL ) ) { +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) ) + { + *renderer_type = RENDERER_OMASA_OBJECT_EXT; + move32(); + } + ELSE IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) + { + *renderer_type = RENDERER_OMASA_MIX_EXT; + move32(); + } + ELSE + { + *renderer_type = RENDERER_DISABLE; + move32(); + } +#else *renderer_type = RENDERER_DISABLE; move16(); +#endif } } ELSE IF( EQ_32( st_ivas->ivas_format, MC_FORMAT ) ) diff --git a/lib_dec/ivas_sba_dec_fx.c b/lib_dec/ivas_sba_dec_fx.c index 687991c8931e49533bf13399579596d9941e5bdc..1e58959d58beaa0bd0ecdf71ee104b67622f79f1 100644 --- a/lib_dec/ivas_sba_dec_fx.c +++ b/lib_dec/ivas_sba_dec_fx.c @@ -771,7 +771,12 @@ void ivas_sba_dec_digest_tc_fx( Word16 ch_idx, nchan_transport; /* set the md map */ +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); + IF( st_ivas->hDirAC != NULL || EQ_32( st_ivas->renderer_type, RENDERER_OMASA_OBJECT_EXT ) ) +#else IF( st_ivas->hDirAC ) +#endif { ivas_dirac_dec_set_md_map_fx( st_ivas, nCldfbSlots ); } diff --git a/lib_dec/ivas_stat_dec.h b/lib_dec/ivas_stat_dec.h index 4a8c3cbd99febd54e9600ffef4d26e883ad80426..5b8bd48ffed7b8b3757bfd7b2f4f2cf9b045cd18 100644 --- a/lib_dec/ivas_stat_dec.h +++ b/lib_dec/ivas_stat_dec.h @@ -926,6 +926,25 @@ typedef struct ivas_masa_decoder_struct } MASA_DECODER, *MASA_DECODER_HANDLE; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT +/* Data structure for MASA_ISM EXT rendering */ +typedef struct ivas_masa_ism_ext_data_structure +{ + Word16 prev_idx_separated_ism; // Q0 (Integer) + Word32 prev_panning_gains[MAX_NUM_OBJECTS][2]; // Q31 + Word16 ism_render_proto_energy_exp[MAX_NUM_OBJECTS][CLDFB_NO_CHANNELS_MAX]; // Q0 (Integer exponent) + Word32 ism_render_proto_energy_frac[MAX_NUM_OBJECTS][CLDFB_NO_CHANNELS_MAX]; // Q31 + Word16 ism_render_target_energy_exp[MAX_NUM_OBJECTS][CLDFB_NO_CHANNELS_MAX]; // Q0 (Integer exponent) + Word32 ism_render_target_energy_frac[MAX_NUM_OBJECTS][CLDFB_NO_CHANNELS_MAX]; // Q31 + Word16 masa_render_proto_energy_exp[CLDFB_NO_CHANNELS_MAX]; // Q0 (Integer exponent) + Word32 masa_render_proto_energy_frac[CLDFB_NO_CHANNELS_MAX]; // Q31 + Word16 masa_render_target_energy_exp[CLDFB_NO_CHANNELS_MAX]; // Q0 (Integer exponent) + Word32 masa_render_target_energy_frac[CLDFB_NO_CHANNELS_MAX]; // Q31 + Word32 masa_render_masa_to_total[MAX_PARAM_SPATIAL_SUBFRAMES + DELAY_MASA_PARAM_DEC_SFR][CLDFB_NO_CHANNELS_MAX]; // Q30 + +} MASA_ISM_EXT_DATA, *MASA_ISM_EXT_DATA_HANDLE; +#endif + /* Data structure for MASA_ISM rendering */ typedef struct ivas_masa_ism_data_structure { @@ -955,7 +974,9 @@ typedef struct ivas_masa_ism_data_structure Word32 **delayBuffer_fx; /* Q11 */ Word16 delayBuffer_size; Word16 delayBuffer_nchan; - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + MASA_ISM_EXT_DATA_HANDLE hExtData; +#endif } MASA_ISM_DATA, *MASA_ISM_DATA_HANDLE; diff --git a/lib_dec/lib_dec_fx.c b/lib_dec/lib_dec_fx.c index 7c881cce983bd84a83833722e87d9e5d4df5f9d3..98bbfd3d53091ffca8387c1b9c10efe06130ce8b 100644 --- a/lib_dec/lib_dec_fx.c +++ b/lib_dec/lib_dec_fx.c @@ -1987,14 +1987,37 @@ ivas_error IVAS_DEC_GetNumObjects( UWord16 *numObjects /* o : number of objects for which the decoder has been configured */ ) { +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + Word16 is_masa_ism; + is_masa_ism = 0; + move16(); +#endif test(); IF( hIvasDec == NULL || hIvasDec->st_ivas == NULL ) { return IVAS_ERR_UNEXPECTED_NULL_POINTER; } +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( hIvasDec->st_ivas->hMasa != NULL ) + { + IF( EQ_32( hIvasDec->st_ivas->hMasa->config.input_ivas_format, MASA_ISM_FORMAT ) ) + { + is_masa_ism = 1; + move16(); + } + } + test(); + test(); + test(); + IF( EQ_32( hIvasDec->st_ivas->ivas_format, ISM_FORMAT ) || + EQ_32( hIvasDec->st_ivas->ivas_format, SBA_ISM_FORMAT ) || + EQ_32( hIvasDec->st_ivas->ivas_format, MASA_ISM_FORMAT ) || + EQ_16( is_masa_ism, 1 ) ) +#else test(); test(); IF( EQ_16( (Word16) hIvasDec->st_ivas->ivas_format, ISM_FORMAT ) || EQ_16( (Word16) hIvasDec->st_ivas->ivas_format, SBA_ISM_FORMAT ) || EQ_16( (Word16) hIvasDec->st_ivas->ivas_format, MASA_ISM_FORMAT ) ) +#endif { *numObjects = hIvasDec->st_ivas->nchan_ism; } @@ -2029,7 +2052,14 @@ ivas_error IVAS_DEC_GetFormat( *format = IVAS_DEC_BS_UNKOWN; } move32(); - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); + if ( EQ_32( *format, IVAS_DEC_BS_MASA ) && EQ_32( hIvasDec->st_ivas->hMasa->config.input_ivas_format, MASA_ISM_FORMAT ) ) + { + *format = IVAS_DEC_BS_MASA_ISM; + move32(); + } +#endif return IVAS_ERR_OK; } @@ -2140,7 +2170,11 @@ ivas_error IVAS_DEC_GetObjectMetadata( { Decoder_Struct *st_ivas; ISM_METADATA_HANDLE hIsmMeta; - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + Word16 is_masa_ism; + is_masa_ism = 0; + move16(); +#endif test(); IF( hIvasDec == NULL || hIvasDec->st_ivas == NULL ) { @@ -2148,9 +2182,27 @@ ivas_error IVAS_DEC_GetObjectMetadata( } st_ivas = hIvasDec->st_ivas; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( hIvasDec->st_ivas->hMasa != NULL ) + { + IF( EQ_32( hIvasDec->st_ivas->hMasa->config.input_ivas_format, MASA_ISM_FORMAT ) ) + { + is_masa_ism = 1; + move16(); + } + } + test(); + test(); + test(); + if ( NE_32( st_ivas->ivas_format, ISM_FORMAT ) && + NE_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) && + NE_32( st_ivas->ivas_format, SBA_ISM_FORMAT ) && + EQ_16( is_masa_ism, 0 ) ) +#else test(); test(); IF( NE_16( st_ivas->ivas_format, ISM_FORMAT ) && NE_16( st_ivas->ivas_format, MASA_ISM_FORMAT ) && NE_16( st_ivas->ivas_format, SBA_ISM_FORMAT ) ) +#endif { return IVAS_ERR_WRONG_MODE; } @@ -2161,8 +2213,16 @@ ivas_error IVAS_DEC_GetObjectMetadata( } hIsmMeta = st_ivas->hIsmMetaData[objectIdx]; - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); + test(); + test(); + IF( hIsmMeta == NULL || + EQ_16( zero_flag, 1 ) || + ( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) && EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) ) ) +#else IF( hIsmMeta == NULL || zero_flag ) +#endif { metadata->azimuth_fx = 0; // Q22 metadata->elevation_fx = 0; // Q22 @@ -2834,9 +2894,13 @@ ivas_error IVAS_DEC_GetDelay( out_fs_fx = FS_48K_IN_NS_Q31; } move32(); - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + nSamples[1] = NS2SA_FX2( hDecoderConfig->output_Fs, get_delay_fx( DEC, hDecoderConfig->output_Fs, st_ivas->ivas_format, st_ivas->cldfbSynDec[0], hDecoderConfig->output_config ) ); + move16(); +#else nSamples[1] = NS2SA_FX2( hDecoderConfig->output_Fs, get_delay_fx( DEC, hDecoderConfig->output_Fs, st_ivas->ivas_format, st_ivas->cldfbAnaDec[0], hDecoderConfig->output_config ) ); move16(); +#endif nSamples[2] = extract_l( W_round64_L( W_mult0_32_32( L_shl( st_ivas->binaural_latency_ns, 1 ), out_fs_fx ) ) ); move16(); nSamples[0] = add( nSamples[1], nSamples[2] ); diff --git a/lib_enc/ivas_masa_enc_fx.c b/lib_enc/ivas_masa_enc_fx.c index 616c28ad8912b7c69d52a0b4420d1a34a362d84c..72cc9d78da5296ed31afb0a82f73d9da500f0a04 100644 --- a/lib_enc/ivas_masa_enc_fx.c +++ b/lib_enc/ivas_masa_enc_fx.c @@ -533,8 +533,28 @@ ivas_error ivas_masa_encode_fx( } ELSE { - /* write the number of MASA transport channels */ - push_next_indice( hMetaData, sub( nchan_transport, 1 ), MASA_TRANSP_BITS ); +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + test(); + IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MODE_NONE ) ) + { + /* use the MASA number of transport channels bit to signal if there are 3 or 4 objects */ + IF( EQ_16( nchan_ism, 4 ) ) + { + push_next_indice( hMetaData, 1, MASA_TRANSP_BITS ); + } + ELSE + { + push_next_indice( hMetaData, 0, MASA_TRANSP_BITS ); + } + } + ELSE + { +#endif + /* write the number of MASA transport channels */ + push_next_indice( hMetaData, sub( nchan_transport, 1 ), MASA_TRANSP_BITS ); +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + } +#endif hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_TRANSP_BITS ); move16(); } @@ -542,12 +562,25 @@ ivas_error ivas_masa_encode_fx( test(); IF( EQ_32( ivas_format, MASA_ISM_FORMAT ) && EQ_32( ism_mode, ISM_MODE_NONE ) ) { +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IF( LE_16( nchan_ism, 3 ) ) + { + push_next_indice( hMetaData, nchan_ism, MASA_HEADER_BITS ); + } + ELSE + { + push_next_indice( hMetaData, sub( nchan_ism, 1 ), MASA_HEADER_BITS ); + } + hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_HEADER_BITS ); + move16(); +#else /* signal MASA_ISM_FORMAT to decoder */ push_next_indice( hMetaData, 1, 1 ); /* write reserved bit */ push_next_indice( hMetaData, 0, MASA_HEADER_BITS - 1 ); hQMetaData->metadata_max_bits = sub( hQMetaData->metadata_max_bits, MASA_HEADER_BITS ); move16(); +#endif } ELSE { diff --git a/lib_rend/ivas_masa_merge_fx.c b/lib_rend/ivas_masa_merge_fx.c index 528ee4d769520842037cc74c1f4a2ee8edb497b0..432ed8253dfc04c8f6fe00202f0ce3edd02849ff 100644 --- a/lib_rend/ivas_masa_merge_fx.c +++ b/lib_rend/ivas_masa_merge_fx.c @@ -220,6 +220,7 @@ void diffuse_meta_merge_1x1_fx( { Word32 new_dir_ratio_fx, new_diff_ratio_fx; Word16 new_dir_ratio_e; + outMeta->directionIndex[0][sf][band] = inMetaISM->directionIndex[0][sf][band]; move16(); outMeta->directToTotalRatio[0][sf][band] = inMetaISM->directToTotalRatio[0][sf][band]; @@ -252,7 +253,8 @@ void diffuse_meta_merge_1x1_fx( move16(); } - outMeta->directToTotalRatio[0][sf][band] = (UWord8) extract_l( L_shr( Mpy_32_16_1( new_dir_ratio_fx, UINT8_MAX ) /* (31 - new_dir_ratio_e) - 15*/, sub( 31 - 15, new_dir_ratio_e ) ) ); + outMeta->directToTotalRatio[0][sf][band] = (UWord8) extract_l( L_shr( Mpy_32_16_1( new_dir_ratio_fx, UINT8_MAX ) /* (31 - new_dir_ratio_e) - 15*/, sub( 31 - 15, new_dir_ratio_e ) ) ); /* Q0 */ + move16(); IF( GT_16( sub( 31, new_dir_ratio_e ), Q30 ) ) { diff --git a/lib_util/masa_file_writer.c b/lib_util/masa_file_writer.c index 0939d0829ce7a4a2bc7a8b1718eea70694c37bf5..ab25963201ee24abbda50e57636bbd356d74fc93 100644 --- a/lib_util/masa_file_writer.c +++ b/lib_util/masa_file_writer.c @@ -41,11 +41,20 @@ typedef struct masaMetaDelayStorage { MASA_DECRIPTIVE_META descriptiveMeta; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + uint16_t directionIndex[MASA_MAXIMUM_DIRECTIONS][DELAY_MASA_PARAM_DEC_SFR + 1][MASA_FREQUENCY_BANDS]; + uint8_t directToTotalRatio[MASA_MAXIMUM_DIRECTIONS][DELAY_MASA_PARAM_DEC_SFR + 1][MASA_FREQUENCY_BANDS]; + uint8_t spreadCoherence[MASA_MAXIMUM_DIRECTIONS][DELAY_MASA_PARAM_DEC_SFR + 1][MASA_FREQUENCY_BANDS]; + uint8_t surroundCoherence[DELAY_MASA_PARAM_DEC_SFR + 1][MASA_FREQUENCY_BANDS]; + uint8_t diffuseToTotalRatio[DELAY_MASA_PARAM_DEC_SFR + 1][MASA_FREQUENCY_BANDS]; + uint8_t prevDelay; +#else uint16_t directionIndex[MASA_MAXIMUM_DIRECTIONS][DELAY_MASA_PARAM_DEC_SFR][MASA_FREQUENCY_BANDS]; uint8_t directToTotalRatio[MASA_MAXIMUM_DIRECTIONS][DELAY_MASA_PARAM_DEC_SFR][MASA_FREQUENCY_BANDS]; uint8_t spreadCoherence[MASA_MAXIMUM_DIRECTIONS][DELAY_MASA_PARAM_DEC_SFR][MASA_FREQUENCY_BANDS]; uint8_t surroundCoherence[DELAY_MASA_PARAM_DEC_SFR][MASA_FREQUENCY_BANDS]; uint8_t diffuseToTotalRatio[DELAY_MASA_PARAM_DEC_SFR][MASA_FREQUENCY_BANDS]; +#endif } MASA_META_DELAY_STORAGE; @@ -88,14 +97,93 @@ static void getExtMasaMetadataFileName( static void delayMasaMetadata( MASA_DECODER_EXT_OUT_META_HANDLE extOutMeta, /* i/o: New input metadata which is inplace replaced with delayed metadata frame */ - MASA_META_DELAY_STORAGE *delayStorage /* i/o: Storage for 10 ms of metadata and related descriptive metadata */ +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + MASA_META_DELAY_STORAGE *delayStorage, /* i/o: Storage for 15 ms of metadata and related descriptive metadata */ + uint8_t delayNsf +#else + MASA_META_DELAY_STORAGE *delayStorage /* i/o: Storage for 10 ms of metadata and related descriptive metadata */ +#endif ) { int16_t dir, sf, band; uint8_t currentNumberOfDirections; - +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + int16_t storeReadOffset; +#endif /* Move meta to delay and output. Always use two directions as the metadata is prepared to contain zero energy second direction * if there is 1dir meta. */ +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + /* stable state expected results delay change expected results + delayNsf = 2 delayNsf = 3 delayNsf = 3 (from 2) delayNsf = 2 (from 3) + ext[0] = delayStorage[0] (prev ext[2]) ext[0] = delayStorage[0] (prev ext[1]) ext[0] = delayStorage[0] (prev ext[2]) ext[0] = delayStorage[1] (prev ext[2]) + ext[1] = delayStorage[1] (prev ext[3]) ext[1] = delayStorage[1] (prev ext[2]) ext[1] = delayStorage[1] (prev ext[3]) ext[1] = delayStorage[2] (prev ext[3]) + ext[2] = ext[0] ext[2] = delayStorage[2] (prev ext[3]) ext[2] = delayStorage[1] (prev ext[3]) ext[2] = ext[0] + ext[3] = ext[1] ext[3] = ext[0] ext[3] = ext[0] ext[3] = ext[0] + delayStorage[0] = ext[2] delayStorage[0] = ext[1] delayStorage[0] = ext[1] delayStorage[0] = ext[2] + delayStorage[1] = ext[3] delayStorage[1] = ext[2] delayStorage[1] = ext[2] delayStorage[1] = ext[3] + delayStorage[2] = ext[3] delayStorage[2] = ext[3] + */ + storeReadOffset = delayStorage->prevDelay > delayNsf ? delayStorage->prevDelay - delayNsf : 0; /* delay decreases: read later from storage -> discard one sf */ + + for ( sf = 0; sf < delayNsf; sf++ ) + { + for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ ) + { + uint16_t temp_u16; + uint8_t temp_u8; + int16_t toStoreIdx, reOrgIdx, storeReadIdx; + + toStoreIdx = sf + MAX_PARAM_SPATIAL_SUBFRAMES - delayNsf; + reOrgIdx = sf + delayNsf; + /* when switching to longer delay, repeat the last valid sf to fill the gap */ + storeReadIdx = ( ( sf + storeReadOffset ) < delayStorage->prevDelay ) ? sf + storeReadOffset : delayStorage->prevDelay - 1; + + for ( dir = 0; dir < MASA_MAXIMUM_DIRECTIONS; dir++ ) + { + temp_u16 = delayStorage->directionIndex[dir][storeReadIdx][band]; + delayStorage->directionIndex[dir][sf][band] = extOutMeta->directionIndex[dir][toStoreIdx][band]; + if ( reOrgIdx < MAX_PARAM_SPATIAL_SUBFRAMES ) + { + extOutMeta->directionIndex[dir][reOrgIdx][band] = extOutMeta->directionIndex[dir][sf][band]; + } + extOutMeta->directionIndex[dir][sf][band] = temp_u16; + + temp_u8 = delayStorage->directToTotalRatio[dir][storeReadIdx][band]; + delayStorage->directToTotalRatio[dir][sf][band] = extOutMeta->directToTotalRatio[dir][toStoreIdx][band]; + if ( reOrgIdx < MAX_PARAM_SPATIAL_SUBFRAMES ) + { + extOutMeta->directToTotalRatio[dir][reOrgIdx][band] = extOutMeta->directToTotalRatio[dir][sf][band]; + } + extOutMeta->directToTotalRatio[dir][sf][band] = temp_u8; + + temp_u8 = delayStorage->spreadCoherence[dir][storeReadIdx][band]; + delayStorage->spreadCoherence[dir][sf][band] = extOutMeta->spreadCoherence[dir][toStoreIdx][band]; + if ( reOrgIdx < MAX_PARAM_SPATIAL_SUBFRAMES ) + { + extOutMeta->spreadCoherence[dir][reOrgIdx][band] = extOutMeta->spreadCoherence[dir][sf][band]; + } + extOutMeta->spreadCoherence[dir][sf][band] = temp_u8; + } + + temp_u8 = delayStorage->surroundCoherence[storeReadIdx][band]; + delayStorage->surroundCoherence[sf][band] = extOutMeta->surroundCoherence[toStoreIdx][band]; + if ( reOrgIdx < MAX_PARAM_SPATIAL_SUBFRAMES ) + { + extOutMeta->surroundCoherence[reOrgIdx][band] = extOutMeta->surroundCoherence[sf][band]; + } + extOutMeta->surroundCoherence[sf][band] = temp_u8; + + temp_u8 = delayStorage->diffuseToTotalRatio[storeReadIdx][band]; + delayStorage->diffuseToTotalRatio[sf][band] = extOutMeta->diffuseToTotalRatio[toStoreIdx][band]; + if ( reOrgIdx < MAX_PARAM_SPATIAL_SUBFRAMES ) + { + extOutMeta->diffuseToTotalRatio[reOrgIdx][band] = extOutMeta->diffuseToTotalRatio[sf][band]; + } + extOutMeta->diffuseToTotalRatio[sf][band] = temp_u8; + } + } + +#else for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES - DELAY_MASA_PARAM_DEC_SFR; sf++ ) { for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ ) @@ -131,6 +219,7 @@ static void delayMasaMetadata( extOutMeta->diffuseToTotalRatio[sf][band] = temp_u8; } } +#endif /* Finalize descriptive meta by using new frame except for number of directions which is the larger of the two */ currentNumberOfDirections = extOutMeta->descriptiveMeta.numberOfDirections; @@ -140,6 +229,9 @@ static void delayMasaMetadata( } delayStorage->descriptiveMeta.numberOfDirections = currentNumberOfDirections; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + delayStorage->prevDelay = delayNsf; +#endif return; } @@ -182,6 +274,9 @@ ivas_error MasaFileWriter_open( if ( !delayCompensationEnabled ) { self->delayStorage = calloc( sizeof( MASA_META_DELAY_STORAGE ), 1 ); +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + self->delayStorage->prevDelay = DELAY_MASA_PARAM_DEC_SFR; +#endif } *masaWriter = self; @@ -197,8 +292,13 @@ ivas_error MasaFileWriter_open( *---------------------------------------------------------------------*/ ivas_error MasaFileWriter_writeFrame( - MasaFileWriter *self, /* i/o: MasaFileWriter handle */ + MasaFileWriter *self, /* i/o: MasaFileWriter handle */ +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta, /* i/o: MASA ext out meta handle to be written */ + const float *decDelay /* i : decoding audio delay */ +#else MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta /* i/o: MASA ext out meta handle to be written */ +#endif ) { if ( self == NULL ) @@ -209,7 +309,17 @@ ivas_error MasaFileWriter_writeFrame( uint16_t descMetaTemp = 0; int16_t i, sf, dir, numDirections; uint8_t writeTempOther[MASA_FREQUENCY_BANDS]; +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + /* If delay storage has been reserved, then we are in the normal mode for the decoder + * (i.e., no delay compensation for PCM) which means that metadata should be delayed + * by two or three subframes (10 or 15 ms). Descriptive metadata is a combined result. */ + if ( self->delayStorage ) + { + uint8_t delayFrames = (uint8_t) ( (int32_t) ( ( *decDelay ) * 48000 ) / L_SPATIAL_SUBFR_48k ); + delayMasaMetadata( hMasaExtOutMeta, self->delayStorage, delayFrames ); + } +#else /* If delay storage has been reserved, then we are in the normal mode for the decoder * (i.e., no delay compensation for PCM) which means that metadata should be delayed * by two subframes (10 ms). Descriptive metadata is a combined result. */ @@ -217,7 +327,7 @@ ivas_error MasaFileWriter_writeFrame( { delayMasaMetadata( hMasaExtOutMeta, self->delayStorage ); } - +#endif numDirections = hMasaExtOutMeta->descriptiveMeta.numberOfDirections + 1; if ( fwrite( &( hMasaExtOutMeta->descriptiveMeta.formatDescriptor ), sizeof( uint8_t ), 8, self->file ) != 8 ) diff --git a/lib_util/masa_file_writer.h b/lib_util/masa_file_writer.h index 2d476e28f037e45af8a957b77015c1582bff2ef0..c3e142254b9e6e365e3f95e9d9bcb97af66cd547 100644 --- a/lib_util/masa_file_writer.h +++ b/lib_util/masa_file_writer.h @@ -47,8 +47,13 @@ ivas_error MasaFileWriter_open( ); ivas_error MasaFileWriter_writeFrame( - MasaFileWriter *self, /* i/o: MasaFileWriter handle */ + MasaFileWriter *self, /* i/o: MasaFileWriter handle */ +#ifdef NONBE_FIX_984_OMASA_EXT_OUTPUT + IVAS_MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta, /* i/o: MASA ext out meta handle to be written */ + const float *decDelay /* i : decoding audio delay */ +#else IVAS_MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta /* i/o: MASA ext out meta handle to be written */ +#endif ); void MasaFileWriter_close(