Loading apps/renderer.c +3 −0 Original line number Diff line number Diff line Loading @@ -1559,6 +1559,9 @@ int main( free( inFloatBuffer ); free( outInt16Buffer ); free( outFloatBuffer ); #ifdef IVAS_FLOAT_FIXED free( outInt32Buffer ); #endif for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i ) { MasaFileReader_close( &masaReaders[i] ); Loading lib_rend/ivas_limiter.c +333 −2 Original line number Diff line number Diff line Loading @@ -37,7 +37,12 @@ #include "ivas_prot_rend.h" #include "wmc_auto.h" #include <assert.h> #ifdef IVAS_FLOAT_FIXED #define ATTACK_CNST_48k (2106670080) //Q31 #define ATTACK_CNST_32k ( 2086555136 ) // Q31 #define ATTACK_CNST_16k ( 2027355264 ) // Q31 #define ATTACK_CNST_8k ( 1913946752 ) // Q31 #endif /*-------------------------------------------------------------------* * detect_strong_saturations() Loading Loading @@ -93,7 +98,65 @@ static int16_t detect_strong_saturations( return apply_strong_limiting; } #ifdef IVAS_FLOAT_FIXED /*-------------------------------------------------------------------* * detect_strong_saturations() * * Detection of very strong saturations, * usually happens as a consequence of a heavy corrupted bitstream *-------------------------------------------------------------------*/ /*! r: apply_strong_limiting flag */ static Word16 detect_strong_saturations_fx( const Word16 BER_detect, /* i : BER detect flag */ Word16 *strong_saturation_cnt, /* i/o: counter of strong saturations */ const Word32 max_val, /* i : maximum absolute value */ Word16 *frame_gain, /* i/o: frame gain value */ Word16 q_factor /*Q factor of the output samples*/ ) { Word16 apply_strong_limiting; Word32 compare_max_value_Mul_3, compare_max_value_Mul_10; apply_strong_limiting = 0; compare_max_value_Mul_3 = L_lshl(98187,q_factor); // 3 * IVAS_LIMITER_THRESHOLD compare_max_value_Mul_10 = L_lshl( 327290, q_factor );//10 * IVAS_LIMITER_THRESHOLD IF ( BER_detect ) { *strong_saturation_cnt = 50; apply_strong_limiting = 1; } ELSE IF( GT_32( max_val , compare_max_value_Mul_3) && GT_16(*strong_saturation_cnt , 0 )) { apply_strong_limiting = 1; } ELSE IF( GT_32 (max_val , compare_max_value_Mul_10) ) { *strong_saturation_cnt += 20; *strong_saturation_cnt = min( *strong_saturation_cnt, 50 ); apply_strong_limiting = 1; } else { ( *strong_saturation_cnt )--; *strong_saturation_cnt = max( *strong_saturation_cnt, 0 ); } if ( apply_strong_limiting ) { IF( LT_16 (* frame_gain , 4915) ) // Q14 of 0.3 is compared { //*frame_gain /= 3.0f; *frame_gain = lshr(divide1616( *frame_gain, 24576 ) , 2);//Q14 } ELSE { apply_strong_limiting = 0; } } return apply_strong_limiting; } /*-------------------------------------------------------------------* * ivas_limiter_open() * Loading @@ -109,7 +172,7 @@ ivas_error ivas_limiter_open( { int16_t i; IVAS_LIMITER_HANDLE hLimiter; Word32 attack_cnst_fx = 0; if ( max_num_channels <= 0 || sampling_rate <= 0 ) { return ( IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Wrong parameters for Limiter\n" ) ); Loading @@ -127,22 +190,96 @@ ivas_error ivas_limiter_open( { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) ); } if ( ( hLimiter->channel_ptrs_fx = malloc( max_num_channels * sizeof( Word32 * ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) ); } hLimiter->sampling_rate = sampling_rate; hLimiter->gain = 1.f; hLimiter->gain_fx = ONE_IN_Q14; hLimiter->release_heuristic = 0.f; hLimiter->release_heuristic_fx = 0; hLimiter->attack_constant = powf( 0.01f, 1.0f / ( IVAS_LIMITER_ATTACK_SECONDS * sampling_rate ) ); SWITCH( sampling_rate ) { case 48000: attack_cnst_fx = ATTACK_CNST_48k; BREAK; case 32000: attack_cnst_fx = ATTACK_CNST_32k; BREAK; case 16000: attack_cnst_fx = ATTACK_CNST_16k; BREAK; case 8000: attack_cnst_fx = ATTACK_CNST_8k; BREAK; } hLimiter->attack_constant_fx = attack_cnst_fx; hLimiter->strong_saturation_count = 0; for ( i = 0; i < max_num_channels; ++i ) { hLimiter->channel_ptrs[i] = NULL; hLimiter->channel_ptrs_fx[i] = NULL; } *hLimiter_out = hLimiter; return IVAS_ERR_OK; } #else /*-------------------------------------------------------------------* * ivas_limiter_open() * * Allocate and initialize limiter struct *-------------------------------------------------------------------*/ /*! r : limiter struct handle */ ivas_error ivas_limiter_open( IVAS_LIMITER_HANDLE *hLimiter_out, /* o : limiter struct handle */ const int16_t max_num_channels, /* i : maximum number of I/O channels to be processed */ const int32_t sampling_rate /* i : sampling rate for processing */ ) { int16_t i; IVAS_LIMITER_HANDLE hLimiter; if ( max_num_channels <= 0 || sampling_rate <= 0 ) { return ( IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Wrong parameters for Limiter\n" ) ); } if ( ( hLimiter = malloc( sizeof( IVAS_LIMITER ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) ); } hLimiter->max_num_channels = max_num_channels; hLimiter->num_channels = max_num_channels; if ( ( hLimiter->channel_ptrs = malloc( max_num_channels * sizeof( float * ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) ); } hLimiter->sampling_rate = sampling_rate; hLimiter->gain = 1.f; hLimiter->release_heuristic = 0.f; hLimiter->attack_constant = powf( 0.01f, 1.0f / ( IVAS_LIMITER_ATTACK_SECONDS * sampling_rate ) ); hLimiter->strong_saturation_count = 0; for ( i = 0; i < max_num_channels; ++i ) { hLimiter->channel_ptrs[i] = NULL; } *hLimiter_out = hLimiter; return IVAS_ERR_OK; } #endif /*-------------------------------------------------------------------* * ivas_limiter_close() Loading Loading @@ -206,7 +343,201 @@ void ivas_limiter_dec( return; } #ifdef IVAS_FLOAT_FIXED /*-------------------------------------------------------------------* * limiter_process() * * hLimiter->channel_ptrs must be set before calling this function. * Consider using a wrapper function like ivas_limiter_dec() instead * of calling this directly. *-------------------------------------------------------------------*/ void limiter_process_fx( IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */ const Word16 output_frame, /* i : number of samples to be processed per channel in the I/O buffer */ const Word32 threshold, /* i : signal amplitude above which limiting starts to be applied */ const Word16 BER_detect, /* i : BER detect flag */ Word16 *strong_saturation_cnt, /* i/o: counter of strong saturations (can be NULL) */ Word16 q_factor /*Q factor of output samples*/ ) { Word16 i, c; Word32 tmp, max_val; Word32 *sample; Word32 attack_constant; Word32 releaseHeuristic; Word16 apply_limiting, apply_strong_limiting; Word32 **output; Word16 num_channels, q_fact_gain, div32, release_constant, compare_value; Word32 sampling_rate; Word16 gain, frame_gain, fact, fact_2, exp_pow, exp_pow_2, result; Word32 mul; Word32 mul_2; /* return early if given nonsensical values */ IF ( hLimiter == NULL || output_frame <= 0 ) { return; } apply_limiting = 1; apply_strong_limiting = 0; gain = hLimiter->gain_fx; output = hLimiter->channel_ptrs_fx; num_channels = hLimiter->num_channels; sampling_rate = hLimiter->sampling_rate; attack_constant = hLimiter->attack_constant_fx; /*-----------------------------------------------------------------* * Find highest absolute peak sample value *-----------------------------------------------------------------*/ max_val = 0; FOR ( i = 0; i < output_frame; i++ ) { FOR( c = 0; c < num_channels; c++ ) { tmp = L_abs( output[c][i] ); IF ( GT_32(tmp , max_val) ) { max_val = tmp; } } } /* Release heuristic * * Value ranging from 0.f to 1.f. Increases on each frame that contains * a sample with a value above threshold and decreases on each frame * with all sample values below threshold. * * Values of 0 and 1 map to the shortest and longest release time, respectively. * * The goal of this heuristic is to avoid the "pumping" effect when only * sharp transients exceed the threshold (use short release time), but also * keep the gain curve smoother if the threshold is exceeded in many frames * in a short span of time. */ Word16 sample_num = 0; SWITCH (sampling_rate) { case 48000: sample_num = L_SUBFRAME_48k; BREAK; case 32000: sample_num = L_SUBFRAME_32k; BREAK; case 16000: sample_num = L_SUBFRAME_16k; BREAK; case 8000: sample_num = L_SUBFRAME_8k; BREAK; } releaseHeuristic = hLimiter->release_heuristic_fx; q_fact_gain = Q14; if ( max_val > threshold ) { frame_gain = shr(divide3232( threshold, max_val ),1);//to q14 releaseHeuristic = min( ONE_IN_Q30, L_add( releaseHeuristic, 21474836 ) ); // release_constant = powf( 0.01f, 1.0f / ( 0.005f * powf( 200.f, .02 ) * sampling_rate ) ); /* Unoptimized code for reference */ /* releaseHeuristic = min( 1.f, releaseHeuristic + ( (float) 2.f * output_frame / sampling_rate / adaptiveReleaseWindowLengthInSeconds ) ); * ^ * React faster when release time should be increased */ } else { releaseHeuristic = max( 0, L_sub( releaseHeuristic, 53687091 ) ); /* Unoptimized code for reference */ /*releaseHeuristic = max( 0.f, releaseHeuristic - ( (float) 0.5f * output_frame / sampling_rate / adaptiveReleaseWindowLengthInSeconds ) ); * ^ * React slower when release time should be decreased */ /* No samples above threshold and gain from previous frame is already 1.f, * therefore gain == 1.f for the entire frame. Skip processing. */ if ( gain >= ( lshl( 1, q_fact_gain ) )) { apply_limiting = 0; } /* No samples above threshold but gain from previous frame is not 1.f, * transition to gain == 1.f */ frame_gain = lshl( 1, q_fact_gain ); } /* Detection of very strong saturations */ if ( strong_saturation_cnt != NULL ) { apply_strong_limiting = detect_strong_saturations_fx( BER_detect, strong_saturation_cnt, max_val, &frame_gain, q_factor ); } compare_value = 3277;//Q14 of 0.1f /* Limit gain reduction to 20dB. Any peaks that require gain reduction * higher than this are most likely due to bit errors during decoding */ if ( frame_gain < compare_value && !apply_strong_limiting ) { frame_gain = compare_value; } if ( apply_limiting ) { /* 99% time constants of the gain curve * * The denominator of the second argument determines after how many * samples the gain curve will reach 99% of its target value */ mul = Mpy_32_32( 1025941011, releaseHeuristic ) >> 10; // Q16 /*For powf(200.0f,x)*/ fact = L_Extract_lc( mul, &exp_pow ); result = extract_l( Pow2( 14, fact ) ); div32 = divide3232( L_lshl( 1, ( 14 - exp_pow + 1 ) ), L_mult( result, sample_num ) ); /*For powf(0.01f,x)*/ mul_2 = L_mult( -13607, div32 ) >> 10; // Q16 fact_2 = L_Extract_lc( mul_2, &exp_pow_2 ); release_constant = extract_l( Pow2( 2, fact_2 ) ); //-(Q2+exp_pow_2) /* Unoptimized code for reference */ /* releaseTimeInSeconds = 0.005f * powf(200.f, releaseHeuristic); <-- Map heuristic value (0; 1) exponentially to range (0.005; 1) * release_constant = powf( 0.01f, 1.0f / ( releaseTimeInSeconds * sampling_rate ) ); */ /*-----------------------------------------------------------------* * Apply limiting *-----------------------------------------------------------------*/ for ( i = 0; i < output_frame; i++ ) { /* Update gain */ if ( frame_gain < gain ) { gain = add(extract_h(Mpy_32_16_r(attack_constant ,( sub(gain , frame_gain) ))) , frame_gain);//q14 } else { gain = add(extract_l(L_lshr( L_mult( release_constant , sub( gain, frame_gain ) ), ( Q2 - exp_pow_2 ) )) , frame_gain);//q14 } for ( c = 0; c < num_channels; c++ ) { sample = &output[c][i]; /* Apply gain */ *sample = Mpy_32_16_r(L_lshl( *sample,1 ),gain ) ;//q_factor } } } /* Save last gain and release heuristic values for next frame */ hLimiter->gain_fx = gain; hLimiter->release_heuristic_fx = releaseHeuristic; return; } #endif /*-------------------------------------------------------------------* * limiter_process() * Loading lib_rend/ivas_prot_rend.h +17 −3 Original line number Diff line number Diff line Loading @@ -127,7 +127,16 @@ void limiter_process( const int16_t BER_detect, /* i : BER detect flag */ int16_t *strong_saturation_cnt /* i/o: counter of strong saturations (can be NULL) */ ); #ifdef IVAS_FLOAT_FIXED void limiter_process_fx( IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */ const Word16 output_frame, /* i : number of samples to be processed per channel in the I/O buffer */ const Word32 threshold, /* i : signal amplitude above which limiting starts to be applied */ const Word16 BER_detect, /* i : BER detect flag */ Word16 *strong_saturation_cnt, /* i/o: counter of strong saturations (can be NULL) */ Word16 q_factor ); #endif /*----------------------------------------------------------------------------------* * TD decorr. function prototypes *----------------------------------------------------------------------------------*/ Loading Loading @@ -1496,12 +1505,17 @@ void ivas_combined_orientation_update_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ const int16_t samples_rendered /* i : samples rendered since the last call */ ); #ifdef IVAS_FLOAT_FIXED void ivas_combined_orientation_update_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ const Word16 samples_rendered /* i : samples rendered since the last call */ ); #else void ivas_combined_orientation_update_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ const int16_t samples_rendered /* i : samples rendered since the last call */ ); #endif void ivas_combined_orientation_set_to_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ ); Loading lib_rend/ivas_reflections.c +4 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,10 @@ ivas_error ivas_er_compute_reflections( /* If size is different, reallocate circ buffers */ /* Otherwise allocate new circ buffers */ #ifdef IVAS_FLOAT_FIXED for ( i = 0; i < 150; i++ ) { reflections->shoebox_data.gains.data_fx[i] = (Word32) float_to_fix( reflections->shoebox_data.gains.data[i], 15 ); } if ( reflections->circ_buffers ) { if ( reflections->circ_len == circ_len ) Loading lib_rend/ivas_rotation.c +65 −1 Original line number Diff line number Diff line Loading @@ -1761,7 +1761,18 @@ ivas_error combine_external_and_head_orientations( hCombinedOrientationData->cur_subframe_samples_rendered = 0; hCombinedOrientationData->subframe_idx_start = 0; hCombinedOrientationData->cur_subframe_samples_rendered_start = 0; #ifdef IVAS_FLOAT_FIXED for ( Word16 k = 0; k < 4; k++ ) { for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 3; j++ ) { hCombinedOrientationData->Rmat_fx[k][i][j] = (Word32) float_to_fix( hCombinedOrientationData->Rmat[k][i][j], 30 ); } } } #endif return IVAS_ERR_OK; } Loading Loading @@ -2384,7 +2395,29 @@ void ivas_combined_orientation_update_index( return; } #ifdef IVAS_FLOAT_FIXED /*------------------------------------------------------------------------- * ivas_combined_orientation_update_index() * * update read index based on the number of rendered samples *------------------------------------------------------------------------*/ void ivas_combined_orientation_set_to_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ ) { IF ( hCombinedOrientationData != NULL ) { hCombinedOrientationData->subframe_idx = hCombinedOrientationData->subframe_idx_start; move16(); hCombinedOrientationData->cur_subframe_samples_rendered = hCombinedOrientationData->cur_subframe_samples_rendered_start; move16(); } return; } #else /*------------------------------------------------------------------------- * ivas_combined_orientation_update_index() Loading @@ -2404,8 +2437,38 @@ void ivas_combined_orientation_set_to_start_index( return; } #endif #ifdef IVAS_FLOAT_FIXED /*------------------------------------------------------------------------- * ivas_combined_orientation_update_start_index() * * update start index based on the number of rendered samples *------------------------------------------------------------------------*/ void ivas_combined_orientation_update_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ const Word16 samples_rendered /* i : samples rendered since the last call */ ) { IF ( hCombinedOrientationData != NULL ) { IF ( hCombinedOrientationData->num_subframes == 1 ) { /* only one orientation available anyway or split rendering with low resolution*/ hCombinedOrientationData->subframe_idx = 0; } ELSE { hCombinedOrientationData->cur_subframe_samples_rendered_start += samples_rendered; hCombinedOrientationData->subframe_idx_start += hCombinedOrientationData->cur_subframe_samples_rendered / hCombinedOrientationData->subframe_size; hCombinedOrientationData->cur_subframe_samples_rendered_start = hCombinedOrientationData->cur_subframe_samples_rendered % hCombinedOrientationData->subframe_size; hCombinedOrientationData->subframe_idx_start = min( hCombinedOrientationData->subframe_idx, hCombinedOrientationData->num_subframes - 1 ); } } return; } #else /*------------------------------------------------------------------------- * ivas_combined_orientation_update_start_index() * Loading Loading @@ -2435,3 +2498,4 @@ void ivas_combined_orientation_update_start_index( return; } #endif No newline at end of file Loading
apps/renderer.c +3 −0 Original line number Diff line number Diff line Loading @@ -1559,6 +1559,9 @@ int main( free( inFloatBuffer ); free( outInt16Buffer ); free( outFloatBuffer ); #ifdef IVAS_FLOAT_FIXED free( outInt32Buffer ); #endif for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i ) { MasaFileReader_close( &masaReaders[i] ); Loading
lib_rend/ivas_limiter.c +333 −2 Original line number Diff line number Diff line Loading @@ -37,7 +37,12 @@ #include "ivas_prot_rend.h" #include "wmc_auto.h" #include <assert.h> #ifdef IVAS_FLOAT_FIXED #define ATTACK_CNST_48k (2106670080) //Q31 #define ATTACK_CNST_32k ( 2086555136 ) // Q31 #define ATTACK_CNST_16k ( 2027355264 ) // Q31 #define ATTACK_CNST_8k ( 1913946752 ) // Q31 #endif /*-------------------------------------------------------------------* * detect_strong_saturations() Loading Loading @@ -93,7 +98,65 @@ static int16_t detect_strong_saturations( return apply_strong_limiting; } #ifdef IVAS_FLOAT_FIXED /*-------------------------------------------------------------------* * detect_strong_saturations() * * Detection of very strong saturations, * usually happens as a consequence of a heavy corrupted bitstream *-------------------------------------------------------------------*/ /*! r: apply_strong_limiting flag */ static Word16 detect_strong_saturations_fx( const Word16 BER_detect, /* i : BER detect flag */ Word16 *strong_saturation_cnt, /* i/o: counter of strong saturations */ const Word32 max_val, /* i : maximum absolute value */ Word16 *frame_gain, /* i/o: frame gain value */ Word16 q_factor /*Q factor of the output samples*/ ) { Word16 apply_strong_limiting; Word32 compare_max_value_Mul_3, compare_max_value_Mul_10; apply_strong_limiting = 0; compare_max_value_Mul_3 = L_lshl(98187,q_factor); // 3 * IVAS_LIMITER_THRESHOLD compare_max_value_Mul_10 = L_lshl( 327290, q_factor );//10 * IVAS_LIMITER_THRESHOLD IF ( BER_detect ) { *strong_saturation_cnt = 50; apply_strong_limiting = 1; } ELSE IF( GT_32( max_val , compare_max_value_Mul_3) && GT_16(*strong_saturation_cnt , 0 )) { apply_strong_limiting = 1; } ELSE IF( GT_32 (max_val , compare_max_value_Mul_10) ) { *strong_saturation_cnt += 20; *strong_saturation_cnt = min( *strong_saturation_cnt, 50 ); apply_strong_limiting = 1; } else { ( *strong_saturation_cnt )--; *strong_saturation_cnt = max( *strong_saturation_cnt, 0 ); } if ( apply_strong_limiting ) { IF( LT_16 (* frame_gain , 4915) ) // Q14 of 0.3 is compared { //*frame_gain /= 3.0f; *frame_gain = lshr(divide1616( *frame_gain, 24576 ) , 2);//Q14 } ELSE { apply_strong_limiting = 0; } } return apply_strong_limiting; } /*-------------------------------------------------------------------* * ivas_limiter_open() * Loading @@ -109,7 +172,7 @@ ivas_error ivas_limiter_open( { int16_t i; IVAS_LIMITER_HANDLE hLimiter; Word32 attack_cnst_fx = 0; if ( max_num_channels <= 0 || sampling_rate <= 0 ) { return ( IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Wrong parameters for Limiter\n" ) ); Loading @@ -127,22 +190,96 @@ ivas_error ivas_limiter_open( { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) ); } if ( ( hLimiter->channel_ptrs_fx = malloc( max_num_channels * sizeof( Word32 * ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) ); } hLimiter->sampling_rate = sampling_rate; hLimiter->gain = 1.f; hLimiter->gain_fx = ONE_IN_Q14; hLimiter->release_heuristic = 0.f; hLimiter->release_heuristic_fx = 0; hLimiter->attack_constant = powf( 0.01f, 1.0f / ( IVAS_LIMITER_ATTACK_SECONDS * sampling_rate ) ); SWITCH( sampling_rate ) { case 48000: attack_cnst_fx = ATTACK_CNST_48k; BREAK; case 32000: attack_cnst_fx = ATTACK_CNST_32k; BREAK; case 16000: attack_cnst_fx = ATTACK_CNST_16k; BREAK; case 8000: attack_cnst_fx = ATTACK_CNST_8k; BREAK; } hLimiter->attack_constant_fx = attack_cnst_fx; hLimiter->strong_saturation_count = 0; for ( i = 0; i < max_num_channels; ++i ) { hLimiter->channel_ptrs[i] = NULL; hLimiter->channel_ptrs_fx[i] = NULL; } *hLimiter_out = hLimiter; return IVAS_ERR_OK; } #else /*-------------------------------------------------------------------* * ivas_limiter_open() * * Allocate and initialize limiter struct *-------------------------------------------------------------------*/ /*! r : limiter struct handle */ ivas_error ivas_limiter_open( IVAS_LIMITER_HANDLE *hLimiter_out, /* o : limiter struct handle */ const int16_t max_num_channels, /* i : maximum number of I/O channels to be processed */ const int32_t sampling_rate /* i : sampling rate for processing */ ) { int16_t i; IVAS_LIMITER_HANDLE hLimiter; if ( max_num_channels <= 0 || sampling_rate <= 0 ) { return ( IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Wrong parameters for Limiter\n" ) ); } if ( ( hLimiter = malloc( sizeof( IVAS_LIMITER ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) ); } hLimiter->max_num_channels = max_num_channels; hLimiter->num_channels = max_num_channels; if ( ( hLimiter->channel_ptrs = malloc( max_num_channels * sizeof( float * ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Limiter handle\n" ) ); } hLimiter->sampling_rate = sampling_rate; hLimiter->gain = 1.f; hLimiter->release_heuristic = 0.f; hLimiter->attack_constant = powf( 0.01f, 1.0f / ( IVAS_LIMITER_ATTACK_SECONDS * sampling_rate ) ); hLimiter->strong_saturation_count = 0; for ( i = 0; i < max_num_channels; ++i ) { hLimiter->channel_ptrs[i] = NULL; } *hLimiter_out = hLimiter; return IVAS_ERR_OK; } #endif /*-------------------------------------------------------------------* * ivas_limiter_close() Loading Loading @@ -206,7 +343,201 @@ void ivas_limiter_dec( return; } #ifdef IVAS_FLOAT_FIXED /*-------------------------------------------------------------------* * limiter_process() * * hLimiter->channel_ptrs must be set before calling this function. * Consider using a wrapper function like ivas_limiter_dec() instead * of calling this directly. *-------------------------------------------------------------------*/ void limiter_process_fx( IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */ const Word16 output_frame, /* i : number of samples to be processed per channel in the I/O buffer */ const Word32 threshold, /* i : signal amplitude above which limiting starts to be applied */ const Word16 BER_detect, /* i : BER detect flag */ Word16 *strong_saturation_cnt, /* i/o: counter of strong saturations (can be NULL) */ Word16 q_factor /*Q factor of output samples*/ ) { Word16 i, c; Word32 tmp, max_val; Word32 *sample; Word32 attack_constant; Word32 releaseHeuristic; Word16 apply_limiting, apply_strong_limiting; Word32 **output; Word16 num_channels, q_fact_gain, div32, release_constant, compare_value; Word32 sampling_rate; Word16 gain, frame_gain, fact, fact_2, exp_pow, exp_pow_2, result; Word32 mul; Word32 mul_2; /* return early if given nonsensical values */ IF ( hLimiter == NULL || output_frame <= 0 ) { return; } apply_limiting = 1; apply_strong_limiting = 0; gain = hLimiter->gain_fx; output = hLimiter->channel_ptrs_fx; num_channels = hLimiter->num_channels; sampling_rate = hLimiter->sampling_rate; attack_constant = hLimiter->attack_constant_fx; /*-----------------------------------------------------------------* * Find highest absolute peak sample value *-----------------------------------------------------------------*/ max_val = 0; FOR ( i = 0; i < output_frame; i++ ) { FOR( c = 0; c < num_channels; c++ ) { tmp = L_abs( output[c][i] ); IF ( GT_32(tmp , max_val) ) { max_val = tmp; } } } /* Release heuristic * * Value ranging from 0.f to 1.f. Increases on each frame that contains * a sample with a value above threshold and decreases on each frame * with all sample values below threshold. * * Values of 0 and 1 map to the shortest and longest release time, respectively. * * The goal of this heuristic is to avoid the "pumping" effect when only * sharp transients exceed the threshold (use short release time), but also * keep the gain curve smoother if the threshold is exceeded in many frames * in a short span of time. */ Word16 sample_num = 0; SWITCH (sampling_rate) { case 48000: sample_num = L_SUBFRAME_48k; BREAK; case 32000: sample_num = L_SUBFRAME_32k; BREAK; case 16000: sample_num = L_SUBFRAME_16k; BREAK; case 8000: sample_num = L_SUBFRAME_8k; BREAK; } releaseHeuristic = hLimiter->release_heuristic_fx; q_fact_gain = Q14; if ( max_val > threshold ) { frame_gain = shr(divide3232( threshold, max_val ),1);//to q14 releaseHeuristic = min( ONE_IN_Q30, L_add( releaseHeuristic, 21474836 ) ); // release_constant = powf( 0.01f, 1.0f / ( 0.005f * powf( 200.f, .02 ) * sampling_rate ) ); /* Unoptimized code for reference */ /* releaseHeuristic = min( 1.f, releaseHeuristic + ( (float) 2.f * output_frame / sampling_rate / adaptiveReleaseWindowLengthInSeconds ) ); * ^ * React faster when release time should be increased */ } else { releaseHeuristic = max( 0, L_sub( releaseHeuristic, 53687091 ) ); /* Unoptimized code for reference */ /*releaseHeuristic = max( 0.f, releaseHeuristic - ( (float) 0.5f * output_frame / sampling_rate / adaptiveReleaseWindowLengthInSeconds ) ); * ^ * React slower when release time should be decreased */ /* No samples above threshold and gain from previous frame is already 1.f, * therefore gain == 1.f for the entire frame. Skip processing. */ if ( gain >= ( lshl( 1, q_fact_gain ) )) { apply_limiting = 0; } /* No samples above threshold but gain from previous frame is not 1.f, * transition to gain == 1.f */ frame_gain = lshl( 1, q_fact_gain ); } /* Detection of very strong saturations */ if ( strong_saturation_cnt != NULL ) { apply_strong_limiting = detect_strong_saturations_fx( BER_detect, strong_saturation_cnt, max_val, &frame_gain, q_factor ); } compare_value = 3277;//Q14 of 0.1f /* Limit gain reduction to 20dB. Any peaks that require gain reduction * higher than this are most likely due to bit errors during decoding */ if ( frame_gain < compare_value && !apply_strong_limiting ) { frame_gain = compare_value; } if ( apply_limiting ) { /* 99% time constants of the gain curve * * The denominator of the second argument determines after how many * samples the gain curve will reach 99% of its target value */ mul = Mpy_32_32( 1025941011, releaseHeuristic ) >> 10; // Q16 /*For powf(200.0f,x)*/ fact = L_Extract_lc( mul, &exp_pow ); result = extract_l( Pow2( 14, fact ) ); div32 = divide3232( L_lshl( 1, ( 14 - exp_pow + 1 ) ), L_mult( result, sample_num ) ); /*For powf(0.01f,x)*/ mul_2 = L_mult( -13607, div32 ) >> 10; // Q16 fact_2 = L_Extract_lc( mul_2, &exp_pow_2 ); release_constant = extract_l( Pow2( 2, fact_2 ) ); //-(Q2+exp_pow_2) /* Unoptimized code for reference */ /* releaseTimeInSeconds = 0.005f * powf(200.f, releaseHeuristic); <-- Map heuristic value (0; 1) exponentially to range (0.005; 1) * release_constant = powf( 0.01f, 1.0f / ( releaseTimeInSeconds * sampling_rate ) ); */ /*-----------------------------------------------------------------* * Apply limiting *-----------------------------------------------------------------*/ for ( i = 0; i < output_frame; i++ ) { /* Update gain */ if ( frame_gain < gain ) { gain = add(extract_h(Mpy_32_16_r(attack_constant ,( sub(gain , frame_gain) ))) , frame_gain);//q14 } else { gain = add(extract_l(L_lshr( L_mult( release_constant , sub( gain, frame_gain ) ), ( Q2 - exp_pow_2 ) )) , frame_gain);//q14 } for ( c = 0; c < num_channels; c++ ) { sample = &output[c][i]; /* Apply gain */ *sample = Mpy_32_16_r(L_lshl( *sample,1 ),gain ) ;//q_factor } } } /* Save last gain and release heuristic values for next frame */ hLimiter->gain_fx = gain; hLimiter->release_heuristic_fx = releaseHeuristic; return; } #endif /*-------------------------------------------------------------------* * limiter_process() * Loading
lib_rend/ivas_prot_rend.h +17 −3 Original line number Diff line number Diff line Loading @@ -127,7 +127,16 @@ void limiter_process( const int16_t BER_detect, /* i : BER detect flag */ int16_t *strong_saturation_cnt /* i/o: counter of strong saturations (can be NULL) */ ); #ifdef IVAS_FLOAT_FIXED void limiter_process_fx( IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */ const Word16 output_frame, /* i : number of samples to be processed per channel in the I/O buffer */ const Word32 threshold, /* i : signal amplitude above which limiting starts to be applied */ const Word16 BER_detect, /* i : BER detect flag */ Word16 *strong_saturation_cnt, /* i/o: counter of strong saturations (can be NULL) */ Word16 q_factor ); #endif /*----------------------------------------------------------------------------------* * TD decorr. function prototypes *----------------------------------------------------------------------------------*/ Loading Loading @@ -1496,12 +1505,17 @@ void ivas_combined_orientation_update_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ const int16_t samples_rendered /* i : samples rendered since the last call */ ); #ifdef IVAS_FLOAT_FIXED void ivas_combined_orientation_update_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ const Word16 samples_rendered /* i : samples rendered since the last call */ ); #else void ivas_combined_orientation_update_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ const int16_t samples_rendered /* i : samples rendered since the last call */ ); #endif void ivas_combined_orientation_set_to_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ ); Loading
lib_rend/ivas_reflections.c +4 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,10 @@ ivas_error ivas_er_compute_reflections( /* If size is different, reallocate circ buffers */ /* Otherwise allocate new circ buffers */ #ifdef IVAS_FLOAT_FIXED for ( i = 0; i < 150; i++ ) { reflections->shoebox_data.gains.data_fx[i] = (Word32) float_to_fix( reflections->shoebox_data.gains.data[i], 15 ); } if ( reflections->circ_buffers ) { if ( reflections->circ_len == circ_len ) Loading
lib_rend/ivas_rotation.c +65 −1 Original line number Diff line number Diff line Loading @@ -1761,7 +1761,18 @@ ivas_error combine_external_and_head_orientations( hCombinedOrientationData->cur_subframe_samples_rendered = 0; hCombinedOrientationData->subframe_idx_start = 0; hCombinedOrientationData->cur_subframe_samples_rendered_start = 0; #ifdef IVAS_FLOAT_FIXED for ( Word16 k = 0; k < 4; k++ ) { for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 3; j++ ) { hCombinedOrientationData->Rmat_fx[k][i][j] = (Word32) float_to_fix( hCombinedOrientationData->Rmat[k][i][j], 30 ); } } } #endif return IVAS_ERR_OK; } Loading Loading @@ -2384,7 +2395,29 @@ void ivas_combined_orientation_update_index( return; } #ifdef IVAS_FLOAT_FIXED /*------------------------------------------------------------------------- * ivas_combined_orientation_update_index() * * update read index based on the number of rendered samples *------------------------------------------------------------------------*/ void ivas_combined_orientation_set_to_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ ) { IF ( hCombinedOrientationData != NULL ) { hCombinedOrientationData->subframe_idx = hCombinedOrientationData->subframe_idx_start; move16(); hCombinedOrientationData->cur_subframe_samples_rendered = hCombinedOrientationData->cur_subframe_samples_rendered_start; move16(); } return; } #else /*------------------------------------------------------------------------- * ivas_combined_orientation_update_index() Loading @@ -2404,8 +2437,38 @@ void ivas_combined_orientation_set_to_start_index( return; } #endif #ifdef IVAS_FLOAT_FIXED /*------------------------------------------------------------------------- * ivas_combined_orientation_update_start_index() * * update start index based on the number of rendered samples *------------------------------------------------------------------------*/ void ivas_combined_orientation_update_start_index( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ const Word16 samples_rendered /* i : samples rendered since the last call */ ) { IF ( hCombinedOrientationData != NULL ) { IF ( hCombinedOrientationData->num_subframes == 1 ) { /* only one orientation available anyway or split rendering with low resolution*/ hCombinedOrientationData->subframe_idx = 0; } ELSE { hCombinedOrientationData->cur_subframe_samples_rendered_start += samples_rendered; hCombinedOrientationData->subframe_idx_start += hCombinedOrientationData->cur_subframe_samples_rendered / hCombinedOrientationData->subframe_size; hCombinedOrientationData->cur_subframe_samples_rendered_start = hCombinedOrientationData->cur_subframe_samples_rendered % hCombinedOrientationData->subframe_size; hCombinedOrientationData->subframe_idx_start = min( hCombinedOrientationData->subframe_idx, hCombinedOrientationData->num_subframes - 1 ); } } return; } #else /*------------------------------------------------------------------------- * ivas_combined_orientation_update_start_index() * Loading Loading @@ -2435,3 +2498,4 @@ void ivas_combined_orientation_update_start_index( return; } #endif No newline at end of file