From 5144c09ba6541afebfa6be2a9edc1999dedd7bb3 Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Tue, 27 Feb 2024 14:35:08 +0530 Subject: [PATCH] hq_core_dec fixed implementation Converted IVAS Specific blocks in hq_core_dec and its subfunctions. --- lib_com/fill_spectrum.c | 263 ++++ lib_com/fine_gain_bits_fx.c | 87 ++ lib_com/hq_bit_allocation_fx.c | 210 +++ lib_com/hq_conf_fx.c | 293 +++++ lib_com/hq_tools_fx.c | 189 +++ lib_com/interleave_spectrum.c | 93 ++ lib_com/ivas_prot_fx.h | 206 +++ lib_com/low_rate_band_att_fx.c | 121 ++ lib_com/options.h | 1 + lib_com/prot_fx2.h | 9 + lib_com/rom_com.c | 9 + lib_com/rom_com.h | 5 + lib_com/swb_bwe_com_fx.c | 4 + lib_com/tools_fx.c | 17 + lib_dec/FEC_HQ_core_fx.c | 290 ++++ lib_dec/FEC_HQ_phase_ecu_fx.c | 2262 +++++++++++++++++++++++++++++--- lib_dec/dec_tcx_fx.c | 32 +- lib_dec/hq_classifier_dec_fx.c | 73 ++ lib_dec/hq_core_dec.c | 148 +++ lib_dec/hq_core_dec_fx.c | 618 +++++++++ lib_dec/hq_hr_dec_fx.c | 335 +++++ lib_dec/init_dec.c | 11 + lib_dec/ivas_core_dec.c | 152 +++ lib_dec/pvq_core_dec_fx.c | 84 ++ lib_dec/rom_dec.c | 45 + lib_dec/rom_dec.h | 2 + 26 files changed, 5345 insertions(+), 214 deletions(-) diff --git a/lib_com/fill_spectrum.c b/lib_com/fill_spectrum.c index 28ac1af5d..2fd58ade8 100644 --- a/lib_com/fill_spectrum.c +++ b/lib_com/fill_spectrum.c @@ -42,6 +42,9 @@ #include "wmc_auto.h" #include "prot_fx1.h" #include "prot_fx2.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*--------------------------------------------------------------------------* * fill_spectrum() @@ -267,6 +270,266 @@ void fill_spectrum( return; } +#ifdef IVAS_FLOAT_FIXED +void ivas_fill_spectrum_fx( + Word16 *coeff, /* i/o: normalized MLT spectrum / nf spectrum Q12 */ + Word32 *L_coeff_out, /* i/o: Noisefilled MLT spectrum Q12 */ + const Word16 *R, /* i : number of pulses per band Q0 */ + const Word16 is_transient, /* i : transient flag Q0 */ + Word16 norm[], /* i : quantization indices for norms Q0 */ + const Word16 *hq_generic_fenv, /* i : HQ GENERIC envelope Q1 */ + const Word16 hq_generic_offset, /* i : HQ GENERIC offset Q0 */ + const Word16 nf_idx, /* i : noise fill index Q0 */ + const Word16 length, /* i : Length of spectrum (32 or 48 kHz) Q0 */ + const Word16 env_stab, /* i : Envelope stability measure [0..1] Q15 */ + Word16 *no_att_hangover, /* i/o: Frame counter for attenuation hangover Q0 */ + Word32 *L_energy_lt, /* i/o: Long-term energy measure for transient detection Q13 */ + Word16 *bwe_seed, /* i/o: random seed for generating BWE input Q0 */ + const Word16 hq_generic_exc_clas, /* i : BWE excitation class Q0 */ + const Word16 core_sfm, /* i : index of the end band for core Q0 */ + const Word16 HQ_mode, /* i : HQ mode Q0 */ + Word16 noise_level[], /* i : noise levels for harmonic modes Q15 */ + const Word32 L_core_brate, /* i : target bit-rate Q0 */ + Word16 prev_noise_level[], /* i/o: noise factor in previous frame Q15 */ + Word16 *prev_R, /* i/o: bit allocation info. in previous frame Q0 */ + Word32 *prev_coeff_out, /* i/o: decoded spectrum in previous frame Q12 */ + const Word16 *peak_idx, /* i : peak indices for hvq Q0 */ + const Word16 Npeaks, /* i : number of peaks in hvq Q0 */ + const Word16 *npulses, /* i : number of pulses per band Q0 */ + const Word16 prev_is_transient, /* i : previous transient flag Q0 */ + Word32 *prev_normq, /* i/o: previous norms Q14 */ + Word32 *prev_env, /* i/o: previous noise envelopes Q(prev_env_Q) */ + const Word16 prev_bfi, /* i : previous bad frame indicator Q0 */ + const Word16 *sfmsize, /* i : Length of bands Q0 */ + const Word16 *sfm_start, /* i : Start of bands Q0 */ + const Word16 *sfm_end, /* i : End of bands Q0 */ + Word16 *prev_L_swb_norm, /* i/o: HVQ/Harmonic mode normalization length Q0 */ + const Word16 prev_hq_mode, /* i : Previous HQ mode Q0 */ + const Word16 num_sfm, /* i : Total number of bands Q0 */ + Word16 *prev_env_Q, + const Word16 num_env_bands, /* i : Number sub bands to be encoded for HQ_GEN Q0 */ + const Word16 element_mode /* i : IVAS element mode */ +) +{ + Word16 CodeBook[L_SPEC48k_EXT]; /* Q12 */ + Word16 cb_size; + Word16 last_sfm; + Word16 CodeBook_mod[L_SPEC48k_EXT]; /*Q12 */ + Word16 norm_adj[NB_SFM]; /*Q15 */ + Word16 high_sfm; + Word16 flag_32K_env_hangover; + Word16 bin_th; + Word16 peak_pos[L_HARMONIC_EXC]; + Word16 bwe_peaks[L_FRAME48k]; + Word32 L_normq_v[NB_SFM]; /*Q14 */ + Word16 coeff_fine[L_SPEC48k_EXT]; /*Q15 */ + Word32 L_coeff_out1[L_SPEC48k_EXT]; /*Q12 */ + set16_fx( peak_pos, 0, L_HARMONIC_EXC ); + set16_fx( bwe_peaks, 0, L_FRAME48k ); + set16_fx( norm_adj, 32767, num_sfm ); /* 1.0, Q15 */ + cb_size = 0; + move16(); + bin_th = 0; + move16(); + high_sfm = 23; + move16(); + + test(); + IF( EQ_16( HQ_mode, HQ_TRANSIENT ) ) + { + last_sfm = sub( num_sfm, 1 ); + } + ELSE IF( EQ_16( HQ_mode, HQ_GEN_SWB ) || EQ_16( HQ_mode, HQ_GEN_FB ) ) + { + last_sfm = s_max( core_sfm, sub( num_env_bands, 1 ) ); + } + ELSE + { + last_sfm = core_sfm; + move16(); + } + + IF( EQ_16( HQ_mode, HQ_HARMONIC ) ) + { + /*high_sfm = (core_brate == HQ_BWE_CROSSOVER_BRATE) ? HVQ_THRES_SFM_24k-1 : HVQ_THRES_SFM_32k-3; */ + high_sfm = sub( HVQ_THRES_SFM_32k, 1 ); + IF( LT_32( L_core_brate, HQ_BWE_CROSSOVER_BRATE ) ) + { + high_sfm = sub( HVQ_THRES_SFM_24k, 1 ); + } + + IF( LT_16( last_sfm, high_sfm ) ) + { + last_sfm = high_sfm; + move16(); + } + } + ELSE IF( EQ_16( HQ_mode, HQ_HVQ ) ) + { + bin_th = sfm_end[last_sfm]; + move16(); + } + + /* Transient analysis for envelope stability measure */ + IF( EQ_16( length, L_FRAME32k ) ) + { + env_stab_transient_detect_fx( is_transient, length, norm, no_att_hangover, L_energy_lt, HQ_mode, bin_th, L_coeff_out, 12 ); + } + + test(); + test(); + test(); + test(); + IF( EQ_16( length, L_FRAME16k ) || + ( ( EQ_16( length, L_FRAME32k ) && NE_16( HQ_mode, HQ_HARMONIC ) && NE_16( HQ_mode, HQ_HVQ ) ) && EQ_16( *no_att_hangover, 0 ) ) ) + { + /* Norm adjustment function */ + env_adj_fx( npulses, length, last_sfm, norm_adj, env_stab, sfmsize ); + } + + /*flag_32K_env_hangover = ( length == L_FRAME32k && ( (env_stab < 0.5f && *no_att_hangover == 0) || HQ_mode == HQ_HVQ ) ); */ + flag_32K_env_hangover = 0; + move16(); + test(); + test(); + test(); + IF( EQ_16( length, L_FRAME32k ) && ( ( LT_16( env_stab, 16384 ) && *no_att_hangover == 0 ) || EQ_16( HQ_mode, HQ_HVQ ) ) ) + { + flag_32K_env_hangover = 1; + move16(); + } + + + /*----------------------------------------------------------------* + * Build noise-fill codebook + *----------------------------------------------------------------*/ + + IF( NE_16( HQ_mode, HQ_HVQ ) ) + { + cb_size = build_nf_codebook_fx( flag_32K_env_hangover, coeff, sfm_start, sfmsize, sfm_end, last_sfm, R, CodeBook, CodeBook_mod ); + } + /*----------------------------------------------------------------* + * Prepare fine structure for Harmonic and HVQ + *----------------------------------------------------------------*/ + + IF( EQ_16( HQ_mode, HQ_HARMONIC ) ) + { + harm_bwe_fine_fx( R, last_sfm, high_sfm, num_sfm, norm, sfm_start, sfm_end, prev_L_swb_norm, coeff, L_coeff_out, coeff_fine ); + } + ELSE IF( EQ_16( HQ_mode, HQ_HVQ ) ) + { + hvq_bwe_fine_fx( last_sfm, num_sfm, sfm_end, peak_idx, Npeaks, peak_pos, prev_L_swb_norm, L_coeff_out, bwe_peaks, coeff_fine ); + } + + /*----------------------------------------------------------------* + * Apply noise-fill + *----------------------------------------------------------------*/ + + test(); + IF( NE_16( HQ_mode, HQ_HVQ ) && GT_16( cb_size, 0 ) ) + { + apply_noisefill_HQ_fx( R, length, flag_32K_env_hangover, L_core_brate, last_sfm, CodeBook, + CodeBook_mod, cb_size, sfm_start, sfm_end, sfmsize, coeff ); + } + + /*----------------------------------------------------------------* + * Normal mode BWE + *----------------------------------------------------------------*/ + + IF( EQ_16( HQ_mode, HQ_NORMAL ) ) + { + hq_fold_bwe_fx( last_sfm, sfm_end, num_sfm, coeff ); + } + + /*----------------------------------------------------------------* + * Apply noise-fill adjustment + *----------------------------------------------------------------*/ + + test(); + test(); + test(); + IF( ( GE_16( length, L_FRAME32k ) || GT_32( L_core_brate, HQ_32k ) || LT_32( L_core_brate, HQ_24k40 ) ) && NE_16( HQ_mode, HQ_HVQ ) ) + { + apply_nf_gain_fx( nf_idx, last_sfm, R, sfm_start, sfm_end, coeff ); + } + + /*----------------------------------------------------------------* + * Prepare fine strucutre for HQ GENERIC + *----------------------------------------------------------------*/ + test(); + IF( EQ_16( HQ_mode, HQ_GEN_SWB ) || EQ_16( HQ_mode, HQ_GEN_FB ) ) + { + hq_generic_fine_fx( coeff, last_sfm, sfm_start, sfm_end, bwe_seed, coeff_fine ); + } + + /*----------------------------------------------------------------* + * Apply envelope + *----------------------------------------------------------------*/ + + test(); + IF( NE_16( HQ_mode, HQ_HARMONIC ) && NE_16( HQ_mode, HQ_HVQ ) ) + { + apply_envelope_fx( coeff, norm, norm_adj, num_sfm, last_sfm, HQ_mode, length, sfm_start, sfm_end, + L_normq_v, L_coeff_out, coeff_fine, L_coeff_out1 ); + } + + /*----------------------------------------------------------------* + * Harmonic BWE, HVQ BWE and HQ SWB BWE + *----------------------------------------------------------------*/ + test(); + IF( EQ_16( HQ_mode, HQ_HARMONIC ) ) + { + ivas_harm_bwe_fx( coeff_fine, coeff, num_sfm, sfm_start, sfm_end, last_sfm, R, prev_hq_mode, norm, noise_level, prev_noise_level, bwe_seed, L_coeff_out, element_mode ); + } + ELSE IF( EQ_16( HQ_mode, HQ_HVQ ) ) + { + hvq_bwe_fx( L_coeff_out, coeff_fine, sfm_start, sfm_end, sfmsize, last_sfm, prev_hq_mode, bwe_peaks, bin_th, num_sfm, L_core_brate, R, norm, + noise_level, prev_noise_level, bwe_seed, L_coeff_out, 15, 12 ); + } + ELSE IF( EQ_16( HQ_mode, HQ_GEN_SWB ) || EQ_16( HQ_mode, HQ_GEN_FB ) ) + { + hq_bwe_fx( HQ_mode, L_coeff_out1, hq_generic_fenv, L_coeff_out, hq_generic_offset, prev_L_swb_norm, hq_generic_exc_clas, sfm_end, num_sfm, num_env_bands, R ); + } + + /*----------------------------------------------------------------* + * HQ WB BWE refinements + *----------------------------------------------------------------*/ + test(); + IF( EQ_16( length, L_FRAME16k ) && LE_32( L_core_brate, HQ_32k ) ) + { + hq_wb_nf_bwe_fx( coeff, is_transient, prev_bfi, L_normq_v, num_sfm, sfm_start, sfm_end, sfmsize, last_sfm, R, + prev_is_transient, prev_normq, prev_env, bwe_seed, prev_coeff_out, prev_R, L_coeff_out, prev_env_Q ); + } + + /*----------------------------------------------------------------* + * Update memories + *----------------------------------------------------------------*/ + + test(); + IF( NE_16( HQ_mode, HQ_HARMONIC ) && NE_16( HQ_mode, HQ_HVQ ) ) + { + prev_noise_level[0] = 3277; + move16(); /* 0.1 in Q15 */ + prev_noise_level[1] = 3277; + move16(); /* 0.1 in Q15 */ + } + test(); + IF( !( EQ_16( length, L_FRAME16k ) && LE_32( L_core_brate, HQ_32k ) ) ) + { + set32_fx( prev_env, 0, SFM_N_WB ); + set32_fx( prev_normq, 0, SFM_N_WB ); + } + + test(); + IF( EQ_16( length, L_FRAME32k ) && LE_32( L_core_brate, HQ_32k ) ) + { + *prev_R = R[SFM_N_WB - 1]; + Copy32( L_coeff_out + L_FRAME16k - L_HQ_WB_BWE, prev_coeff_out, L_HQ_WB_BWE ); + } + + return; +} +#endif void fill_spectrum_fx( Word16 *coeff, /* i/o: normalized MLT spectrum / nf spectrum Q12 */ diff --git a/lib_com/fine_gain_bits_fx.c b/lib_com/fine_gain_bits_fx.c index 440517657..778af0a17 100644 --- a/lib_com/fine_gain_bits_fx.c +++ b/lib_com/fine_gain_bits_fx.c @@ -7,6 +7,9 @@ #include "rom_com.h" /* Static table prototypes */ #include "prot_fx1.h" /* Function prototypes */ #include "prot_fx2.h" /* Function prototypes */ +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*-------------------------------------------------------------------------- @@ -103,3 +106,87 @@ Word16 assign_gain_bits_fx( /* o : Number of assigned gain bits return gain_bits_tot; } + +#ifdef IVAS_FLOAT_FIXED +static void ivas_subband_gain_bits_fx( + const Word16 *Rk, /* i : bit allocation per band Q3 */ + const Word16 N, /* i : number of bands */ + Word16 *bits, /* o : gain bits per band */ + const Word16 *sfmsize /* i : Size of bands */ +) +{ + Word16 i, b, tot; + Word16 bps; + + tot = 0; + move16(); + + FOR( i = 0; i < N; i++ ) + { + /*bps = (short)(Rk[i]*((word16)min(32767, ceil(32767.0f/sfmsize[i]); inexact C-integer division approx. */ + bps = extract_l( L_shr( L_mult0( Rk[i], fg_inv_tbl_fx[sfmsize[i] >> 3] ), 18 ) ); /* 3+15 */ + IF( EQ_32( L_shl( L_mult0( sfmsize[i], add( bps, 1 ) ), 3 ), Rk[i] ) ) + { + bps = add( bps, 1 ); + } + + bps = s_min( 7, bps ); + b = fine_gain_bits[bps]; + move16(); + bits[i] = b; + move16(); + tot = add( tot, b ); + } + + IF( EQ_16( tot, 0 ) ) + { + /* If no gain bits were assigned, use one bit anyway for potential PVQ overage */ + bits[0] = 1; + move16(); + } + + return; +} + +Word16 ivas_assign_gain_bits_fx( /* o : Number of assigned gain bits */ + const Word16 core, /* i : HQ core */ + const Word16 BANDS, /* i : Number of bands */ + const Word16 *band_width, /* i : Sub band bandwidth */ + Word16 *Rk, /* i/o: Bit allocation/Adjusted bit alloc. Q3 */ + Word16 *gain_bits_array, /* o : Assigned gain bits */ + Word16 *Rcalc /* o : Bit budget for shape quantizer Q3 */ +) +{ + Word16 gain_bits_tot; + Word16 i; + + /* Allocate gain bits for every subband used, based on bit rate and bandwidth */ + IF( EQ_16( core, HQ_CORE ) ) + { + ivas_subband_gain_bits_fx( Rk, BANDS, gain_bits_array, band_width ); + } + ELSE + { + set16_fx( gain_bits_array, 0, BANDS ); + } + + /* Re-adjust bit budget for gain quantization */ + gain_bits_tot = 0; + move16(); + *Rcalc = 0; + move16(); + FOR( i = 0; i < BANDS; i++ ) + { + IF( GT_16( Rk[i], 0 ) ) + { + Rk[i] = sub( Rk[i], shl( gain_bits_array[i], 3 ) ); + move16(); + gain_bits_tot = add( gain_bits_tot, gain_bits_array[i] ); + *Rcalc = add( *Rcalc, Rk[i] ); + move16(); + } + } + + return gain_bits_tot; +} +#endif diff --git a/lib_com/hq_bit_allocation_fx.c b/lib_com/hq_bit_allocation_fx.c index 447ec250e..31c4ff383 100644 --- a/lib_com/hq_bit_allocation_fx.c +++ b/lib_com/hq_bit_allocation_fx.c @@ -7,6 +7,9 @@ #include "prot_fx1.h" /* Function prototypes */ #include "prot_fx2.h" /* Function prototypes */ #include "cnst.h" /* Common constants */ +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*--------------------------------------------------------------------------* * hq_bit_allocation_fx() @@ -14,6 +17,213 @@ * Assign bits for HQ fine structure coding with PVQ *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_hq_bit_allocation_fx( + const Word32 core_brate, /* i : Core bit-rate Q0 */ + const Word16 length, /* i : Frame length Q0 */ + const Word16 hqswb_clas, /* i : HQ class Q0 */ + Word16 *num_bits, /* i/o: Remaining bit budget Q0 */ + const Word16 *normqlg2, /* i : Quantized norms Q0 */ + const Word16 nb_sfm, /* i : Number sub bands to be encoded Q0 */ + const Word16 *sfmsize, /* i : Sub band bandwidths Q0 */ + Word16 *noise_level, /* o : HVQ noise level */ + Word16 *R, /* o : Bit allocation per sub band Q0 */ + Word16 *Rsubband, /* o : Fractional bit allocation Q3 */ + Word16 *sum, /* o : Sum of allocated shape bits Q0 */ + Word16 *core_sfm, /* o : Last coded band in core Q0 */ + const Word16 num_env_bands /* i : Number sub bands to be encoded for HQ_GEN Q0 */ +) +{ + Word16 i; + Word16 idx[NB_SFM]; + Word16 wnorm[NB_SFM]; + Word16 avrg_wnorm; + Word16 tmp, tmp2; + Word16 E_low; + Word16 E_hb_mean; + Word16 E_max; + Word16 i_max; + /* Temp */ + + Word16 sfm_limit = nb_sfm; + move16(); + + set16_fx( R, 0, NB_SFM ); + FOR( i = 0; i < nb_sfm; i++ ) + { + idx[i] = i; + move16(); + } + test(); + test(); + test(); + IF( NE_16( hqswb_clas, HQ_TRANSIENT ) && NE_16( hqswb_clas, HQ_HVQ ) && !( EQ_16( length, L_FRAME16k ) && LE_32( core_brate, HQ_32k ) ) ) + { + /* 'nf_idx' 2-bits index written later */ + *num_bits = sub( *num_bits, 2 ); + } + + test(); + IF( EQ_16( hqswb_clas, HQ_GEN_SWB ) || EQ_16( hqswb_clas, HQ_GEN_FB ) ) + { + IF( GE_32( core_brate, HQ_32k ) ) + { + *num_bits = sub( *num_bits, HQ_GENERIC_SWB_NBITS2 ); + } + ELSE + { + *num_bits = sub( *num_bits, HQ_GENERIC_SWB_NBITS ); + } + + IF( EQ_16( length, L_SPEC48k ) ) + { + *num_bits = sub( *num_bits, HQ_GENERIC_FB_NBITS ); + } + } + + test(); + test(); + IF( ( EQ_16( length, L_SPEC48k ) ) && ( NE_16( hqswb_clas, HQ_HARMONIC ) ) && ( NE_16( hqswb_clas, HQ_HVQ ) ) ) + { + tmp = 0; + move16(); + IF( EQ_16( hqswb_clas, HQ_TRANSIENT ) ) + { + tmp = 1; + move16(); + } + map_quant_weight_fx( normqlg2, wnorm, tmp ); + } + ELSE + { + Copy( normqlg2, wnorm, nb_sfm ); + } + + IF( EQ_16( hqswb_clas, HQ_HARMONIC ) ) + { + /* classification and limit bandwidth for bit allocation */ + sfm_limit = sub( sfm_limit, 2 ); + limit_band_noise_level_calc_fx( wnorm, &sfm_limit, core_brate, noise_level ); + + /* Detect important band in high frequency region */ + E_low = sum16_fx( wnorm, SFM_G1 ); + i_max = 0; + move16(); + E_max = MIN16B; + move16(); + E_hb_mean = 0; + move16(); + FOR( i = SFM_G1; i < nb_sfm; i++ ) + { + E_hb_mean = add( E_hb_mean, wnorm[i] ); + IF( GT_16( wnorm[i], E_max ) ) + { + E_max = wnorm[i]; + move16(); + i_max = i; + move16(); + } + } + E_hb_mean = shr( E_hb_mean, 4 ); /* Truncated division by SFM_G1 */ + set16_fx( wnorm + sfm_limit, -20, sub( nb_sfm, sfm_limit ) ); + IF( LE_32( L_msu0( L_deposit_l( E_low ), E_max, 15 ), 0 ) ) + { + IF( LE_32( L_msu( L_deposit_h( E_hb_mean ), E_max, 21955 ), 0 ) ) /* 21955 = 0.67 (Q15) */ + { + IF( GE_16( i_max, sfm_limit ) ) + { + wnorm[i_max] = E_max; + move16(); + } + } + } + } + test(); + test(); + test(); + test(); + IF( EQ_16( hqswb_clas, HQ_HVQ ) ) + { + *sum = 0; + move16(); + } + ELSE IF( EQ_16( hqswb_clas, HQ_GEN_SWB ) || ( EQ_16( hqswb_clas, HQ_TRANSIENT ) && EQ_16( length, L_FRAME32k ) && LE_32( core_brate, HQ_32k ) ) ) + { + *sum = BitAllocF_fx( wnorm, core_brate, *num_bits, nb_sfm, R, Rsubband, hqswb_clas, num_env_bands ); + } + ELSE IF( EQ_16( length, L_FRAME16k ) && LE_32( core_brate, HQ_32k ) ) + { + IF( NE_16( hqswb_clas, HQ_TRANSIENT ) ) + { + avrg_wnorm = wnorm[10]; + move16(); + FOR( i = 11; i < 18; i++ ) + { + avrg_wnorm = add( avrg_wnorm, wnorm[i] ); + } + + avrg_wnorm = shr( avrg_wnorm, 3 ); + FOR( i = 0; i < 4; i++ ) + { + IF( LT_16( wnorm[i], avrg_wnorm ) ) + { + wnorm[i] = avrg_wnorm; + move16(); + } + } + + /* Estimate number of bits per band */ + *sum = BitAllocWB_fx( wnorm, *num_bits, nb_sfm, R, Rsubband ); + } + ELSE + { + reordvct_fx( wnorm, nb_sfm, idx ); + bitalloc_fx( wnorm, idx, *num_bits, nb_sfm, QBIT_MAX2, R, sfmsize, hqswb_clas ); + bitallocsum_fx( R, nb_sfm, sum, Rsubband, *num_bits, length, sfmsize ); + } + } + ELSE + { + reordvct_fx( wnorm, nb_sfm, idx ); + + /* enlarge the wnorm value so that more bits can be allocated to (sfm_limit/2 ~ sfm_limit) range */ + IF( EQ_16( hqswb_clas, HQ_HARMONIC ) ) + { + tmp = shr( sfm_limit, 1 ); + tmp2 = sub( tmp, 1 ); + FOR( i = tmp; i < sfm_limit; i++ ) + { + wnorm[i] = wnorm[tmp2]; + move16(); + } + } + bitalloc_fx( wnorm, idx, *num_bits, nb_sfm, QBIT_MAX2, R, sfmsize, hqswb_clas ); + bitallocsum_fx( R, nb_sfm, sum, Rsubband, *num_bits, length, sfmsize ); + } + + /* Find last coded core band */ + *core_sfm = sub( nb_sfm, 1 ); + test(); + test(); + IF( hqswb_clas == HQ_NORMAL || EQ_16( hqswb_clas, HQ_HARMONIC ) ) + { + *core_sfm = find_last_band_fx( R, nb_sfm ); + } + ELSE IF( EQ_16( hqswb_clas, HQ_GEN_SWB ) || EQ_16( hqswb_clas, HQ_GEN_FB ) ) + { + *core_sfm = find_last_band_fx( R, nb_sfm ); + IF( LT_16( *core_sfm, num_env_bands ) ) + { + *core_sfm = sub( num_env_bands, 1 ); + } + } + + *num_bits = sub( *num_bits, *sum ); + + return; +} +#endif + void hq_bit_allocation_fx( const Word32 core_brate, /* i : Core bit-rate Q0 */ const Word16 length, /* i : Frame length Q0 */ diff --git a/lib_com/hq_conf_fx.c b/lib_com/hq_conf_fx.c index a8b9ad138..0f197a151 100644 --- a/lib_com/hq_conf_fx.c +++ b/lib_com/hq_conf_fx.c @@ -8,6 +8,9 @@ #include "rom_com.h" /* Static table prototypes */ #include "prot_fx1.h" /* Function prototypes */ #include "prot_fx2.h" /* Function prototypes */ +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*--------------------------------------------------------------------------* * hq_configure() @@ -15,6 +18,296 @@ * Configuration routine for HQ mode *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_hq_configure_fx( + const Word16 length, /* i : Frame length Q0 */ + const Word16 hqswb_clas, /* i : HQ SWB class Q0 */ + const Word32 core_brate, /* i : Codec bitrate Q0 */ + Word16 *num_sfm, /* o : Total number of subbands Q0 */ + Word16 *nb_sfm, /* o : Total number of coded bands Q0 */ + Word16 *start_norm, /* o : First norm to be SDE encoded Q0 */ + Word16 *num_env_bands, /* o : Number coded envelope bands Q0 */ + Word16 *numnrmibits, /* o : Number of bits in fall-back norm encoding Q0 */ + Word16 *hq_generic_offset, /* o : Freq offset for HQ GENERIC Q0 */ + Word16 *sfmsize, /* o : Subband bandwidths Q0 */ + Word16 *sfm_start, /* o : Subband start coefficients Q0 */ + Word16 *sfm_end /* o : Subband end coefficients Q0 */ +) +{ + const Word16 *p_sfmsize; + const Word16 *p_sfm_start; + const Word16 *p_sfm_end; + Word16 i, bw_ext; + + bw_ext = 0; + move16(); + + *start_norm = 0; + move16(); + + IF( EQ_16( length, L_SPEC48k ) ) + { + IF( EQ_16( hqswb_clas, HQ_GEN_FB ) ) + { + *num_sfm = NB_SFM; + move16(); + p_sfmsize = band_len_HQ; + move16(); + p_sfm_start = band_start_HQ; + move16(); + p_sfm_end = band_end_HQ; + move16(); + + test(); + IF( GE_32( core_brate, HQ_32k ) ) + { + *hq_generic_offset = HQ_GENERIC_FOFFSET_32K; + move16(); + *num_env_bands = SFM_N_STA_10k; + move16(); + } + ELSE /*IF(EQ_32(core_brate, HQ_16k40) || EQ_32(core_brate, HQ_24k40))*/ + { + *hq_generic_offset = HQ_GENERIC_FOFFSET_24K4; + move16(); + *num_env_bands = SFM_N_STA_8k; + move16(); + } + *nb_sfm = *num_sfm; + move16(); + } + ELSE + { + IF( EQ_16( hqswb_clas, HQ_HARMONIC ) ) + { + *num_sfm = SFM_N_HARM_FB; + move16(); + *nb_sfm = SFM_N_HARM_FB; + move16(); + *num_env_bands = SFM_N_HARM_FB; + move16(); + + p_sfmsize = band_len_harm; + move16(); + p_sfm_start = band_start_harm; + move16(); + p_sfm_end = band_end_harm; + move16(); + } + ELSE IF( EQ_16( hqswb_clas, HQ_HVQ ) ) + { + IF( LT_32( core_brate, HQ_BWE_CROSSOVER_BRATE ) ) + { + *num_sfm = SFM_N_HARM_FB; + move16(); + *nb_sfm = HVQ_THRES_SFM_24k; + move16(); + *num_env_bands = sub( *num_sfm, *nb_sfm ); + move16(); + *start_norm = HVQ_THRES_SFM_24k; + move16(); + } + ELSE + { + *num_sfm = SFM_N_HARM_FB; + move16(); + *nb_sfm = HVQ_THRES_SFM_32k; + move16(); + *num_env_bands = sub( *num_sfm, *nb_sfm ); + move16(); + *start_norm = HVQ_THRES_SFM_32k; + move16(); + } + p_sfmsize = band_len_harm; + p_sfm_start = band_start_harm; + p_sfm_end = band_end_harm; + move16(); + move16(); + move16(); + } + ELSE + { + *num_sfm = NB_SFM; + move16(); + *nb_sfm = *num_sfm; + move16(); + *num_env_bands = NB_SFM; + move16(); + + p_sfmsize = band_len_HQ; + move16(); + p_sfm_start = band_start_HQ; + move16(); + p_sfm_end = band_end_HQ; + move16(); + } + } + } + ELSE IF( EQ_16( length, L_SPEC32k ) ) + { + IF( EQ_16( hqswb_clas, HQ_HARMONIC ) ) + { + *num_sfm = SFM_N_HARM; + move16(); + *nb_sfm = SFM_N_HARM; + move16(); + *num_env_bands = SFM_N_HARM; + move16(); + + p_sfmsize = band_len_harm; + move16(); + p_sfm_start = band_start_harm; + move16(); + p_sfm_end = band_end_harm; + move16(); + } + ELSE IF( EQ_16( hqswb_clas, HQ_HVQ ) ) + { + IF( LT_32( core_brate, HQ_BWE_CROSSOVER_BRATE ) ) + { + *num_sfm = SFM_N_HARM; + move16(); + *nb_sfm = HVQ_THRES_SFM_24k; + move16(); + *num_env_bands = sub( *num_sfm, *nb_sfm ); + + *start_norm = HVQ_THRES_SFM_24k; + move16(); + } + ELSE + { + *num_sfm = SFM_N_HARM; + move16(); + *nb_sfm = HVQ_THRES_SFM_32k; + move16(); + *num_env_bands = sub( *num_sfm, *nb_sfm ); + + *start_norm = HVQ_THRES_SFM_32k; + move16(); + } + p_sfmsize = band_len_harm; + move16(); + p_sfm_start = band_start_harm; + move16(); + p_sfm_end = band_end_harm; + move16(); + } + ELSE IF( EQ_16( hqswb_clas, HQ_GEN_SWB ) ) + { + *num_sfm = SFM_N_SWB; + move16(); + p_sfmsize = band_len_HQ; + move16(); + p_sfm_start = band_start_HQ; + move16(); + p_sfm_end = band_end_HQ; + move16(); + + IF( GE_32( core_brate, HQ_32k ) ) + { + *hq_generic_offset = HQ_GENERIC_FOFFSET_32K; + move16(); + *num_env_bands = SFM_N_STA_10k; + move16(); + } + ELSE /*if( EQ_32(core_brate, HQ_24k40))*/ + { + *hq_generic_offset = HQ_GENERIC_FOFFSET_24K4; + move16(); + *num_env_bands = SFM_N_STA_8k; + move16(); + } + + *nb_sfm = *num_sfm; + move16(); + } + ELSE + { + /* HQ_NORMAL and HQ_TRANSIENT */ + *num_sfm = SFM_N_SWB; + move16(); + *nb_sfm = *num_sfm; + move16(); + *num_env_bands = SFM_N_SWB; + move16(); + + p_sfmsize = band_len_HQ; + move16(); + p_sfm_start = band_start_HQ; + move16(); + p_sfm_end = band_end_HQ; + move16(); + } + } + ELSE IF( EQ_16( length, L_SPEC48k_EXT ) ) + { + bw_ext = 1; + p_sfmsize = band_len_HQ; + p_sfm_start = band_start_HQ; + p_sfm_end = band_end_HQ; + *num_sfm = NB_SFM; + move16(); + move16(); + move16(); + move16(); + } + ELSE IF( EQ_16( length, L_SPEC16k_EXT ) ) + { + bw_ext = 1; + p_sfmsize = band_len_wb; + p_sfm_start = band_start_wb; + p_sfm_end = band_end_wb; + *num_sfm = SFM_N_WB; + move16(); + move16(); + move16(); + move16(); + } + ELSE + { + *num_sfm = SFM_N_WB; + move16(); + *nb_sfm = *num_sfm; + move16(); + *num_env_bands = SFM_N_WB; + move16(); + + p_sfmsize = band_len_wb; + move16(); + p_sfm_start = band_start_wb; + move16(); + p_sfm_end = band_end_wb; + move16(); + } + IF( bw_ext ) + { + FOR( i = 0; i < *num_sfm; i++ ) + { + /*sfmsize[i] = (int16_t)(1.25f * p_sfmsize[i]);*/ + sfmsize[i] = mult_r( shl( p_sfmsize[i], 1 ), 20480 ); + /*sfm_start[i] = (int16_t)(1.25f * p_sfm_start[i]);*/ + sfm_start[i] = mult_r( shl( p_sfm_start[i], 1 ), 20480 ); + /*sfm_end[i] = (int16_t)(1.25f * p_sfm_end[i]);*/ + sfm_end[i] = mult_r( shl( p_sfm_end[i], 1 ), 20480 ); + } + *nb_sfm = *num_sfm; + *num_env_bands = *num_sfm; + move16(); + move16(); + } + ELSE + { + Copy( p_sfmsize, sfmsize, *num_sfm ); + Copy( p_sfm_start, sfm_start, *num_sfm ); + Copy( p_sfm_end, sfm_end, *num_sfm ); + } + + *numnrmibits = extract_l( L_mult0( sub( *num_env_bands, 1 ), NORMI_BITS ) ); + + return; +} +#endif + void hq_configure_evs_fx( const Word16 length, /* i : Frame length Q0 */ const Word16 hqswb_clas, /* i : HQ SWB class Q0 */ diff --git a/lib_com/hq_tools_fx.c b/lib_com/hq_tools_fx.c index 5617168c5..88b4340a4 100644 --- a/lib_com/hq_tools_fx.c +++ b/lib_com/hq_tools_fx.c @@ -39,6 +39,9 @@ #include "rom_com.h" /* Static table prototypes FIP version */ #include "stl.h" /* required for wmc_tool */ #include "prot_fx2.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*--------------------------------------------------------------------------* * Local function prototypes @@ -819,6 +822,191 @@ void apply_nf_gain_fx( * HQ Harmonic BWE *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_harm_bwe_fx( + const Word16 *coeff_fine, /* i : fine structure for BWE */ + const Word16 *coeff, /* i : coded/noisefilled normalized spectrum */ + const Word16 num_sfm, /* i : Number of subbands */ + const Word16 *sfm_start, /* i : Subband start coefficient */ + const Word16 *sfm_end, /* i : Subband end coefficient */ + const Word16 last_sfm, /* i : last coded subband */ + const Word16 *R, /* i : bit allocation */ + const Word16 prev_hq_mode, /* i : previous hq mode */ + Word16 *norm, /* i/o: quantization indices for norms */ + Word16 *noise_level, /* i/o: noise levels for harmonic modes */ + Word16 *prev_noise_level, /* i/o: noise factor in previous frame */ + Word16 *bwe_seed, /* i/o: random seed for generating BWE input */ + Word32 *coeff_out, /* o : coded/noisefilled spectrum */ + const Word16 element_mode /* i : IVAS element mode */ +) +{ + Word16 i, j; + Word16 sfm, band_width; + Word32 normq, L_tmp, L_tmp2; + Word32 E_L; + Word16 alfa = 16384; + Word16 tmp, tmp1, exp1; + Word16 beta; + Word32 *src, *dst; + + move16(); /* alfa */ + + FOR( sfm = 0; sfm <= last_sfm; sfm++ ) + { + IF( EQ_16( R[sfm], 0 ) ) + { + normq = dicn_fx[norm[sfm]]; /*Q14 */ + move16(); + + FOR( i = sfm_start[sfm]; i < sfm_end[sfm]; i++ ) + { + coeff_out[i] = L_shl( Mult_32_16( normq, coeff[i] ), 1 ); + move32(); /*12 Q(14 +12+1-16 +1) */ + } + } + } + noise_level[1] = noise_level[0]; + move16(); + + /* shaping the BWE spectrum further by envelopes and noise factors */ + L_tmp = L_mult( 29491, prev_noise_level[0] ); /* 15 +1 +15 */ + noise_level[0] = round_fx( L_mac( L_tmp, 3277, noise_level[0] ) ); /*15 */ + move16(); + + L_tmp = L_mult( 29491, prev_noise_level[1] ); + noise_level[1] = round_fx( L_mac( L_tmp, 3277, noise_level[1] ) ); + move16(); + + test(); + IF( EQ_16( prev_hq_mode, HQ_NORMAL ) || EQ_16( prev_hq_mode, HQ_GEN_SWB ) ) + { + IF( LT_16( noise_level[0], 8192 ) ) + { + noise_level[0] = shl( noise_level[0], 2 ); + move16(); + } + + IF( LT_16( noise_level[1], 8192 ) ) + { + noise_level[1] = shl( noise_level[1], 2 ); + move16(); + } + } + + FOR( i = add( last_sfm, 1 ); i < num_sfm; i++ ) + { + E_L = 1; + move32(); + FOR( j = sfm_start[i]; j < sfm_end[i]; j++ ) + { + L_tmp = L_mult0( coeff_fine[j], coeff_fine[j] ); /*Q30 */ + E_L = L_add( E_L, L_shr( L_tmp, 6 ) ); /*Q24 */ + } + + normq = dicn_fx[norm[i]]; + move32(); + + alfa = noise_level[0]; + move16(); + IF( GT_16( i, 27 ) ) + { + alfa = noise_level[1]; + move16(); + } + + band_width = sub( sfm_end[i], sfm_start[i] ); /* */ + exp1 = norm_l( E_L ); + IF( EQ_16( exp1, 0 ) ) + { + E_L = Mult_32_16( E_L, inv_tbl_fx[band_width] ); /* Q24 (24+15+1-16) */ /*24+15+1-16 */ + tmp = div_l( E_L, sub( 32767, alfa ) ); /*Q24-15-1 =8 */ + tmp = s_max( 1, tmp ); + L_tmp = L_deposit_h( tmp ); /*24 */ + E_L = Isqrt( L_tmp ); /* Q19 (31-24/2) */ + } + ELSE + { + exp1 = sub( exp1, 1 ); + E_L = Mult_32_16( L_shl( E_L, exp1 ), inv_tbl_fx[band_width] ); /* Q24+exp1 (24+exp1+15+1-16) */ + tmp = div_l( E_L, sub( 32767, alfa ) ); /*Q24+exp1-15-1 =8+exp1 */ + tmp = s_max( 1, tmp ); + L_tmp = L_shl( L_deposit_l( tmp ), sub( 16, exp1 ) ); /*24 8+exp1+16-exp1 */ + E_L = Isqrt( L_tmp ); /* Q19 (31-24/2) */ + } + + exp1 = norm_s( alfa ); + tmp1 = shl( alfa, exp1 ); + IF( EQ_16( element_mode, EVS_MONO ) ) + { + exp1 = add( 1, exp1 ); + } +#ifdef DEBUGGING + else + { + // PMT("VERIFY if this really matches IVAS float") + } +#endif + tmp1 = s_max( tmp1, 16384 ); + tmp1 = div_s( 16384, tmp1 ); + L_tmp2 = L_deposit_h( tmp1 ); + L_tmp2 = Isqrt_lc( L_tmp2, &exp1 ); + +#ifdef BASOP_NOGLOB + beta = round_fx_sat( L_shl_sat( L_tmp2, exp1 ) ); + beta = shr( beta, 1 ); /*Q15 */ +#else + beta = round_fx( L_shl( L_tmp2, exp1 ) ); + beta = shr( beta, 1 ); /*Q15 */ +#endif + + + FOR( sfm = sfm_start[i]; sfm < sfm_end[i]; sfm++ ) + { + L_tmp = Mult_32_16( E_L, coeff_fine[sfm] ); /*Q19 19 + 15 +1-16 */ +#ifdef BASOP_NOGLOB + L_tmp = L_shl_sat( L_tmp, 9 ); /*Q28 */ +#else + L_tmp = L_shl( L_tmp, 9 ); /*Q28 */ +#endif + tmp = Random( bwe_seed ); /*Q15 */ + L_tmp2 = L_shr( L_mult( beta, tmp ), 3 ); /* Q28 31-3 15+15 +1-3 */ +#ifdef BASOP_NOGLOB + L_tmp = L_add_sat( L_tmp, L_tmp2 ); /*Q28 */ + coeff_out[sfm] = L_shl_sat( Mult_32_32( L_tmp, normq ), 1 ); /*Q12 28 +14 +1 -31 */ + move32(); +#else + L_tmp = L_add( L_tmp, L_tmp2 ); /*Q28 */ + coeff_out[sfm] = L_shl( Mult_32_32( L_tmp, normq ), 1 ); /*Q12 28 +14 +1 -31 */ + move32(); +#endif + } + } + + prev_noise_level[0] = noise_level[0]; + move16(); + prev_noise_level[1] = noise_level[1]; + move16(); + + src = &coeff_out[add( sfm_end[last_sfm], L_HARMONIC_EXC - START_EXC )]; /*Q12 */ + + dst = src - 1; + FOR( i = 0; i < 16; i++ ) + { + *src = Mult_32_16( *src, hvq_bwe_fac_fx[i] ); /* Q12 (12+15+1-16) */ + move32(); + src++; + *dst = Mult_32_16( *dst, hvq_bwe_fac_fx[i] ); /* Q12 (12+15+1-16) */ + move32(); + dst--; + } + IF( EQ_16( num_sfm, 33 ) ) + { + set32_fx( &coeff_out[800], 0, 160 ); + } + return; +} +#endif + void harm_bwe_fx( const Word16 *coeff_fine, /* i : fine structure for BWE */ const Word16 *coeff, /* i : coded/noisefilled normalized spectrum */ @@ -944,6 +1132,7 @@ void harm_bwe_fx( tmp1 = div_s(16384, tmp1); L_tmp2 = L_deposit_h(tmp1); L_tmp2 = Isqrt_lc(L_tmp2, &exp1); + beta = round_fx(L_shl(L_tmp2, exp1)); beta = shr(beta, 1); /*Q15 */ diff --git a/lib_com/interleave_spectrum.c b/lib_com/interleave_spectrum.c index 4304b167a..88aeffdf9 100644 --- a/lib_com/interleave_spectrum.c +++ b/lib_com/interleave_spectrum.c @@ -42,6 +42,9 @@ #include "wmc_auto.h" #include "prot_fx1.h" #include "prot_fx2.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*--------------------------------------------------------------------------* * interleave_spectrum() @@ -291,6 +294,96 @@ void de_interleave_spectrum( return; } +#ifdef IVAS_FLOAT_FIXED +void ivas_de_interleave_spectrum_fx( + Word32 *coefs, /* i/o: input and output coefficients Q12 */ + const Word16 length /* i : length of spectrum Q0 */ +) +{ + Word16 i, j, k; + Word32 *p1, *p2, *p3, *p4; + Word32 *p_in; + Word32 coefs_out[L_FRAME48k]; + Word16 sublen[] = { 80, 160, 240, 320, 480, 720 }; + Word16 grps; + Word16 l_frame; + const Word16 *bw; + const Word16 *cnt; + + /* common for all groups */ + p1 = coefs_out; + l_frame = length; + move16(); + IF( EQ_16( length, L_SPEC48k ) ) + { + bw = intl_bw_48; + cnt = intl_cnt_48; + grps = N_INTL_GRP_48; + move16(); + l_frame = L_FRAME48k; + p2 = coefs_out + sublen[2]; /* 240, length/4 */ + p3 = coefs_out + sublen[4]; /* 480, 2*length/4 */ + p4 = coefs_out + sublen[5]; /* 720, 3*length/4 */ + } + ELSE IF( EQ_16( length, L_FRAME32k ) ) + { + bw = intl_bw_32; + cnt = intl_cnt_32; + grps = N_INTL_GRP_32; + move16(); + + p2 = coefs_out + sublen[1]; /* 160 */ + p3 = coefs_out + sublen[3]; /* 320 */ + p4 = coefs_out + sublen[4]; /* 480 */ + } + ELSE /* length == L_SPEC16k */ + { + bw = intl_bw_16; + cnt = intl_cnt_16; + grps = N_INTL_GRP_16; + move16(); + + p2 = coefs_out + sublen[0]; /* 80 */ + p3 = coefs_out + sublen[1]; /* 160 */ + p4 = coefs_out + sublen[2]; /* 240 */ + } + + set32_fx( coefs_out, 0, L_FRAME48k ); + p_in = coefs; + + FOR( i = 0; i < grps; i++ ) + { + FOR( j = 0; j < cnt[i]; j++ ) + { + FOR( k = 0; k < bw[i]; k++ ) + { + *p1++ = *p_in++; + move32(); + } + FOR( k = 0; k < bw[i]; k++ ) + { + *p2++ = *p_in++; + move32(); + } + FOR( k = 0; k < bw[i]; k++ ) + { + *p3++ = *p_in++; + move32(); + } + FOR( k = 0; k < bw[i]; k++ ) + { + *p4++ = *p_in++; + move32(); + } + } + } + + Copy32( coefs_out, coefs, l_frame ); + + return; +} +#endif + void de_interleave_spectrum_fx( Word32 *coefs, /* i/o: input and output coefficients Q12 */ const Word16 length /* i : length of spectrum Q0 */ diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index fa2af493b..6bf289f39 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -1295,4 +1295,210 @@ void ivas_sba_dirac_stereo_dec_fx( const Word16 mcmasa /* i : McMASA flag */ ); +void ivas_hq_core_dec_fx( + Decoder_State *st_fx, /* i/o: decoder state structure fx */ + Word16 synth[], /* o : output synthesis */ + Word16 *Q_synth, /* o : Q value of synth */ + const Word16 output_frame, /* i : output frame length */ + const Word16 hq_core_type, /* i : HQ core type */ + const Word16 core_switching_flag, /* i : ACELP->HQ switching frame flag */ + Word16 output[], + Word16 *Q_output ); + +void ivas_HQ_FEC_Mem_update_fx( + Decoder_State *st_fx, /* i/o: decoder state structure */ + Word32 *t_audio_q_fx, /*Q12*/ + Word32 *normq_fx, /*Q14*/ + Word16 *ynrm, + Word16 *Num_bands_p, + Word16 is_transient, + Word16 hqswb_clas, + Word16 c_switching_flag, + Word16 nb_sfm, + Word16 num_Sb, + Word16 *mean_en_high_fx, /*Q5*/ + Word16 hq_core_type, /* i : normal or low-rate MDCT(HQ) core */ + Word16 output_frame ); + +Word16 ivas_hq_classifier_dec_fx( /* o : Consumed bits Q0 */ + Decoder_State *st_fx, /* i/o: decoder state structure */ + const Word32 core_brate, /* i : Core bit rate Q0 */ + const Word16 length, /* i : Frame length Q0 */ + Word16 *is_transient, /* o : Transient flag Q0 */ + Word16 *hqswb_clas /* o : HQ class Q0 */ +); + +void ivas_hq_hr_dec_fx( + Decoder_State *st_fx, /* i/o: decoder state structure fx */ + Word32 *t_audio_q, /* o : transform-domain coefficients Q12 */ + const Word16 length, /* i : frame length Q0 */ + Word16 num_bits, /* i : number of available bits Q0 */ + Word16 *ynrm, /* o : norm quantization index vector Q0 */ + Word16 *is_transient, /* o : transient flag Q0 */ + Word16 *hqswb_clas, /* o : HQ SWB class Q0 */ + Word16 *SWB_fenv, /* o : SWB frequency envelopes Q1 */ + const Word16 core_switching_flag /* i : Core switching flag */ +); + +void ivas_hq_configure_fx( + const Word16 length, /* i : Frame length Q0 */ + const Word16 hqswb_clas, /* i : HQ SWB class Q0 */ + const Word32 core_brate, /* i : Codec bitrate Q0 */ + Word16 *num_sfm, /* o : Total number of subbands Q0 */ + Word16 *nb_sfm, /* o : Total number of coded bands Q0 */ + Word16 *start_norm, /* o : First norm to be SDE encoded Q0 */ + Word16 *num_env_bands, /* o : Number coded envelope bands Q0 */ + Word16 *numnrmibits, /* o : Number of bits in fall-back norm encoding Q0 */ + Word16 *hq_generic_offset, /* o : Freq offset for HQ GENERIC Q0 */ + Word16 *sfmsize, /* o : Subband bandwidths Q0 */ + Word16 *sfm_start, /* o : Subband start coefficients Q0 */ + Word16 *sfm_end /* o : Subband end coefficients Q0 */ +); + +void ivas_hq_bit_allocation_fx( + const Word32 core_brate, /* i : Core bit-rate Q0 */ + const Word16 length, /* i : Frame length Q0 */ + const Word16 hqswb_clas, /* i : HQ class Q0 */ + Word16 *num_bits, /* i/o: Remaining bit budget Q0 */ + const Word16 *normqlg2, /* i : Quantized norms Q0 */ + const Word16 nb_sfm, /* i : Number sub bands to be encoded Q0 */ + const Word16 *sfmsize, /* i : Sub band bandwidths Q0 */ + Word16 *noise_level, /* o : HVQ noise level */ + Word16 *R, /* o : Bit allocation per sub band Q0 */ + Word16 *Rsubband, /* o : Fractional bit allocation Q3 */ + Word16 *sum, /* o : Sum of allocated shape bits Q0 */ + Word16 *core_sfm, /* o : Last coded band in core Q0 */ + const Word16 num_env_bands /* i : Number sub bands to be encoded for HQ_GEN Q0 */ +); + +Word16 ivas_assign_gain_bits_fx( /* o : Number of assigned gain bits */ + const Word16 core, /* i : HQ core */ + const Word16 BANDS, /* i : Number of bands */ + const Word16 *band_width, /* i : Sub band bandwidth */ + Word16 *Rk, /* i/o: Bit allocation/Adjusted bit alloc. Q3 */ + Word16 *gain_bits_array, /* o : Assigned gain bits */ + Word16 *Rcalc /* o : Bit budget for shape quantizer Q3 */ +); + +void ivas_fine_gain_pred_fx( + const Word16 *sfm_start, /* i : Sub band start indices */ + const Word16 *sfm_end, /* i : Sub band end indices */ + const Word16 *sfm_size, /* i : Sub band bandwidths */ + const Word16 *i_sort, /* i : Energy sorting indices */ + const Word16 *K, /* i : Number of pulses per band */ + const Word16 *maxpulse, /* i : Maximum pulse per band */ + const Word16 *R, /* i : Bits per sub band Q3 */ + const Word16 num_sfm, /* i : Number of sub bands */ + Word16 *xq, /* i/o: Quantized vector /quantized vector with finegain adj Q15*/ + Word16 *y, /* i/o: Quantized vector (int) */ + Word16 *fg_pred, /* o : Predicted fine gains Q12 */ + const Word16 core /* i : Core */ +); + +Word16 ivas_pvq_core_dec_fx( + Decoder_State *st_fx, + const Word16 *sfm_start, + const Word16 *sfm_end, + const Word16 *sfmsize, + Word16 coefs_quant[], /* o : output MDCT */ + Word16 *Q_coefs, + Word16 bits_tot, + Word16 nb_sfm, + Word16 *R, /* Q3 */ + Word16 *Rs, + Word16 *npulses, + Word16 *maxpulse, + const Word16 core ); + +void ivas_hq_ecu_fx( + const Word16 *prevsynth, /* i : buffer of previously synthesized signal */ + Word32 *ecu_rec, /* o : reconstructed frame in tda domain */ + Word16 *time_offs, /* i/o: Sample offset for consecutive frame losses */ + Word16 *X_sav, /* i/o: Stored spectrum of prototype frame */ + Word16 *Q_spec, /* i/o: Q value of stored spectrum */ + Word16 *num_p, /* i/o: Number of identified peaks */ + Word16 *plocs, /* i/o: Peak locations */ + Word32 *plocsi, /* i/o: Interpolated peak locations Q16 */ + const Word16 env_stab, /* i : Envelope stability parameter */ + Word16 *last_fec, /* i/o: Flag for usage of pitch dependent ECU */ + const Word16 ph_ecu_HqVoicing, /* i : HQ Voicing flag */ + Word16 *ph_ecu_active, /* i : Phase ECU active flag */ + Word16 *gapsynth, /* o : Gap synthesis */ + const Word16 prev_bfi, /* i : indicating burst frame error */ + const Word16 old_is_transient[2], /* i : flags indicating previous transient frames */ + Word16 *mag_chg_1st, /* i/o: per band magnitude modifier for transients */ + Word16 *Xavg, /* i/o: Frequency group average gain to fade to */ + Word16 *beta_mute, /* o : Factor for long-term mute */ + const Word16 output_frame, /* i : frame length */ + Decoder_State *st_fx /* i/o: decoder state structure */ +); + +void ivas_fill_spectrum_fx( + Word16 *coeff, /* i/o: normalized MLT spectrum / nf spectrum Q12 */ + Word32 *L_coeff_out, /* i/o: Noisefilled MLT spectrum Q12 */ + const Word16 *R, /* i : number of pulses per band Q0 */ + const Word16 is_transient, /* i : transient flag Q0 */ + Word16 norm[], /* i : quantization indices for norms Q0 */ + const Word16 *hq_generic_fenv, /* i : HQ GENERIC envelope Q1 */ + const Word16 hq_generic_offset, /* i : HQ GENERIC offset Q0 */ + const Word16 nf_idx, /* i : noise fill index Q0 */ + const Word16 length, /* i : Length of spectrum (32 or 48 kHz) Q0 */ + const Word16 env_stab, /* i : Envelope stability measure [0..1] Q15 */ + Word16 *no_att_hangover, /* i/o: Frame counter for attenuation hangover Q0 */ + Word32 *L_energy_lt, /* i/o: Long-term energy measure for transient detection Q13 */ + Word16 *bwe_seed, /* i/o: random seed for generating BWE i Q0 */ + const Word16 hq_generic_exc_clas, /* i : BWE excitation class Q0 */ + const Word16 core_sfm, /* i : index of the end band for core Q0 */ + const Word16 HQ_mode, /* i : HQ mode Q0 */ + Word16 noise_level[], /* i : noise levels for harmonic modes Q15 */ + const Word32 L_core_brate, /* i : target bit-rate Q0 */ + Word16 prev_noise_level[], /* i/o: noise factor in previous frame Q15 */ + Word16 *prev_R, /* i/o: bit allocation info. in previous frame Q0 */ + Word32 *prev_coeff_out, /* i/o: decoded spectrum in previous frame Q12 */ + const Word16 *peak_idx, /* i : peak indices for hvq Q0 */ + const Word16 Npeaks, /* i : number of peaks in hvq Q0 */ + const Word16 *npulses, /* i : number of pulses per band Q0 */ + const Word16 prev_is_transient, /* i : previous transient flag Q0 */ + Word32 *prev_normq, /* i/o: previous norms Q14 */ + Word32 *prev_env, /* i/o: previous noise envelopes Q(prev_env_Q) */ + const Word16 prev_bfi, /* i : previous bad frame indicator Q0 */ + const Word16 *sfmsize, /* i : Length of bands Q0 */ + const Word16 *sfm_start, /* i : Start of bands Q0 */ + const Word16 *sfm_end, /* i : End of bands Q0 */ + Word16 *prev_L_swb_norm, /* i/o: HVQ/Harmonic mode normalization length Q0 */ + const Word16 prev_hq_mode, /* i : Previous HQ mode Q0 */ + const Word16 num_sfm, /* i : Total number of bands Q0 */ + Word16 *prev_env_Q, + const Word16 num_env_bands, + const Word16 element_mode ); + +void ivas_de_interleave_spectrum_fx( + Word32 *coefs, /* i/o: input and output coefficients Q12 */ + const Word16 length /* i : length of spectrum Q0 */ +); + +void ivas_harm_bwe_fx( + const Word16 *coeff_fine, /* i : fine structure for BWE */ + const Word16 *coeff, /* i : coded/noisefilled normalized spectrum */ + const Word16 num_sfm, /* i : Number of subbands */ + const Word16 *sfm_start, /* i : Subband start coefficient */ + const Word16 *sfm_end, /* i : Subband end coefficient */ + const Word16 last_sfm, /* i : last coded subband */ + const Word16 *R, /* i : bit allocation */ + const Word16 prev_hq_mode, /* i : previous hq mode */ + Word16 *norm, /* i/o: quantization indices for norms */ + Word16 *noise_level, /* i/o: noise levels for harmonic modes */ + Word16 *prev_noise_level, /* i/o: noise factor in previous frame */ + Word16 *bwe_seed, /* i/o: random seed for generating BWE input */ + Word32 *coeff_out, /* o : coded/noisefilled spectrum */ + const Word16 element_mode /* i : IVAS element mode */ +); + +void ivas_hq_pred_hb_bws_fx( + Decoder_State *st_fx, /* i/o: decoder state structure */ + const Word16 *ynrm, /* i : norm quantization index vector */ + const Word16 length, /* i : frame length */ + const Word16 hqswb_clas, /* i : HQ SWB class */ + const Word16 *SWB_fenv /* i : SWB frequency envelopes Q1 */ +); #endif diff --git a/lib_com/low_rate_band_att_fx.c b/lib_com/low_rate_band_att_fx.c index 5b0e3c482..0e835a37d 100644 --- a/lib_com/low_rate_band_att_fx.c +++ b/lib_com/low_rate_band_att_fx.c @@ -7,6 +7,9 @@ #include "rom_com.h" /* Static table prototypes */ #include "prot_fx1.h" #include "prot_fx2.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*--------------------------------------------------------------------------* @@ -15,6 +18,124 @@ * Fine gain prediction *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_fine_gain_pred_fx( + const Word16 *sfm_start, /* i : Sub band start indices */ + const Word16 *sfm_end, /* i : Sub band end indices */ + const Word16 *sfm_size, /* i : Sub band bandwidths */ + const Word16 *i_sort, /* i : Energy sorting indices */ + const Word16 *K, /* i : Number of pulses per band */ + const Word16 *maxpulse, /* i : Maximum pulse per band */ + const Word16 *R, /* i : Bits per sub band Q3 */ + const Word16 num_sfm, /* i : Number of sub bands */ + Word16 *xq, /* i/o: Quantized vector /quantized vector with finegain adj Q15*/ + Word16 *y, /* i/o: Quantized vector (int) */ + Word16 *fg_pred, /* o : Predicted fine gains Q12 */ + const Word16 core /* i : Core */ +) +{ + Word16 i, band; + Word16 gp; + Word32 xx; + Word16 accuracy; + Word16 k, bw; + + Word16 shift, bw_idx; + Word16 tmp, exp, exp2; + Word32 L_tmp; + UWord16 lsb; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + FOR( band = 0; band < num_sfm; band++ ) + { + k = K[i_sort[band]]; + move16(); + + IF( GT_16( k, 0 ) ) + { + /* bw, bw_idx only used if k>0 */ + bw = sfm_size[i_sort[band]]; + move16(); // Extending for IVAS /* allowed. 8, 16, 24,32,40,48,64,80,96*/ + + bw_idx = ivas_band_len_idx[shr( bw, 3 )]; + move16(); /* bw_idx= 0: 8 */ + xx = L_deposit_l( 0 ); + shift = ivas_band_len_ener_shift[bw_idx]; + FOR( i = sfm_start[i_sort[band]]; i < sfm_end[i_sort[band]]; i++ ) + { + /*xx += xq[i] * xq[i]; */ + tmp = shr( xq[i], shift ); /*15-shift */ + xx = L_mac0( xx, tmp, tmp ); /*30-2*shift */ + } + + IF( GT_32( xx, 0 ) ) + { + /* Normalize synthesis to RMS=1.0 */ + /*gp = (float) sqrt(bw / xx); */ + exp = norm_l( xx ); + L_tmp = L_shl( xx, exp ); /*2*(15-shift)+exp */ + exp = sub( 31, add( exp, sub( 30, shl( shift, 1 ) ) ) ); + L_tmp = Isqrt_lc( L_tmp, &exp ); /*31 - exp */ + Mpy_32_16_ss( L_tmp, ivas_fine_gain_pred_sqrt_bw[bw_idx], &L_tmp, &lsb ); /*31-exp+11-15=27-exp */ +#ifdef BASOP_NOGLOB + gp = round_fx_o( L_shl_o( L_tmp, add( 1, exp ), &Overflow ), &Overflow ); /*27-exp+1+exp-16=12 */ +#else + gp = round_fx( L_shl( L_tmp, add( 1, exp ) ) ); /*27-exp+1+exp-16=12 */ +#endif + test(); + test(); + IF( EQ_16( core, HQ_CORE ) && R != NULL && LE_16( R[i_sort[band]], 256 ) ) /* 256 is 32 in Q3 */ + { + /*accuracy = ((float)k/(float)bw)*maxpulse[i_sort[band]]; */ + L_tmp = L_mult( k, inv_tbl_fx[bw] ); /*0+15+1 */ + exp2 = norm_l( L_tmp ); + tmp = round_fx( L_shl( L_tmp, exp2 ) ); /*16+exp2-16 */ + L_tmp = L_mult0( maxpulse[i_sort[band]], tmp ); /*0+exp2 */ + exp = norm_l( L_tmp ); + accuracy = round_fx( L_shl( L_tmp, exp ) ); /*exp2+exp-16=exp-16 */ + exp = add( exp, exp2 ); + + /*gp *= 1.0f - 0.05f / accuracy; */ + tmp = div_s( 13107, accuracy ); /* 0.05 in Q18 */ +#ifdef BASOP_NOGLOB + tmp = shr_o( tmp, sub( 34, exp ), &Overflow ); /*15+18-exp+16-15=34-exp */ +#else /* BASOP_NOGLOB */ + tmp = shr( tmp, sub( 34, exp ) ); /*15+18-exp+16-15=34-exp */ +#endif + tmp = sub( 32767, tmp ); + tmp = s_max( 27554, tmp ); /* Limit attenuation to norm quantizer error, 2^-0.25 in Q15 */ + gp = mult_r( tmp, gp ); /*15+12+1-16=12 */ + } + + fg_pred[band] = gp; + move16(); + } + ELSE + { + fg_pred[band] = 0; + move16(); + } + } + ELSE + { + fg_pred[band] = 0; + move16(); + FOR( i = sfm_start[i_sort[band]]; i < sfm_end[i_sort[band]]; i++ ) + { + y[i] = 0; + move16(); + xq[i] = 0; + move16(); + } + } + } + + return; +} +#endif + void fine_gain_pred_fx( const Word16 *sfm_start, /* i : Sub band start indices */ const Word16 *sfm_end, /* i : Sub band end indices */ diff --git a/lib_com/options.h b/lib_com/options.h index 192b4ccf1..086de2889 100644 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -95,6 +95,7 @@ #define NONBE_FIX_819_DOUBLE_PREC_COMB_FORMATS /* VA: issue 820: Double precision arithmetic in combined formats */ #define NONBE_FIX_849_OMASA_BFI_CRASH /* VA: issue 849: fix OMASA 2TC and FEC crashes */ #define IVAS_FLOAT_FIXED +#define EVS_FUNC_MODIFIED //#define DEBUGGING //#define DBG_WAV_WRITER #define EVS_FLOAT diff --git a/lib_com/prot_fx2.h b/lib_com/prot_fx2.h index 18fb66328..c3d460aaf 100644 --- a/lib_com/prot_fx2.h +++ b/lib_com/prot_fx2.h @@ -8692,4 +8692,13 @@ void Interpolate_allpass_steep_32( Word32 *out_fx /* o : output array of size 2*N */ ); +void IMDCT( Word32 *x, Word16 x_e, Word16 *old_syn_overl, Word16 *syn_Overl_TDAC, Word16 *xn_buf, const Word16 *tcx_aldo_window_1, const PWord16 *tcx_aldo_window_1_trunc, const PWord16 *tcx_aldo_window_2, const PWord16 *tcx_mdct_window_half, const PWord16 *tcx_mdct_window_minimum, const PWord16 *tcx_mdct_window_trans, Word16 tcx_mdct_window_half_length, Word16 tcx_mdct_window_min_length, Word16 index, Word16 left_rect, Word16 tcx_offset, Word16 overlap, Word16 L_frame, Word16 L_frameTCX, Word16 L_spec_TCX5, Word16 L_frame_glob, Word16 frame_cnt, Word16 bfi, Word16 *old_out, Word16 *Q_old_wtda, Decoder_State *st, Word16 fullbandScale, Word16 *acelp_zir ); + +void v_mult16_fixed( + const Word16 x1[], /* i : Input vector 1 */ + const Word16 x2[], /* i : Input vector 2 */ + Word16 y[], /* o : Output vector that contains vector 1 .* vector 2 */ + const Word16 N /* i : Vector length */ +); + #endif diff --git a/lib_com/rom_com.c b/lib_com/rom_com.c index 42526d53f..313ae0715 100644 --- a/lib_com/rom_com.c +++ b/lib_com/rom_com.c @@ -40462,6 +40462,15 @@ const Word16 band_len_idx[1 + (MAX_SFM_LEN_FX / 8)] = const Word16 band_len_ener_shift[8] = { 1, 2, 2, 2, 3, 3 , 4/*sfm==80*/, 4 /*sfm==96*/ }; /* 96 requires 1 bit more than 48 */ /*% sfms=[8,16,24,32,48,64,80,96], round(sqrt(sfms)*2^11) */ const Word16 fine_gain_pred_sqrt_bw[8] = { 5793, 8192, 10033, 11585, 14189, 16384, 18318 , 20066 }; /* (Q11) */ +#ifdef IVAS_FLOAT_FIXED +const Word16 ivas_band_len_idx[1 + ( MAX_SFM_LEN_FX / 8 )] = { + /*sfm/8*/ /*1*/ /*2 */ /*3 */ /*4 */ /*6 */ /*8 */ /*10*/ /*12*/ + -1, 0 /*8*/, 1 /*16*/, 2 /*24*/, 3 /*32*/, 4 /*40*/, 5 /*48 */, -1, 6 /*64 */, -1, 7 /*80*/, -1, 8 /*96*/ +}; +const Word16 ivas_band_len_ener_shift[9] = { 1, 2, 2, 2, 3, 3, 3, 4 /*sfm==80*/, 4 /*sfm==96*/ }; /* 96 requires 1 bit more than 48 */ +const Word16 ivas_fine_gain_pred_sqrt_bw[9] = { 5793, 8192, 10033, 11585, 12953, 14189, 16384, 18318, 20066 }; /* (Q11) */ +/*% sfms=[8,16,24,32,40,48,64,80,96], round(sqrt(sfms)*2^11) */ +#endif /*----------------------------------------------------------------------------------* * means of ISFs for WB active speech *----------------------------------------------------------------------------------*/ diff --git a/lib_com/rom_com.h b/lib_com/rom_com.h index f3a5a4ec4..86a2e82c0 100644 --- a/lib_com/rom_com.h +++ b/lib_com/rom_com.h @@ -2066,6 +2066,11 @@ extern const Word16 mfreq_loc_div_25[]; extern const Word16 band_len_idx[]; extern const Word16 band_len_ener_shift[]; extern const Word16 fine_gain_pred_sqrt_bw[]; +#ifdef IVAS_FLOAT_FIXED +extern const Word16 ivas_band_len_idx[]; +extern const Word16 ivas_band_len_ener_shift[]; +extern const Word16 ivas_fine_gain_pred_sqrt_bw[]; +#endif extern const Word16 Mean_isf_wb[]; extern const Word16 lsp_shb_prev_tbl_fx[]; extern const Word16 tab_ari_qnew[4][4]; diff --git a/lib_com/swb_bwe_com_fx.c b/lib_com/swb_bwe_com_fx.c index 3dac7c4e8..8f69bfebd 100644 --- a/lib_com/swb_bwe_com_fx.c +++ b/lib_com/swb_bwe_com_fx.c @@ -2604,7 +2604,11 @@ void hq_generic_decoding_fx( IF(L_tmp != 0) { exp = norm_l(L_tmp); +#ifdef EVS_FUNC_MODIFIED + frac = round_fx_sat(L_shl(L_tmp, exp));/*cs+exp-16 */ +#else frac = round_fx(L_shl(L_tmp, exp));/*cs+exp-16 */ +#endif tmp = div_s(16384, frac);/*15 + 14 - (cs+exp-16) */ exp = sub(add(cs, exp), 30); L_tmp = Isqrt_lc(L_deposit_h(tmp), &exp);/*Q31 - exp */ diff --git a/lib_com/tools_fx.c b/lib_com/tools_fx.c index f44798f14..0f629a176 100644 --- a/lib_com/tools_fx.c +++ b/lib_com/tools_fx.c @@ -3653,3 +3653,20 @@ Word32 sign_l( return MAX_32; } } + +void v_mult16_fixed( + const Word16 x1[], /* i : Input vector 1 */ + const Word16 x2[], /* i : Input vector 2 */ + Word16 y[], /* o : Output vector that contains vector 1 .* vector 2 */ + const Word16 N /* i : Vector length */ +) +{ + Word16 i; + + FOR( i = 0; i < N; i++ ) + { + y[i] = mult_r( x1[i], x2[i] ); + } + + return; +} diff --git a/lib_dec/FEC_HQ_core_fx.c b/lib_dec/FEC_HQ_core_fx.c index f1b243328..d1493f8b9 100644 --- a/lib_dec/FEC_HQ_core_fx.c +++ b/lib_dec/FEC_HQ_core_fx.c @@ -7,6 +7,9 @@ #include "prot_fx1.h" /* Function prototypes */ #include "prot_fx2.h" /* Function prototypes */ #include "rom_com.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*---------------------------------------------------------------------* @@ -395,6 +398,293 @@ void HQ_FEC_processing_fx( return; } +#ifdef IVAS_FLOAT_FIXED +void ivas_HQ_FEC_Mem_update_fx( + Decoder_State *st_fx, /* i/o: decoder state structure */ + Word32 *t_audio_q_fx, /*Q12*/ + Word32 *normq_fx, /*Q14*/ + Word16 *ynrm, + Word16 *Num_bands_p, + Word16 is_transient, + Word16 hqswb_clas, + Word16 c_switching_flag, + Word16 nb_sfm, + Word16 num_Sb, + Word16 *mean_en_high_fx, /*Q5*/ + Word16 hq_core_type, /* i : normal or low-rate MDCT(HQ) core */ + Word16 output_frame ) +{ + Word16 Min_ind; + Word32 Min_value; + Word16 Max_ind; + Word16 stat_mode_curr; + + Word16 i, j, k; + Word16 offset; + Word16 exp, exp1, exp2, tmp_fx; + Word32 *norm_values_fx; + Word32 L_tmp, tmp_energy_fx = 0, Max_coeff_fx; + Word32 en_high_fx[MAX_SB_NB]; + HQ_NBFEC_HANDLE hHQ_nbfec; + HQ_DEC_HANDLE hHQ_core; + hHQ_nbfec = st_fx->hHQ_nbfec; + hHQ_core = st_fx->hHQ_core; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + IF( EQ_16( output_frame, L_FRAME8k ) ) + { + + IF( is_transient ) + { + set16_fx( hHQ_nbfec->prev_sign_switch_2_fx, 0, HQ_FEC_SIGN_SFM ); + set16_fx( hHQ_nbfec->prev_sign_switch_fx, 0, HQ_FEC_SIGN_SFM ); + } + ELSE + { + FOR( j = 0; j < HQ_FEC_SIGN_SFM; j++ ) + { + hHQ_nbfec->prev_sign_switch_fx[j] = hHQ_nbfec->prev_sign_switch_2_fx[j]; + move16(); + hHQ_nbfec->prev_sign_switch_2_fx[j] = 0; + move16(); + + FOR( i = 0; i < HQ_FEC_BAND_SIZE; i++ ) + { + test(); + test(); + test(); + IF( ( GT_32( hHQ_nbfec->old_coeffs_fx[i + j * HQ_FEC_BAND_SIZE], 0 ) && LT_32( t_audio_q_fx[i + j * HQ_FEC_BAND_SIZE], 0 ) ) || ( LT_32( hHQ_nbfec->old_coeffs_fx[i + j * HQ_FEC_BAND_SIZE], 0 ) && GT_32( t_audio_q_fx[i + j * HQ_FEC_BAND_SIZE], 0 ) ) ) + { + hHQ_nbfec->prev_sign_switch_fx[j] = add( hHQ_nbfec->prev_sign_switch_fx[j], 1 ); + move16(); + hHQ_nbfec->prev_sign_switch_2_fx[j] = add( hHQ_nbfec->prev_sign_switch_2_fx[j], 1 ); + move16(); + } + } + } + } + /* if LR MDCT core is used, recalculate norms from decoded MDCT spectrum (using code from hq_hr_enc_fx()) */ + test(); + IF( ( EQ_16( hqswb_clas, HQ_HVQ ) ) || ( EQ_16( hq_core_type, LOW_RATE_HQ_CORE ) ) ) + { + /* First group */ + logqnorm_fx( t_audio_q_fx, 12, ynrm, 32, WID_G1, ( hqswb_clas == HQ_HVQ ) ); + j = ynrm[0]; + move16(); + offset = WID_G1; + move16(); + + FOR( i = 1; i < SFM_G1; i++ ) + { + logqnorm_fx( &t_audio_q_fx[offset], 12, &ynrm[i], 40, WID_G1, ( hqswb_clas == HQ_HVQ ) ); + offset += WID_G1; + move16(); + } + + /* Second group */ + FOR( i = SFM_G1; i < SFM_G1 + 2; i++ ) + { + logqnorm_fx( &t_audio_q_fx[offset], 12, &ynrm[i], 40, WID_G2, ( hqswb_clas == HQ_HVQ ) ); + offset += WID_G2; + move16(); + } + } + + /* Memory update for the LGF log2 Norm */ + FOR( i = 0; i < nb_sfm; i++ ) + { + normq_fx[i] = dicn_fx[ynrm[i]]; + move32(); + } + k = 0; + move16(); + FOR( i = 0; i < num_Sb; i++ ) + { + norm_values_fx = &hHQ_nbfec->ynrm_values_fx[i][0]; + Copy32( norm_values_fx, &norm_values_fx[1], MAX_PGF - 1 ); + + L_tmp = L_deposit_l( 0 ); + FOR( j = 0; j < Num_bands_p[i]; j++ ) + { + L_tmp = L_add( L_tmp, L_shr( normq_fx[k++], 3 ) ); /*11*/ + } +#ifdef BASOP_NOGLOB + tmp_fx = shl_o( inv_tbl_fx[Num_bands_p[i]], 1, &Overflow ); /*16*/ +#else + tmp_fx = shl( inv_tbl_fx[Num_bands_p[i]], 1 ); /*16*/ +#endif + norm_values_fx[0] = Mult_32_16( L_tmp, tmp_fx ); /*11 + 16 - 15*/ + move32(); + tmp_energy_fx = L_add( tmp_energy_fx, L_shr( L_tmp, 3 ) ); /*8*/ + } + test(); + test(); + IF( ( c_switching_flag ) || ( ( EQ_16( st_fx->last_core, ACELP_CORE ) ) && ( EQ_16( st_fx->core, HQ_CORE ) ) ) ) + { + FOR( i = 0; i < MAX_SB_NB; i++ ) + { + FOR( j = 1; j < MAX_PGF; j++ ) + { + hHQ_nbfec->ynrm_values_fx[i][j] = hHQ_nbfec->ynrm_values_fx[i][0]; + move32(); + } + } + } + set16_fx( hHQ_nbfec->Norm_gain_fx, 32767, SFM_N_NB ); /*15*/ + /* st->energy_MA_Curr[1]=Energy of the current frame */ + tmp_fx = inv_tbl_fx[nb_sfm]; + move16(); /*15*/ + L_tmp = Mult_32_16( tmp_energy_fx, tmp_fx ); /*8 + 15 - 15*/ + + hHQ_nbfec->energy_MA_Curr_fx[1] = extract_h( L_shl( L_tmp, 16 - 8 ) ); + move16(); + /* Moving Average */ + hHQ_nbfec->energy_MA_Curr_fx[0] = s_max( 1, add( mult_r( 26214, hHQ_nbfec->energy_MA_Curr_fx[0] ), mult_r( 6554, hHQ_nbfec->energy_MA_Curr_fx[1] ) ) ); + move16(); + + /*st->diff_energy = (float)fabs((st->energy_MA_Curr[1] - st->energy_MA_Curr[0])/st->energy_MA_Curr[0]); */ + hHQ_nbfec->diff_energy_fx = abs_s( sub( hHQ_nbfec->energy_MA_Curr_fx[1], hHQ_nbfec->energy_MA_Curr_fx[0] ) ); + exp1 = sub( norm_l( hHQ_nbfec->diff_energy_fx ), 1 ); + exp2 = norm_l( hHQ_nbfec->energy_MA_Curr_fx[0] ); + hHQ_nbfec->diff_energy_fx = div_s( extract_h( L_shl( hHQ_nbfec->diff_energy_fx, exp1 ) ), extract_h( L_shl( hHQ_nbfec->energy_MA_Curr_fx[0], exp2 ) ) ); + exp = add( 15, sub( exp1, exp2 ) ); + hHQ_nbfec->diff_energy_fx = shl( hHQ_nbfec->diff_energy_fx, sub( 11, exp ) ); /*11*/ + + /* Classify the stationary mode : 12% */ + IF( LT_16( hHQ_nbfec->diff_energy_fx, ED_THRES_12P_fx ) ) + { + stat_mode_curr = 1; + move16(); + } + ELSE + { + stat_mode_curr = 0; + move16(); + } + + /* Apply Hysteresis to prevent frequent mode changing */ + IF( EQ_16( hHQ_nbfec->stat_mode_old_fx, stat_mode_curr ) ) + { + hHQ_nbfec->stat_mode_out_fx = stat_mode_curr; + move16(); + } + + hHQ_nbfec->stat_mode_old_fx = stat_mode_curr; + move16(); + + /* Find max. band index (Minimum value means maximum energy) */ + Min_ind = 0; + move16(); + Min_value = L_deposit_l( 100 ); + FOR( i = 0; i < num_Sb; i++ ) + { + IF( GT_32( Min_value, ynrm[i] ) ) + { + Min_value = ynrm[i]; + move16(); + Min_ind = i; + move16(); + } + } + + /* Find max. coeff in band 0 */ + Max_ind = 0; + move16(); + IF( EQ_16( Min_ind, 0 ) ) + { + Max_coeff_fx = L_deposit_l( 0 ); + FOR( i = 0; i < 8; i++ ) + { + L_tmp = L_abs( t_audio_q_fx[i] ); + IF( LT_32( Max_coeff_fx, L_tmp ) ) + { + Max_coeff_fx = L_add( L_tmp, 0 ); + Max_ind = i; + move16(); + } + } + } + + /* Find energy difference from band 16 */ + k = 1; + move16(); + + FOR( i = k; i < num_Sb; i++ ) + { + en_high_fx[i] = L_deposit_l( 0 ); + FOR( j = 0; j < 2; j++ ) + { + /*en_high[i] += 0.5f*st->ynrm_values[i][j+1];*/ + en_high_fx[i] = L_add( en_high_fx[i], L_shr( hHQ_nbfec->ynrm_values_fx[i][j + 1], 1 ) ); /*Q12*/ + move32(); + } + } + + *mean_en_high_fx = 0; + move16(); + FOR( i = k; i < num_Sb; i++ ) + { + /* *mean_en_high += (float)(en_high[i]/st->ynrm_values[i][0]);*/ + exp1 = sub( norm_l( en_high_fx[i] ), 1 ); + exp2 = norm_l( hHQ_nbfec->ynrm_values_fx[i][0] ); + tmp_fx = div_s( extract_h( L_shl( en_high_fx[i], exp1 ) ), extract_h( L_shl( hHQ_nbfec->ynrm_values_fx[i][0], exp2 ) ) ); + exp = add( 15, sub( exp1, exp2 ) ); +#ifdef BASOP_NOGLOB + *mean_en_high_fx = add_o( *mean_en_high_fx, shr_o( tmp_fx, sub( exp, 5 ), &Overflow ), &Overflow ); +#else + *mean_en_high_fx = add( *mean_en_high_fx, shr( tmp_fx, sub( exp, 5 ) ) ); +#endif + } + *mean_en_high_fx = mult( *mean_en_high_fx, inv_tbl_fx[num_Sb - k] ); + + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + IF( ( LT_16( Min_ind, 5 ) ) && ( LT_16( abs_s( sub( Min_ind, hHQ_nbfec->old_Min_ind_fx ) ), 2 ) ) && ( LT_16( hHQ_nbfec->diff_energy_fx, ED_THRES_90P_fx ) ) && ( !st_fx->bfi ) && ( !st_fx->prev_bfi ) && ( !st_fx->prev_old_bfi_fx ) && ( !is_transient ) && ( !hHQ_core->old_is_transient_fx[1] ) && ( EQ_16( hHQ_nbfec->prev_last_core_fx, HQ_CORE ) ) && ( EQ_16( st_fx->last_core, HQ_CORE ) ) ) + { + hHQ_nbfec->phase_mat_flag_fx = 1; + move16(); + test(); + IF( ( EQ_16( Min_ind, 0 ) ) && ( LT_16( Max_ind, 3 ) ) ) + { + hHQ_nbfec->phase_mat_flag_fx = 0; + move16(); + } + } + ELSE + { + hHQ_nbfec->phase_mat_flag_fx = 0; + move16(); + } + + hHQ_nbfec->old_Min_ind_fx = Min_ind; + move16(); + + FOR( i = 0; i < L_FRAME8k; i++ ) + { + hHQ_nbfec->old_coeffs_fx[i] = t_audio_q_fx[i]; + move32(); + } + } + + hHQ_core->old_is_transient_fx[2] = hHQ_core->old_is_transient_fx[1]; + move16(); + hHQ_core->old_is_transient_fx[1] = hHQ_core->old_is_transient_fx[0]; + move16(); + hHQ_core->old_is_transient_fx[0] = is_transient; + move16(); + + return; +} +#endif + void HQ_FEC_Mem_update_fx( Decoder_State *st_fx, /* i/o: decoder state structure */ Word32 *t_audio_q_fx, /*Q12*/ diff --git a/lib_dec/FEC_HQ_phase_ecu_fx.c b/lib_dec/FEC_HQ_phase_ecu_fx.c index d6a65de42..128d0db6a 100644 --- a/lib_dec/FEC_HQ_phase_ecu_fx.c +++ b/lib_dec/FEC_HQ_phase_ecu_fx.c @@ -9,6 +9,9 @@ #include "prot_fx1.h" #include "prot_fx2.h" #include "basop_util.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*---------------------------------------------------------------------* * Local constants @@ -45,6 +48,15 @@ #define PFIND_SENS_FX 31785 /* 0.97 in Q15 */ #define CMPLMNT_PFIND_SENS_FX 983 /* (1.0 - pfind_sen) in Q15 */ +#ifdef IVAS_FLOAT_FIXED +#define DELTA_CORR_F0_INT 2 /* Constant controls the bin range where Jacobsen is used */ +#define ST_PFIND_SENS 0.93f /* peakfinder sensitivity */ +#define L_PROT_NS 32000000L /* Prototype frame length in nanoseconds (32 ms) */ +#define PH_ECU_CORR_LIMIT 0.85f /* Correlation limit for IVAS Phase ECU activation */ +#define PH_ECU_CORR_LIMIT_Q15 27853 /* 0.85 in Q15 */ +#define PH_ECU_N_LIMIT 56 /* fec_alg analysis frame limit for IVAS Phase ECU activation */ +#define CMPLMNT_ST_PFIND_SENS_FX 2293 /* (1.0 - st_pfind_sen) in Q15 */ +#else #ifdef IVAS_FEC_ECU_TO_COMPLETE #define DELTA_CORR_F0_INT 2 /* Constant controls the bin range where Jacobsen is used */ #define ST_PFIND_SENS 0.93f /* peakfinder sensitivity */ @@ -52,6 +64,7 @@ #define PH_ECU_CORR_LIMIT 0.85f /* Correlation limit for IVAS Phase ECU activation */ #define PH_ECU_N_LIMIT 56 /* fec_alg analysis frame limit for IVAS Phase ECU activation */ #endif +#endif #define FEC_HQ_ECU_POINT5 (0x4000) /* 0.5 in Q15. Prefix with FEC_HQ namespace to avoid naming conflict. */ #define FEC_HQ_ECU_ROOT2 (0x5a83) /* sqrt(2) in Q14 */ @@ -114,6 +127,79 @@ static Word16 rand_phase_fx(const Word16 seed, Word16 *sin_F, Word16 *cos_F) return seed2; } + +#ifdef IVAS_FLOAT_FIXED + /*! r: The location, relative to the middle of the 3 given data point, of the maximum. (Q15)*/ +static Word16 ivas_imax2_jacobsen_mag_fx( + const Word16 *y_re, /* i : The 3 given data points. real part order -1 0 1 */ + const Word16 *y_im /* i : The 3 given data points. imag part order 1 0 -1 (from FFT) */ +) +{ + Word16 posi; + const Word16 *pY; + Word16 y_m1_re, y_0_re, y_p1_re; + Word16 y_m1_im, y_0_im, y_p1_im; + Word16 N_re, N_im; + Word16 D_re, D_im; + Word16 tmp, tmp_e; + Word32 numer, denom; + + /* Jacobsen estimates peak offset relative y_0 using + * X_m1 - X_p1 + * d = REAL ( ------------------- ) * c_jacob + * 2*X_0 - X_m1 -Xp1 + * + * Where c_jacob is a window dependent constant + */ +#define C_JACOB 1.1453f /* % assume 0.1875 hammrect window 'symmetric' */ +#define C_JACOB_FX 18765 /* % assume 0.1875 hammrect window 'symmetric' */ /*Q14*/ + + /* Get the bin parameters into variables */ + pY = y_re; + y_m1_re = *pY++; + move16(); + y_0_re = *pY++; + move16(); + y_p1_re = *pY++; + move16(); + + /* Same for imaginary parts - note reverse order from FFT */ + pY = y_im; + y_p1_im = *pY++; + move16(); + y_0_im = *pY++; + move16(); + y_m1_im = *pY++; + move16(); + + /* prepare numerator real and imaginary parts*/ + N_re = sub( y_m1_re, y_p1_re ); + N_im = sub( y_m1_im, y_p1_im ); + + /* prepare denominator real and imaginary parts */ + + D_re = sub( sub( shl( y_0_re, 1 ), y_m1_re ), y_p1_re ); + D_im = sub( sub( shl( y_0_im, 1 ), y_m1_im ), y_p1_im ); + + /* REAL part of complex division */ + numer = L_add( L_mult0( N_re, D_re ), L_mult0( N_im, D_im ) ); + denom = L_add( L_mult0( D_re, D_re ), L_mult0( D_im, D_im ) ); + + test(); + IF( NE_32( numer, 0 ) && NE_32( denom, 0 ) ) + { + tmp = BASOP_Util_Divide3232_Scale( numer, denom, &tmp_e ); + tmp = shl( tmp, tmp_e ); // Q15 + posi = shl_sat( mult_r( tmp, C_JACOB_FX ), Q1 ); // Q15 + } + ELSE + { + posi = 0; /* flat top, division is not possible choose center freq */ + } + + return posi; +} +#else #ifdef IVAS_FEC_ECU_TO_COMPLETE /*----------------------------------------------------------------------------- * imax2_jacobsen_mag() @@ -182,6 +268,7 @@ static float imax2_jacobsen_mag( return posi; } #endif +#endif /*----------------------------------------------------------------------------- * fft_spec2_fx() @@ -577,36 +664,36 @@ static void trans_ana_fx( * * Peak-picking algorithm *----------------------------------------------------------------------------*/ -static void peakfinder_fx( - const Word16 *x0, /* i : vector from which the maxima will be found */ - const Word16 len0, /* i : length of input vector */ - Word16 *plocs, /* o : the indices of the identified peaks in x0 Q0 */ - Word16 *cInd, /* o : number of identified peaks Q0 */ - const Word16 sel /* i : The amount above surrounding data for a peak to be identified */ -#ifdef IVAS_FEC_ECU_TO_COMPLETE - ,const Word16 endpoints /* i : Flag to include endpoints in peak search */ -#endif +#ifdef IVAS_FLOAT_FIXED +static void ivas_peakfinder_fx( + const Word16 *x0, /* i : vector from which the maxima will be found */ + const Word16 len0, /* i : length of input vector */ + Word16 *plocs, /* o : the indices of the identified peaks in x0 Q0 */ + Word16 *cInd, /* o : number of identified peaks Q0 */ + const Word16 sel, /* i : The amount above surrounding data for a peak to be identified */ + const Word16 endpoints /* i : Flag to include endpoints in peak search */ ) { const Word16 *pX0; Word16 minMag, tempMag, leftMin; - Word16 dx0[L_PROT48k_2], x[L_PROT48k_2+1], peakMag[MAX_PLOCS]; + Word16 dx0[L_PROT48k_2], x[L_PROT48k_2 + 1], peakMag[MAX_PLOCS]; Word16 *pDx0, *pDx01, *pX; Word16 i, len, tempLoc, foundPeak, ii, xInd, tmp16, threshold, xAt0, xAt1, xAt2; Word16 len0Minus1, len0Minus2, lenMinus1; - Word16 indarr[L_PROT48k_2+1], peakLoc[MAX_PLOCS]; + Word16 indarr[L_PROT48k_2 + 1], peakLoc[MAX_PLOCS]; Word16 *pInd; tempLoc = 0; + move16(); /* Find derivative */ - len0Minus1 = sub(len0, 1); + len0Minus1 = sub( len0, 1 ); pX0 = x0 + 1; - Vr_subt(pX0, x0, dx0, len0Minus1); + Vr_subt( pX0, x0, dx0, len0Minus1 ); - FOR (i=0; i 0))) -#else - IF (GT_16(len, 2)) -#endif + test(); + test(); + IF( GT_16( len, 2 ) || ( !endpoints && ( GT_16( len, 0 ) ) ) ) { /* Set initial parameters for loop */ tempMag = minMag; @@ -676,81 +756,83 @@ static void peakfinder_fx( move16(); leftMin = minMag; move16(); - threshold = add(leftMin, sel); + threshold = add( leftMin, sel ); -#ifdef IVAS_FEC_ECU_TO_COMPLETE - IF(len > 0) -#endif + IF( GT_16( len, 0 ) ) { /* Deal with first point a little differently since tacked it on Calculate the sign of the derivative since we took the first point on it does not necessarily alternate like the rest. */ - /* The first point is larger or equal to the second */ + /* The first point is larger or equal to the second */ pX = x; xAt0 = *pX++; move16(); xAt1 = *pX++; move16(); - xAt2 = *pX--; /* After decrement, pX points to x[1]. */ move16(); - IF(GE_16(xAt0, xAt1)) + xAt2 = *pX--; /* After decrement, pX points to x[1]. */ + move16(); + IF( GE_16( xAt0, xAt1 ) ) { ii = -1; move16(); - IF(GE_16(xAt1, xAt2)) /* x[1] is not extremum -> overwrite with x[0] */ + IF( GE_16( xAt1, xAt2 ) ) /* x[1] is not extremum -> overwrite with x[0] */ { - *pX = xAt0; /* x[1] = x[0] */ move16(); + *pX = xAt0; /* x[1] = x[0] */ + move16(); tmp16 = *pInd++; move16(); - *pInd++ = tmp16; /* ind[1] = ind[0] */ move16(); - len = sub(len, 1); + *pInd++ = tmp16; /* ind[1] = ind[0] */ + move16(); + len = sub( len, 1 ); } pX--; /* After decrement, pX points to x[0]. */ } ELSE /* First point is smaller than the second */ { ii = 0; - IF(LT_16(xAt1, xAt2)) /* x[1] is not extremum -> overwrite with x[0] */ + IF( LT_16( xAt1, xAt2 ) ) /* x[1] is not extremum -> overwrite with x[0] */ { - *pX = xAt0; /* x[1] = x[0] */ move16(); + *pX = xAt0; /* x[1] = x[0] */ + move16(); tmp16 = *pInd++; move16(); - *pInd++ = tmp16; /* ind[1] = ind[0] */ move16(); - len = sub(len, 1); + *pInd++ = tmp16; /* ind[1] = ind[0] */ + move16(); + len = sub( len, 1 ); } } pX--; /* After decrement, pX points to either x[-1] or x[0]. */ } -#ifdef IVAS_FEC_ECU_TO_COMPLETE ELSE - { PMTE () + { + // PMTE () ii = -1; /* First point is a peak */ - if (len >= 2) + IF( GE_16( len, 2 ) ) { - if (x[1] >= x[0]) + IF( GE_16( x[1], x[0] ) ) { ii = 0; /* First point is a valley, skip it */ } } } -#endif *cInd = 0; move16(); /*Loop through extrema which should be peaks and then valleys*/ - lenMinus1 = sub(len, 1); - FOR (;;) + lenMinus1 = sub( len, 1 ); + FOR( ;; ) { - ii = add(ii, 1); /* This is a peak */ + ii = add( ii, 1 ); /* This is a peak */ /* Make sure we don't iterate past the length of our vector */ - IF (GE_16(ii, lenMinus1)) + IF( GE_16( ii, lenMinus1 ) ) { BREAK; } /*Reset peak finding if we had a peak and the next peak is bigger than the last or the left min was small enough to reset.*/ - IF (GT_16(foundPeak,0)) + IF( GT_16( foundPeak, 0 ) ) { tempMag = minMag; move16(); @@ -760,9 +842,9 @@ static void peakfinder_fx( /* Found new peak that was larger than temp mag and selectivity larger than the minimum to its left. */ - IF (GT_16(*(++pX), tempMag)) + IF( GT_16( *( ++pX ), tempMag ) ) { - IF ( GT_16(*pX, threshold)) /* threshold = leftMin + sel */ + IF( GT_16( *pX, threshold ) ) /* threshold = leftMin + sel */ { tempLoc = ii; move16(); @@ -771,78 +853,78 @@ static void peakfinder_fx( } } - ii = add(ii, 1); /* Move onto the valley */ + ii = add( ii, 1 ); /* Move onto the valley */ pX++; /* Come down at least sel from peak */ - IF (foundPeak == 0) + IF( EQ_16( foundPeak, 0 ) ) { - IF (GT_16(tempMag, add(sel, *pX))) + IF( GT_16( tempMag, add( sel, *pX ) ) ) { - foundPeak = 1; /* We have found a peak */ move16(); + foundPeak = 1; /* We have found a peak */ + move16(); leftMin = *pX; move16(); - threshold = add(leftMin, sel); - peakLoc[*cInd] = tempLoc; /* Add peak to index */ move16(); + threshold = add( leftMin, sel ); + peakLoc[*cInd] = tempLoc; /* Add peak to index */ + move16(); peakMag[*cInd] = tempMag; move16(); - *cInd = add(*cInd, 1); + *cInd = add( *cInd, 1 ); } } - IF (foundPeak == 0) /* The above IF-block has not found the peak yet. */ + IF( EQ_16( foundPeak, 0 ) ) /* The above IF-block has not found the peak yet. */ { - IF (LT_16(*pX, leftMin))/* New left minimum */ + IF( LT_16( *pX, leftMin ) ) /* New left minimum */ { leftMin = *pX; move16(); - threshold = add(leftMin, sel); + threshold = add( leftMin, sel ); } } } /* Check end point */ - IF (GT_16(x[lenMinus1], tempMag)) + IF( GT_16( x[lenMinus1], tempMag ) ) { - IF (GT_16(x[lenMinus1], threshold)) /* threshold = leftMin + sel */ + IF( GT_16( x[lenMinus1], threshold ) ) /* threshold = leftMin + sel */ { peakLoc[*cInd] = lenMinus1; move16(); peakMag[*cInd] = x[lenMinus1]; move16(); - *cInd = add(*cInd, 1); + *cInd = add( *cInd, 1 ); foundPeak = 1; move16(); } } - IF (foundPeak == 0) /* Check if we still need to add the last point */ + IF( EQ_16( foundPeak, 0 ) ) /* Check if we still need to add the last point */ { - IF (GT_16(tempMag, minMag)) + IF( GT_16( tempMag, minMag ) ) { peakLoc[*cInd] = tempLoc; move16(); peakMag[*cInd] = tempMag; move16(); - *cInd = add(*cInd, 1); + *cInd = add( *cInd, 1 ); } } /* Create output */ - FOR (i = 0; i < *cInd; i++) + FOR( i = 0; i < *cInd; i++ ) { - plocs[i] = *(indarr + peakLoc[i]); + plocs[i] = *( indarr + peakLoc[i] ); move16(); move16(); } } ELSE /* This is a monotone function where an endpoint is the only peak */ { -#ifdef IVAS_FEC_ECU_TO_COMPLETE - IF(endpoints) -#endif + IF( endpoints ) { xInd = 1; move16(); - if (GT_16(x[0], x[1])) + IF( GT_16( x[0], x[1] ) ) { xInd = 0; move16(); @@ -850,9 +932,9 @@ static void peakfinder_fx( peakMag[0] = x[xInd]; move16(); - IF(GT_16(peakMag[0], add(minMag, sel))) + IF( GT_16( peakMag[0], add( minMag, sel ) ) ) { - plocs[0] = *(indarr + xInd); + plocs[0] = *( indarr + xInd ); move16(); *cInd = 1; move16(); @@ -863,77 +945,372 @@ static void peakfinder_fx( move16(); } } -#ifdef IVAS_FEC_ECU_TO_COMPLETE ELSE - {/* Input constant or all zeros -- no peaks found */ + { /* Input constant or all zeros -- no peaks found */ *cInd = 0; move16(); } -#endif } } +#endif -/*----------------------------------------------------------------------------- -* imax_fx() -* -* Get interpolated maximum position -*-----------------------------------------------------------------------------*/ -static Word16 imax_fx( /* o: The location, relative to the middle of the 3 given data point, of the maximum. (Q15) */ - const Word16 *y, /* i: The 3 given data points. */ - const Word16 special /* i: -1 = left edge special case, 0 = normal, +1 = right edge special case */ +static void peakfinder_fx( + const Word16 *x0, /* i : vector from which the maxima will be found */ + const Word16 len0, /* i : length of input vector */ + Word16 *plocs, /* o : the indices of the identified peaks in x0 Q0 */ + Word16 *cInd, /* o : number of identified peaks Q0 */ + const Word16 sel /* i : The amount above surrounding data for a peak to be identified */ +#ifdef IVAS_FEC_ECU_TO_COMPLETE + ,const Word16 endpoints /* i : Flag to include endpoints in peak search */ +#endif ) { - Word16 posi; - Word16 y1, y2, y3, man, expo, edge; - const Word16 *pY; - Word32 numer, denom, sign, acc, y3_y1; -#ifdef BASOP_NOGLOB_DECLARE_LOCAL - Flag Overflow = 0; -#endif - /* Seek the extremum of the parabola P(x) defined by 3 consecutive points - so that P([-1 0 1]) = [y1 y2 y3] */ - pY = y; - y1 = *pY++, y2 = *pY++, y3 = *pY; - move16(); - move16(); - move16(); + const Word16 *pX0; + Word16 minMag, tempMag, leftMin; + Word16 dx0[L_PROT48k_2], x[L_PROT48k_2+1], peakMag[MAX_PLOCS]; + Word16 *pDx0, *pDx01, *pX; + Word16 i, len, tempLoc, foundPeak, ii, xInd, tmp16, threshold, xAt0, xAt1, xAt2; + Word16 len0Minus1, len0Minus2, lenMinus1; + Word16 indarr[L_PROT48k_2+1], peakLoc[MAX_PLOCS]; + Word16 *pInd; - /* The extremum value: - * y2i = -0.125f * SQR(y3_y1) / (y1+y3-2*y2)+y2 - * is not computed. Alternatively, the derivative of the parabola evaluated at y=0, - * dP/dy|y=0, is used to determine whether the extremum is maximum or not. - */ + tempLoc = 0; - /* Compute the extremum location: posi = (y3 - y1)/(4*y2 - 2*y1 - 2*y3). */ - y3_y1 = L_sub(y3, y1); - acc = L_shl(y2,1); /* N.B. y2 is multiplied by 2 not 4. */ - acc = L_sub(acc, y1); /* N.B. Y1 is not multiplied by 2. */ - denom = L_sub(acc, y3); /* N.B. Y3 is not multiplied by 2. */ - sign = L_xor(y3_y1, denom); /* Preserve the sign since div_s() only takes positive arguments. */ - numer = L_abs(y3_y1); - denom = L_abs(denom); - IF (numer == 0) - { - return 0; - } - IF (denom == 0) + /* Find derivative */ + len0Minus1 = sub(len0, 1); + pX0 = x0 + 1; + Vr_subt(pX0, x0, dx0, len0Minus1); + + FOR (i=0; i 0))) +#else + IF (GT_16(len, 2)) +#endif + { + /* Set initial parameters for loop */ + tempMag = minMag; + move16(); + foundPeak = 0; + move16(); + leftMin = minMag; + move16(); + threshold = add(leftMin, sel); + +#ifdef IVAS_FEC_ECU_TO_COMPLETE + IF(len > 0) +#endif + { + /* Deal with first point a little differently since tacked it on + Calculate the sign of the derivative since we took the first point + on it does not necessarily alternate like the rest. */ + + /* The first point is larger or equal to the second */ + pX = x; + xAt0 = *pX++; + move16(); + xAt1 = *pX++; + move16(); + xAt2 = *pX--; /* After decrement, pX points to x[1]. */ move16(); + IF(GE_16(xAt0, xAt1)) + { + ii = -1; + move16(); + IF(GE_16(xAt1, xAt2)) /* x[1] is not extremum -> overwrite with x[0] */ + { + *pX = xAt0; /* x[1] = x[0] */ move16(); + tmp16 = *pInd++; + move16(); + *pInd++ = tmp16; /* ind[1] = ind[0] */ move16(); + len = sub(len, 1); + } + pX--; /* After decrement, pX points to x[0]. */ + } + ELSE /* First point is smaller than the second */ + { + ii = 0; + IF(LT_16(xAt1, xAt2)) /* x[1] is not extremum -> overwrite with x[0] */ + { + *pX = xAt0; /* x[1] = x[0] */ move16(); + tmp16 = *pInd++; + move16(); + *pInd++ = tmp16; /* ind[1] = ind[0] */ move16(); + len = sub(len, 1); + } + } + pX--; /* After decrement, pX points to either x[-1] or x[0]. */ + } +#ifdef IVAS_FEC_ECU_TO_COMPLETE + ELSE + { PMTE () + ii = -1; /* First point is a peak */ + if (len >= 2) + { + if (x[1] >= x[0]) + { + ii = 0; /* First point is a valley, skip it */ + } + } + } +#endif + *cInd = 0; + move16(); + /*Loop through extrema which should be peaks and then valleys*/ + lenMinus1 = sub(len, 1); + FOR (;;) + { + ii = add(ii, 1); /* This is a peak */ + + /* Make sure we don't iterate past the length of our vector */ + IF (GE_16(ii, lenMinus1)) + { + BREAK; + } + + /*Reset peak finding if we had a peak and the next peak is bigger + than the last or the left min was small enough to reset.*/ + IF (GT_16(foundPeak,0)) + { + tempMag = minMag; + move16(); + foundPeak = 0; + move16(); + } + + /* Found new peak that was larger than temp mag and selectivity larger + than the minimum to its left. */ + IF (GT_16(*(++pX), tempMag)) + { + IF ( GT_16(*pX, threshold)) /* threshold = leftMin + sel */ + { + tempLoc = ii; + move16(); + tempMag = *pX; + move16(); + } + } + + ii = add(ii, 1); /* Move onto the valley */ + pX++; + + /* Come down at least sel from peak */ + IF (foundPeak == 0) + { + IF (GT_16(tempMag, add(sel, *pX))) + { + foundPeak = 1; /* We have found a peak */ move16(); + leftMin = *pX; + move16(); + threshold = add(leftMin, sel); + peakLoc[*cInd] = tempLoc; /* Add peak to index */ move16(); + peakMag[*cInd] = tempMag; + move16(); + *cInd = add(*cInd, 1); + } + } + IF (foundPeak == 0) /* The above IF-block has not found the peak yet. */ + { + IF (LT_16(*pX, leftMin))/* New left minimum */ + { + leftMin = *pX; + move16(); + threshold = add(leftMin, sel); + } + } + } + + /* Check end point */ + IF (GT_16(x[lenMinus1], tempMag)) + { + IF (GT_16(x[lenMinus1], threshold)) /* threshold = leftMin + sel */ + { + peakLoc[*cInd] = lenMinus1; + move16(); + peakMag[*cInd] = x[lenMinus1]; + move16(); + *cInd = add(*cInd, 1); + foundPeak = 1; + move16(); + } + } + IF (foundPeak == 0) /* Check if we still need to add the last point */ + { + IF (GT_16(tempMag, minMag)) + { + peakLoc[*cInd] = tempLoc; + move16(); + peakMag[*cInd] = tempMag; + move16(); + *cInd = add(*cInd, 1); + } + } + + /* Create output */ + FOR (i = 0; i < *cInd; i++) + { + plocs[i] = *(indarr + peakLoc[i]); + move16(); + move16(); + } + } + ELSE /* This is a monotone function where an endpoint is the only peak */ + { +#ifdef IVAS_FEC_ECU_TO_COMPLETE + IF(endpoints) +#endif + { + xInd = 1; + move16(); + if (GT_16(x[0], x[1])) + { + xInd = 0; + move16(); + } + + peakMag[0] = x[xInd]; + move16(); + IF(GT_16(peakMag[0], add(minMag, sel))) + { + plocs[0] = *(indarr + xInd); + move16(); + *cInd = 1; + move16(); + } + ELSE + { + *cInd = 0; + move16(); + } + } +#ifdef IVAS_FEC_ECU_TO_COMPLETE + ELSE + {/* Input constant or all zeros -- no peaks found */ + *cInd = 0; + move16(); + } +#endif + } +} + +/*----------------------------------------------------------------------------- +* imax_fx() +* +* Get interpolated maximum position +*-----------------------------------------------------------------------------*/ +static Word16 imax_fx( /* o: The location, relative to the middle of the 3 given data point, of the maximum. (Q15) */ + const Word16 *y, /* i: The 3 given data points. */ + const Word16 special /* i: -1 = left edge special case, 0 = normal, +1 = right edge special case */ +) +{ + Word16 posi; + Word16 y1, y2, y3, man, expo, edge; + const Word16 *pY; + Word32 numer, denom, sign, acc, y3_y1; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + /* Seek the extremum of the parabola P(x) defined by 3 consecutive points + so that P([-1 0 1]) = [y1 y2 y3] */ + pY = y; + y1 = *pY++, y2 = *pY++, y3 = *pY; + move16(); + move16(); + move16(); + + /* The extremum value: + * y2i = -0.125f * SQR(y3_y1) / (y1+y3-2*y2)+y2 + * is not computed. Alternatively, the derivative of the parabola evaluated at y=0, + * dP/dy|y=0, is used to determine whether the extremum is maximum or not. + */ + + /* Compute the extremum location: posi = (y3 - y1)/(4*y2 - 2*y1 - 2*y3). */ + y3_y1 = L_sub(y3, y1); + acc = L_shl(y2,1); /* N.B. y2 is multiplied by 2 not 4. */ + acc = L_sub(acc, y1); /* N.B. Y1 is not multiplied by 2. */ + denom = L_sub(acc, y3); /* N.B. Y3 is not multiplied by 2. */ + sign = L_xor(y3_y1, denom); /* Preserve the sign since div_s() only takes positive arguments. */ + numer = L_abs(y3_y1); + denom = L_abs(denom); + IF (numer == 0) + { + return 0; + } + IF (denom == 0) + { + return 0; + } + /* Although the output of ratio() is in Q14, adding the missing factor of 2 (See above) + * in the denominator, the output is now considered to be in Q15. */ + man = ratio(numer, denom, &expo); /* The mantissa is considered in Q15 */ +#ifdef BASOP_NOGLOB + posi = shr_o(man, expo, &Overflow); /* in Q15 (Due to saturation, it is automatically bound inside [-1.0,1.0].) */ +#else + posi = shr(man, expo); /* in Q15 (Due to saturation, it is automatically bound inside [-1.0,1.0].) */ +#endif + if (sign < 0) /* Restore the sign. */ + { + posi = negate(posi); + } + + /* For both edges (left and right), the extremum found above may be minimum. * It needs to reject the minimum. */ IF (NE_16(special,0)) /* Either edge specical case. */ { @@ -972,14 +1349,384 @@ static Word16 imax_fx( /* o: The location, relative to the middle of the 3 given } } } - return posi; /* Q15. The position either left or right relative to the index of the middle of the 3 given data points. */ + return posi; /* Q15. The position either left or right relative to the index of the middle of the 3 given data points. */ +} + +/*----------------------------------------------------------------------------- +* spec_ana_fx() +* +* Spectral analysis +*-----------------------------------------------------------------------------*/ + +#ifdef IVAS_FLOAT_FIXED +static void ivas_spec_ana_fx( + const Word16 *prevsynth, /* i : Input signal */ + Word16 *plocs, /* o : The indicies of the identified peaks Q0 */ + Word32 *plocsi, /* o : Interpolated positions of the identified peaks Q16 */ + Word16 *num_plocs, /* o : Number of identified peaks Q0 */ + Word16 *X_sav, /* o : Stored fft spectrum */ + const Word16 output_frame, /* i : Frame length Q0 */ + const Word16 bwidth_fx, /* i : Encoded bandwidth index Q0 */ + Word16 *Q, /* o : Q value of the fft spectrum */ + const Word16 element_mode, /* i : IVAS element mode */ + Word16 *noise_fac, /* o : for few peaks zeroing valleys decision making */ + const Word16 pcorr ) +{ + Word16 Lprot, LprotLog2Minus1 = 0, hamm_len2 = 0, Lprot2, Lprot2_1, m, n; + const Word16 *pFftTbl = NULL; + Word16 xfp[L_PROT48k]; + Word32 magSq[L_PROT48k / 2 + 1], *pMagSq; + Word16 *pXfp, *pXfp1, *pXsav, *pPlocs; + Word16 Xmax, Xmin, sel, man, expo, expoBy2; + Word16 sinTblOffset, rectLength, fraction, special; + Word32 *pPlocsi; + Word32 acc; + Word16 stop_band_start; + Word16 stop_band_length; + const Word16 *w_hamm = NULL; + Word16 window_corr, window_corr_step; + Word16 currPlocs, endPlocs, nJacob, k, i; + Word32 sig, noise, st_point, end_point; + + Lprot = 512; /* 1536=(2*output_frame)*1024/1280; */ + move16(); + + sinTblOffset = 0; + + IF( EQ_16( output_frame, L_FRAME48k ) ) + { + Lprot = L_PROT48k; /* 1536=(2*output_frame)*1024/1280; */ + move16(); + hamm_len2 = L_PROT_HAMM_LEN2_48k; /* half Hamming window = 288 */ + move16(); + w_hamm = w_hamm_sana48k_2_fx; + } + ELSE IF( EQ_16( output_frame, L_FRAME32k ) ) + { + Lprot = L_PROT32k; /* 1024 */ + move16(); + sinTblOffset = 4; + move16(); + hamm_len2 = L_PROT_HAMM_LEN2_32k; /* half Hamming window = 192 */ + move16(); + pFftTbl = FFT_W512; /* Table for 1024-point real input FFT */ + LprotLog2Minus1 = 9; /* FFT stages for complex input FFT */ + move16(); + w_hamm = w_hamm_sana32k_2_fx; + } + ELSE + { + Lprot = 512; + move16(); + sinTblOffset = 8; + move16(); + hamm_len2 = L_PROT_HAMM_LEN2_16k; /* half Hamming window = 96 */ + move16(); + pFftTbl = FFT_W256; /* Table for 512-point real input FFT */ + LprotLog2Minus1 = 8; /* FFT stages for complex input FFT */ + move16(); + w_hamm = w_hamm_sana16k_2_fx; + } + + Lprot2 = shr( Lprot, 1 ); + Lprot2_1 = add( Lprot2, 1 ); + rectLength = sub( Lprot, shl( hamm_len2, 1 ) ); /* The length of the rectangular portion of the Hamming-Rectangular window. */ + + *Q = s_max( 0, sub( Exp16Array( Lprot, prevsynth ), 1 ) ); + move16(); + Copy_Scale_sig( prevsynth, xfp, Lprot, *Q ); + + + IF( EQ_16( output_frame, L_FRAME48k ) ) + { + /* Apply hamming-rect window */ + IF( EQ_16( element_mode, EVS_MONO ) ) + { + windowing( xfp, xfp, w_hamm_sana48k_2_fx, rectLength, hamm_len2 ); + } + ELSE + { + // PMTE() + window_corr = w_hamm[0]; + window_corr_step = w_hamm[0] / hamm_len2; + FOR( i = 0; i < hamm_len2; i++ ) + { + xfp[i] = mult_r( shl( prevsynth[i], *Q ), sub( w_hamm[i], window_corr ) ); + move16(); + xfp[Lprot - i - 1] = mult_r( shl( prevsynth[Lprot - i - 1], *Q ), sub( w_hamm[i], window_corr ) ); + move16(); + window_corr = sub( window_corr, window_corr_step ); + } + } + /* Spectrum */ + fft3_fx( xfp, xfp, Lprot ); + } + ELSE + { + IF( EQ_16( element_mode, EVS_MONO ) ) + { + /* Apply hamming-rect window */ + windowing_ROM_optimized( xfp, xfp, sinTblOffset, rectLength, hamm_len2 ); + } + ELSE + { + // PMTE() + window_corr = w_hamm[0]; + window_corr_step = w_hamm[0] / hamm_len2; + FOR( i = 0; i < hamm_len2; i++ ) + { + xfp[i] = mult_r( shl( prevsynth[i], *Q ), sub( w_hamm[i], window_corr ) ); + move16(); + xfp[Lprot - i - 1] = mult_r( shl( prevsynth[Lprot - i - 1], *Q ), sub( w_hamm[i], window_corr ) ); + move16(); + window_corr = sub( window_corr, window_corr_step ); + } + } + /* Spectrum */ + r_fft_fx_lc( pFftTbl, Lprot, Lprot2, LprotLog2Minus1, xfp, xfp, 1 ); + } + + /* Apply zeroing of non-coded FFT spectrum */ + IF( GT_16( output_frame, inner_frame_tbl[bwidth_fx] ) ) + { + stop_band_start = shl( 128, bwidth_fx ); + stop_band_length = sub( Lprot, shl( stop_band_start, 1 ) ); + stop_band_start = add( stop_band_start, 1 ); + set16_fx( xfp + stop_band_start, 0, stop_band_length ); + } + + pXfp = xfp; + pXsav = X_sav; + + FOR( m = 0; m < Lprot; m++ ) + { + *pXsav++ = *pXfp++; + move16(); + } + + /* Magnitude representation */ + fft_spec2_fx( xfp, magSq, Lprot ); + + /* Compute xfp[m] = sqrt(magSq[m]) */ + pXfp = xfp; + pMagSq = magSq; + FOR( m = 0; m < Lprot2_1; m++ ) + { + IF( *pMagSq == 0 ) + { + *pXfp++ = extract_l( *pMagSq++ ); /* magSq[] is zero */ + } + ELSE + { + expo = norm_l( *pMagSq ); /* exponent */ + man = extract_h( L_shl( *pMagSq++, expo ) ); /* mantissa */ + man = sqrt2ndOrder( man ); + expoBy2 = shr( expo, 1 ); /* Divided by 2-- square root operation. */ + IF( s_and( expo, 1 ) == 0 ) /* Check even or odd. */ + { + man = mult_r( man, FEC_HQ_ECU_ROOT2 ); /* FEC_HQ_ECU_ROOT2 is sqrt(2) in Q14 */ + expoBy2 = sub( expoBy2, 1 ); + } + *pXfp++ = shr( man, expoBy2 ); + move16(); /* Denormalize the mantissa back to Q0. */ + } + } + + /* Find maximum and minimum. */ + maximum_fx( xfp, Lprot2_1, &Xmax ); + minimum_fx( xfp, Lprot2_1, &Xmin ); + IF( EQ_16( element_mode, EVS_MONO ) ) + { + sel = mult_r( sub( Xmax, Xmin ), CMPLMNT_PFIND_SENS_FX ); + } + ELSE + { + sel = mult_r( sub( Xmax, Xmin ), CMPLMNT_ST_PFIND_SENS_FX ); + } + ivas_peakfinder_fx( xfp, Lprot2_1, plocs, num_plocs, sel, TRUE ); + + + /* Currently not the pitch correlation but some LF correlation */ + IF( element_mode != EVS_MONO && *num_plocs > 50 && pcorr < 19661 /* 0.6f in Q15 */ ) + { + *num_plocs = 0; + } + + IF( EQ_16( element_mode, EVS_MONO ) ) + { + + /* Refine peaks */ + pPlocsi = plocsi; + pPlocs = plocs; + n = sub( *num_plocs, 1 ); /* -1 so as to exclude the very last peak. */ + /* Special case-- The very 1st peak if it is at 0 index position */ + IF( EQ_16( *pPlocs, 0 ) ) /* Only the very 1st peak is possible the peak at 0 index position. */ + { + fraction = imax_fx( xfp, -1 ); /* -1 signifies special left edge case. */ + acc = L_deposit_h( *pPlocs++ ); /* N.B., (*pPlocs) must be zero here. */ + *pPlocsi++ = L_mac( acc, fraction, 1 ); + move32(); /* in Q16 */ + n = sub( n, 1 ); /* This special case is taken care of-- one less to go */ + } + /* All peaks except the very last peak but including the very 1st one if it has not been taken care of. */ + pXfp1 = xfp - 1; + FOR( m = 0; m < n; m++ ) /* Loop through up to the last but one peak. (The last one is excluded.) */ + { + pXfp = pXfp1 + *pPlocs; + fraction = imax_fx( pXfp, 0 ); /* in Q15 */ + acc = L_deposit_h( *pPlocs++ ); + *pPlocsi++ = L_mac( acc, fraction, 1 ); + move32(); /* in Q16. Append the fractional part to the integral part. */ + } + IF( n >= 0 ) + { + /* Special case-- The very last peak */ + pXfp = pXfp1 + *pPlocs; + IF( EQ_16( *pPlocs, Lprot2 ) ) /* Only the very last peak is possible the peak at Lprot2 index position. */ + { + pXfp--; /* Special case needs extra decrement */ + special = 1; /* Signify special right edge case. */ + move16(); + } + ELSE + { + special = 0; + move16(); + } + fraction = imax_fx( pXfp, special ); /* in Q15 */ + acc = L_deposit_h( *pPlocs ); + *pPlocsi = L_mac( acc, fraction, 1 ); + move32(); /* in Q16. Append the fractional part to the integral part. */ + } + } + ELSE + { + Lprot2 = shr( Lprot, 1 ); + Lprot2_1 = add( Lprot2, 1 ); + + /* Refine peaks */ + pPlocsi = plocsi; + pPlocs = plocs; + n = *num_plocs; /* number of peaks to process */ + move16(); + + /* Special case-- The very 1st peak if it is at 0 index position (DC) */ + /* With DELTA_CORR_F0_INT == 2 one needs to handle both *pPlocs==0 and *pPlocs==1 */ + //IF( n > 0 && *pPlocs == 0 ) /* Very 1st peak position possible to have a peak at 0/DC index position. */ + test(); + IF( GT_16( n, 0 ) && EQ_16( *pPlocs, 0 ) ) /* Very 1st peak position possible to have a peak at 0/DC index position. */ + { + fraction = imax_fx( &xfp[*pPlocs], -1 ); /* in Q15 */ + acc = L_deposit_h( *pPlocs ); + *pPlocsi++ = L_mac( acc, fraction, 1 ); + move32(); + pPlocs++; + n = sub( n, 1 ); + } + + test(); + IF( GT_16( n, 0 ) && EQ_16( *pPlocs, 1 ) ) /* Also 2nd peak position uses DC which makes jacobsen unsuitable. */ + { + fraction = imax_fx( &xfp[*pPlocs - 1], -1 ); /* in Q15 */ + acc = L_deposit_h( *pPlocs - 1 ); + *pPlocsi++ = L_mac( acc, fraction, 1 ); + move32(); + currPlocs = *pPlocs++; + move16(); + n = sub( n, 1 ); + } + + /* All remaining peaks except the very last two possible integer positions */ + currPlocs = *pPlocs++; + move16(); + endPlocs = sub( Lprot2_1, DELTA_CORR_F0_INT ); /* last *pPlocs position for Jacobsen */ + + /* precompute number of turns based on endpoint integer location and make into a proper for loop */ + IF( GT_16( n, 0 ) ) + { + nJacob = n; + move16(); + IF( LE_16( sub( endPlocs, plocs[sub( *num_plocs, 1 )] ), 0 ) ) + { + nJacob = sub( nJacob, 1 ); + } + + FOR( k = 0; k < nJacob; k++ ) + { + fraction = ivas_imax2_jacobsen_mag_fx( &( X_sav[currPlocs - 1] ), &( X_sav[Lprot - 1 - currPlocs] ) ); /* in Q15 */ + acc = L_deposit_h( currPlocs ); + *pPlocsi++ = L_mac( acc, fraction, 1 ); + move32(); + currPlocs = *pPlocs++; + move16(); + } + n = sub( n, nJacob ); + } + + /* At this point there should at most two plocs left to process */ + /* the position before fs/2 and fs/2 both use the same magnitude points */ + IF( GT_16( n, 0 ) ) + { + /* [ . . . . . . . ] Lprot/2+1 positions */ + /* | | | */ + /* 0 (Lprot/2-2) (Lprot/2) */ + + IF( EQ_16( currPlocs, ( sub( Lprot2_1, DELTA_CORR_F0_INT ) ) ) ) /* Also 2nd last peak position uses fs/2 which makes jacobsen less suitable. */ + { + fraction = imax_fx( &xfp[currPlocs - 1], 0 ); /* in Q15 */ + acc = L_deposit_h( currPlocs - 1 ); + *pPlocsi++ = L_mac( acc, fraction, 1 ); + move32(); + currPlocs = *pPlocs++; + move16(); + n = sub(n, 1); + } + + /* Here the only remaining point would be a fs/2 plocs */ + /* pXfp = xfp + sub(Lprot2,1); already set just a reminder where it + * whould point */ + IF( GT_16( n, 0 ) ) /* fs/2 which makes special case . */ + { + fraction = imax_fx( &xfp[currPlocs - 2], 0 ); /* in Q15 */ + acc = L_deposit_h( currPlocs - 2 ); + *pPlocsi++ = L_mac( acc, fraction, 1 ); + move32(); + currPlocs = *pPlocs++; + move16(); + n = sub( n, 1 ); + } + } + + /* For few peaks decide noise floor attenuation */ + test(); + IF( LT_16( *num_plocs, 3 ) && GT_16( *num_plocs, 0 ) ) + { + sig = sum16_32_fx( xfp, Lprot2_1 ) + 1; + + /*excluding peaks and neighboring bins*/ + FOR( i = 0; i < *num_plocs; i++ ) + { + st_point = s_max( 0, plocs[i] - DELTA_CORR ); + end_point = s_min( Lprot2_1 - 1, plocs[i] + DELTA_CORR ); + set16_fx( &xfp[st_point], 0, (Word16) ( end_point - st_point + 1 ) ); + } + noise = sum16_32_fx( xfp, Lprot2_1 ) + 1; + + IF( LT_32( noise, Mpy_32_32( 64424509 /* 0.03 in Q31 */, sig ) ) ) + { + *noise_fac = 16384; /* 0.5f in Q15 */ + move16(); + } + ELSE + { + *noise_fac = 32767; /* 1.0f in Q15 */ + move16(); + } + } + } } +#endif -/*----------------------------------------------------------------------------- -* spec_ana_fx() -* -* Spectral analysis -*-----------------------------------------------------------------------------*/ static void spec_ana_fx( const Word16* prevsynth, /* i : Input signal */ Word16* plocs, /* o : The indicies of the identified peaks Q0 */ @@ -1307,24 +2054,418 @@ static void spec_ana_fx( noise = sum_f(xfp, Lprot2_1) + EPSILON; nsr = noise / sig; - if (nsr < 0.03f) - { - *noise_fac = 0.5f; - } - else - { - *noise_fac = 1.0f; - } + if (nsr < 0.03f) + { + *noise_fac = 0.5f; + } + else + { + *noise_fac = 1.0f; + } + } + } +#endif +} + +/*-------------------------------------------------------------------* +* subst_spec_fx() +* +* Substitution spectrum calculation +*-------------------------------------------------------------------*/ + +#ifdef IVAS_FLOAT_FIXED +static void ivas_subst_spec_fx( + const Word16 *plocs, /* i : The indices of the identified peaks Q0 */ + const Word32 *plocsi, /* i : Interpolated positions of the identified peaks Q16 */ + Word16 *num_plocs, /* i/o : Number of identified peaks Q0 */ + const Word16 time_offs, /* i : Time offset Q0 */ + Word16 *X, /* i/o : FFT spectrum */ + const Word16 *mag_chg, /* i : Magnitude modification Q15 */ + const Word16 ph_dith, /* i : Phase dither, 2*PI is not included. (Q15, i.e., between 0.0 and 1.0) */ + const Word16 *is_trans, /* i : Transient flags (either 0 or 1) */ + const Word16 output_frame, /* i : Frame length Q0 */ + Word16 *seed, /* i/o : Random seed */ + const Word16 *alpha, /* i : Magnitude modification factors for fade to average Q15 */ + const Word16 *beta, /* i : Magnitude modification factors for fade to average Q15 */ + Word16 beta_mute, /* i : Factor for long-term mute Q15 */ + const Word16 *Xavg, /* i : Frequency group averages to fade to Q0 */ + const Word16 element_mode, /* i : IVAS element mode */ + const Word16 ph_ecu_lookahead, /* i : Phase ECU lookahead */ + const Word16 noise_fac /* i : noise factor Q15 */ +) +{ + Word16 Xph_short; + Word32 corr_phase[MAX_PLOCS], Xph; + Word32 *pCorrPhase; + Word16 cos_F, sin_F, tmp; + Word16 Lprot, m, i, e, im_ind, delta_corr_up, delta_corr_dn, delta_tmp; + UWord16 lsb; + Word16 j, re, im, *pReX, *pImX, lastPeak, lprotBy2Minus1, segmentLen; + Word16 pkLocation_1, pkLocation, pkLocation1; + const Word16 *pPlocs; + const Word32 *pPlocsi; + Word32 acc; + Word16 Lecu; + Word16 Lprot_inv; + Word16 k; + Word16 tmp2; + Word16 alpha_local; + Word16 beta_local; + Word16 expo; + Word16 one_peak_flag_mask; + Word16 mag_chg_local; /*for peak attenuation in burst */ + + Lprot = 512; + move16(); + Lprot_inv = 8192; + move16(); + Lecu = shl( output_frame, 1 ); + + IF( EQ_16( output_frame, L_FRAME48k ) ) + { + Lprot = L_PROT48k; /* 1536=(2*output_frame)*1024/1280; */ + move16(); + Lprot_inv = 2731; /* Q22 */ + move16(); + } + ELSE IF( EQ_16( output_frame, L_FRAME32k ) ) + { + Lprot = L_PROT32k; /* 1024 */ + move16(); + Lprot_inv = 4096; /* Q22 */ + move16(); + } + ELSE + { + Lprot = 512; + move16(); + Lprot_inv = 8192; /* Q22 */ + move16(); + } + + /* Correction phase of the identified peaks */ + IF( s_or( is_trans[0], is_trans[1] ) != 0 ) + { + *num_plocs = 0; + move16(); + } + ELSE + { + // tmp = NS2SA(output_frame*50,PH_ECU_ALDO_OLP2_NS-PH_ECU_LOOKAHEAD_NS); + tmp = NS2SA( output_frame * 50, PH_ECU_ALDO_OLP2_NS ); + tmp = sub( tmp, ph_ecu_lookahead ); + tmp = add( tmp, sub( Lecu, shr( sub( Lecu, Lprot ), 1 ) ) ); + tmp = sub( tmp, shr( output_frame, 1 ) ); + tmp = add( tmp, time_offs ); + tmp = round_fx( L_shl( L_mult0( tmp, Lprot_inv ), 4 ) ); /* 0+22+4-16=10 */ + + pPlocsi = plocsi; + pCorrPhase = corr_phase; + FOR( m = 0; m < *num_plocs; m++ ) + { + Mpy_32_16_ss( *pPlocsi++, tmp, &acc, &lsb ); /* plocsi[] in Q16, tmp in Q10 and tmp does not include 2*PI. */ + acc = L_add( L_shl( acc, 5 ), lshr( lsb, 11 ) ); + *pCorrPhase++ = acc; /* in Q16. 2*PI is not included. */ + move32(); + } + } + one_peak_flag_mask = 32767 /* 1.0f in Q15 */; /* all ones mask -> keep */ + move16(); + IF( NE_16( element_mode, EVS_MONO ) ) + { + test(); + IF( ( GT_16( *num_plocs, 0 ) ) && LT_16( sub( *num_plocs, 3 ), 0 ) ) + { + one_peak_flag_mask = noise_fac; /* all zeroes mask -> zero */ + move16(); + } + IF( EQ_16( *num_plocs, 0 ) ) + { + X[0] = 0; /* reset DC if there are no peaks */ + move16(); + X[shr( Lprot, 1 )] = 0; /* also reset fs/2 if there are no peaks */ + move16(); + } + } + lprotBy2Minus1 = sub( shr( Lprot, 1 ), 1 ); + i = 1; + move16(); + k = 0; + move16(); + im_ind = sub( Lprot, 1 ); + move16(); + pReX = X + i; + pImX = X + im_ind; + pPlocs = plocs; + pCorrPhase = corr_phase; + pkLocation = *pPlocs; /* N.B. No post-increment */ + move16(); + pkLocation1 = *pPlocs++; + move16(); + lastPeak = sub( *num_plocs, 1 ); + FOR( m = 0; m < *num_plocs; m++ ) + { + delta_corr_dn = DELTA_CORR; + move16(); + delta_corr_up = DELTA_CORR; + move16(); + + pkLocation_1 = pkLocation; /* plocs[m - 1] */ + move16(); + pkLocation = pkLocation1; /* plocs[m] */ + move16(); + pkLocation1 = *pPlocs++; /* plocs[m + 1] */ + move16(); + IF( GT_16( m, 0 ) ) + { + delta_tmp = shr( sub( sub( pkLocation, pkLocation_1 ), 1 ), 1 ); + IF( LT_16( delta_tmp, DELTA_CORR ) ) + { + delta_corr_dn = delta_tmp; + move16(); + } + } + + IF( LT_16( m, lastPeak ) ) + { + delta_tmp = shr( sub( sub( pkLocation1, pkLocation ), 1 ), 1 ); + IF( LT_16( delta_tmp, DELTA_CORR ) ) + { + delta_corr_up = delta_tmp; + move16(); + } + } + + /* Input Xph */ + segmentLen = sub( sub( pkLocation, delta_corr_dn ), i ); + /* i = add(i, segmentLen); */ + FOR( j = 0; j < segmentLen; j++ ) + { + *seed = rand_phase_fx( *seed, &sin_F, &cos_F ); + + re = *pReX; + move16(); + im = *pImX; + move16(); + IF( EQ_16( element_mode, EVS_MONO ) ) + { + tmp = sub( mult_r( re, cos_F ), mult_r( im, sin_F ) ); + im = add( mult_r( re, sin_F ), mult_r( im, cos_F ) ); + } + ELSE + { + tmp = mult_r( one_peak_flag_mask, sub( mult_r( re, cos_F ), mult_r( im, sin_F ) ) ); + im = mult_r( one_peak_flag_mask, add( mult_r( re, sin_F ), mult_r( im, cos_F ) ) ); + } + IF( LT_16( alpha[k], 32766 ) ) + { + *seed = rand_phase_fx( *seed, &sin_F, &cos_F ); + tmp2 = mult_r( beta[k], Xavg[k] ); + *pReX++ = add( mult_r( alpha[k], tmp ), mult_r( tmp2, cos_F ) ); + move16(); + *pImX-- = add( mult_r( alpha[k], im ), mult_r( tmp2, sin_F ) ); + move16(); + } + ELSE + { + *pReX++ = mult_r( mag_chg[k], tmp ); + move16(); + *pImX-- = mult_r( mag_chg[k], im ); + move16(); + } + i = add( i, 1 ); + IF( GE_16( i, ivas_gwlpr[k + 1] ) ) + { + k = add( k, 1 ); + } + } + + e = add( pkLocation, delta_corr_up ); + IF( GT_16( e, lprotBy2Minus1 ) ) + { + e = lprotBy2Minus1; + move16(); + } + + Xph = *pCorrPhase; + Xph_short = s_and( extract_l( L_shr( Xph, 16 - 10 ) ), 0x3ff ); /* 10 bits precision after radix point */ + IF( GE_16( Xph_short, 512 ) ) + { + sin_F = negate( sincos_t_ext_fx[Xph_short - 512] ); + IF( LT_16( Xph_short, 768 ) ) + { + cos_F = negate( sincos_t_ext_fx[Xph_short - ( 512 - 256 )] ); + } + ELSE + { + cos_F = sincos_t_ext_fx[-Xph_short + ( 1024 + 256 )]; + move16(); + } + } + ELSE + { + sin_F = sincos_t_ext_fx[Xph_short]; + move16(); + IF( LT_16( Xph_short, 256 ) ) + { + cos_F = sincos_t_ext_fx[Xph_short + 256]; + move16(); + } + ELSE + { + cos_F = negate( sincos_t_ext_fx[-Xph_short + ( 256 + 512 )] ); + } + } + + segmentLen = add( sub( e, i ), 1 ); + /* i = add(i, segmentLen); */ + FOR( j = 0; j < segmentLen; j++ ) + { + mag_chg_local = mag_chg[k]; + move16(); + IF( NE_16( ph_dith, 0 ) ) + { + Xph = *pCorrPhase; /* in Q16. 2*PI is not included. */ + *seed = own_random2_fx( *seed ); /* in Q0 */ + acc = L_mult( *seed, ph_dith ); /* N.B. ph_dith[i] is in Q15, i.e., in between 0 and 1.0 (2*PI not included) */ + acc = L_shr( acc, PHASE_DITH_SCALE_SHIFT ); + Xph = L_add( Xph, acc ); /* in Q16. */ + + IF( GT_16( ph_dith, 0 ) ) /* up to 6 dB additional att of peaks in non_transient longer bursts, (when peak phase is randomized ) */ + { + /* mag_chg_local *= 0.5 + (1.0 - ph_dith[i])/2 where 0.5~= sqrt((float)pow(10.0,-6/10.0)) and ph_dith=0..1.0--> scale=1.0 ...5 */ + mag_chg_local = mult_r( mag_chg_local, sub( 32767, shr( ph_dith, 1 ) ) ); + } + Xph_short = s_and( extract_l( L_shr( Xph, 16 - 10 ) ), 0x3ff ); + IF( GE_16( Xph_short, 512 ) ) + { + sin_F = negate( sincos_t_ext_fx[Xph_short - 512] ); + IF( LT_16( Xph_short, 768 ) ) + { + cos_F = negate( sincos_t_ext_fx[Xph_short - ( 512 - 256 )] ); + } + ELSE + { + cos_F = sincos_t_ext_fx[-Xph_short + ( 1024 + 256 )]; + move16(); + } + } + ELSE + { + sin_F = sincos_t_ext_fx[Xph_short]; + move16(); + IF( LT_16( Xph_short, 256 ) ) + { + cos_F = sincos_t_ext_fx[Xph_short + 256]; + move16(); + } + ELSE + { + cos_F = negate( sincos_t_ext_fx[-Xph_short + ( 256 + 512 )] ); + } + } + } + + re = *pReX; + move16(); + im = *pImX; + move16(); + tmp = sub( mult_r( re, cos_F ), mult_r( im, sin_F ) ); + im = add( mult_r( re, sin_F ), mult_r( im, cos_F ) ); + IF( LT_16( alpha[k], 32766 ) ) + { + alpha_local = mag_chg_local; + move16(); + + acc = L_sub( 1073741824L, L_mult0( alpha_local, alpha_local ) ); + acc = Sqrt_l( acc, &expo ); + expo = add( 30, add( 31, expo ) ); + IF( EQ_16( s_and( expo, 1 ), 1 ) ) + { + acc = Mult_32_16( acc, 23170 ); /* 1/sqrt(2) in Q15 */ + } + expo = shr( expo, 1 ); + beta_local = mult_r( beta_mute, round_fx( L_shl( acc, sub( 31, expo ) ) ) ); + + IF( GE_16( k, LGW32K - 1 ) ) + { + beta_local = mult_r( beta_local, 3277 ); /* 0.1 in Q15 */ + } + ELSE IF( GE_16( k, LGW16K - 1 ) ) + { + beta_local = mult_r( beta_local, 16384 ); /* 0.5 in Q15 */ + } + + *seed = rand_phase_fx( *seed, &sin_F, &cos_F ); + tmp2 = mult_r( beta_local, Xavg[k] ); + *pReX++ = add( mult_r( alpha_local, tmp ), mult_r( tmp2, cos_F ) ); + move16(); + *pImX-- = add( mult_r( alpha_local, im ), mult_r( tmp2, sin_F ) ); + move16(); + } + ELSE + { + *pReX++ = mult_r( mag_chg_local, tmp ); + move16(); + *pImX-- = mult_r( mag_chg_local, im ); + move16(); + } + + i = add( i, 1 ); + IF( GE_16( i, ivas_gwlpr[k + 1] ) ) + { + k = add( k, 1 ); + } + } + pCorrPhase++; + } + + segmentLen = sub( shr( Lprot, 1 ), i ); + FOR( j = 0; j < segmentLen; j++ ) + { + *seed = rand_phase_fx( *seed, &sin_F, &cos_F ); + + re = *pReX; + move16(); + im = *pImX; + move16(); + + + IF( EQ_16( element_mode, EVS_MONO ) ) + { + tmp = sub( mult_r( re, cos_F ), mult_r( im, sin_F ) ); + im = add( mult_r( re, sin_F ), mult_r( im, cos_F ) ); + } + ELSE + { + tmp = mult_r( one_peak_flag_mask, sub( mult_r( re, cos_F ), mult_r( im, sin_F ) ) ); + im = mult_r( one_peak_flag_mask, add( mult_r( re, sin_F ), mult_r( im, cos_F ) ) ); + } + IF( LT_16( alpha[k], 32766 ) ) + { + *seed = rand_phase_fx( *seed, &sin_F, &cos_F ); + tmp2 = mult_r( beta[k], Xavg[k] ); + *pReX++ = add( mult_r( alpha[k], tmp ), mult_r( tmp2, cos_F ) ); + move16(); + *pImX-- = add( mult_r( alpha[k], im ), mult_r( tmp2, sin_F ) ); + move16(); + } + ELSE + { + *pReX++ = mult_r( mag_chg[k], tmp ); + move16(); + *pImX-- = mult_r( mag_chg[k], im ); + move16(); + } + + i = add( i, 1 ); + IF( GE_16( i, ivas_gwlpr[k + 1] ) ) + { + k = add( k, 1 ); } } -#endif } - -/*-------------------------------------------------------------------* -* subst_spec_fx() -* -* Substitution spectrum calculation -*-------------------------------------------------------------------*/ +#endif static void subst_spec_fx( const Word16 *plocs, /* i : The indices of the identified peaks Q0 */ @@ -1723,6 +2864,142 @@ static void subst_spec_fx( * Windowing and TDA of reconstructed frame *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +static void ivas_rec_wtda_fx( + Word16 *X, /* i : FFT spectrum */ + Word32 *ecu_rec, /* o : Reconstructed frame in tda domain */ + const Word16 output_frame, /* i : Frame length */ + const Word16 Lprot, /* i : Prototype frame length */ + const Word16 old_dec[270], /* i : end of last decoded for OLA before tda and itda */ + const Word16 element_mode, /* i : IVAS element mode */ + const Word16 *num_p, /* i : Number of peaks */ + const Word16 *plocs /* i : Peak locations */ +) +{ + Word16 timesh; + Word16 Qin; + Word16 xf_len; + Word16 i, idx; + Word16 *p_ecu; + Word16 g; + Word16 tbl_delta; + Word16 xsubst_[2 * L_FRAME48k]; + const Word16 *w_hamm; + Word16 *pX_start, *pX_end; + Word16 tmp, tmp_e; + Word16 hamm_len2; + Word16 *pNew; + const Word16 *pOldW, *pNewW; + Word16 xfwin[NS2SA( L_FRAME48k * FRAMES_PER_SEC, N_ZERO_MDCT_NS - ( 2 * FRAME_SIZE_NS - L_PROT_NS ) / 2 )]; + const Word16 *pOld; + Word16 copy_len; + Word16 ola_len; + + copy_len = NS2SA( output_frame * FRAMES_PER_SEC, ( 2 * FRAME_SIZE_NS - L_PROT_NS ) / 2 ); /* prototype fill on each side of xsubst to fill MDCT Frame */ + ola_len = NS2SA( output_frame * FRAMES_PER_SEC, N_ZERO_MDCT_NS - ( 2 * FRAME_SIZE_NS - L_PROT_NS ) / 2 ); /* remaining lengt of LA_ZEROS to overlap add decoded with xsubst */ + + xf_len = 26; + move16(); + tbl_delta = 10082; /* Q12 */ + move16(); + IF( EQ_16( output_frame, L_FRAME48k ) ) + { + w_hamm = w_hamm_sana48k_2_fx; + hamm_len2 = L_PROT_HAMM_LEN2_48k; + xf_len = 78; + move16(); + tbl_delta = 3361; /* Q12 */ + move16(); + } + ELSE IF( EQ_16( output_frame, L_FRAME32k ) ) + { + w_hamm = w_hamm_sana32k_2_fx; + hamm_len2 = L_PROT_HAMM_LEN2_32k; + xf_len = 52; + move16(); + tbl_delta = 5041; /* Q12 */ + move16(); + } + ELSE + { + w_hamm = w_hamm_sana16k_2_fx; + hamm_len2 = L_PROT_HAMM_LEN2_16k; + } + + test(); + test(); + IF( NE_16( element_mode, EVS_MONO ) && GT_16( *num_p, 0 ) && GT_16( plocs[0], 3 ) ) + { + /* Perform inverse windowing of hammrect */ + pX_start = X; + pX_end = X + Lprot - 1; + FOR( i = 0; i < hamm_len2; i++ ) + { + tmp = BASOP_Util_Divide1616_Scale( 1, *w_hamm, &tmp_e ); + tmp = shr( tmp, sub( 4, tmp_e ) ); // Q11 + *pX_start = mult_r( *pX_start, tmp ); // Qin - 4 + move16(); + *pX_end = mult_r( *pX_end, tmp ); // Qin - 4 + move16(); + pX_start++; + pX_end--; + w_hamm++; + } + } + + /* extract reconstructed frame with aldo window */ + timesh = NS2SA( output_frame * FRAMES_PER_SEC, N_ZERO_MDCT_NS ) - ( 2 * output_frame - Lprot ) / 2; + + set16_fx( xsubst_, 0, 2 * output_frame - Lprot + timesh ); + Copy( X, xsubst_ + 2 * output_frame - Lprot + timesh, Lprot - timesh ); + + /* Copy and OLA look ahead zero part of MDCT window from decoded signal */ + IF( NE_16( element_mode, EVS_MONO ) ) + { + Copy( old_dec, xsubst_ + NS2SA( output_frame * FRAMES_PER_SEC, N_ZERO_MDCT_NS ), copy_len ); /* also need to scale to Q0 ?? */ + pOld = old_dec + copy_len; + pNew = xsubst_ + copy_len + NS2SA( output_frame * FRAMES_PER_SEC, N_ZERO_MDCT_NS ); + tmp = div_s( 1, shl( ola_len, 1 ) ); // Q15 + tmp = round_fx( L_shl( L_mult( tmp, EVS_PI_FX ), 2 ) ); // Q15 + sinq_fx( tmp, 0, ola_len, xfwin ); + v_mult16_fixed( xfwin, xfwin, xfwin, ola_len ); /* xfwin = sin^2 of 0..pi/4 */ + pOldW = xfwin + ola_len - 1; + pNewW = xfwin; + FOR( i = 0; i < ola_len; i++ ) + { + *pNew = add( mult_r( *pOld, *pOldW ), mult_r( *pNew, *pNewW ) ); + move16(); + pOld += 1; + pNew += 1; + pOldW -= 1; + pNewW += 1; + } + } + ELSE + { + /* Smoothen onset of ECU frame */ + p_ecu = xsubst_ + 2 * output_frame - Lprot + timesh; + FOR( i = 0; i < xf_len; ( i++, p_ecu++ ) ) + { + idx = extract_l( L_shr( L_mult0( i, tbl_delta ), 12 ) ); + g = sincos_t_fx[idx]; + g = mult( g, g ); + *p_ecu = mult( g, ( *p_ecu ) ); + move16(); + p_ecu++; + } + } + + /* Apply TDA and windowing to ECU frame */ + Qin = 0; + move16(); + wtda_fx( xsubst_ + output_frame, &Qin, ecu_rec, NULL, 0, ALDO_WINDOW, ALDO_WINDOW, /* window overlap of current frame (0: full, 2: none, or 3: half) */ + output_frame ); + + return; +} +#endif + static void rec_wtda_fx( Word16 *X, /* i : FFT spectrum */ Word32 *ecu_rec, /* o : Reconstructed frame in tda domain */ @@ -1886,6 +3163,59 @@ static void rec_wtda_fx( * * Frame reconstruction *--------------------------------------------------------------------------*/ + +#ifdef IVAS_FLOAT_FIXED +static void ivas_rec_frame_fx( + Word16 *X, /* i : FFT spectrum */ + Word32 *ecu_rec, /* o : Reconstructed frame in tda domain */ + const Word16 output_frame, /* i : Frame length */ + const Word16 Q, + const Word16 *old_dec, /* i : end of last decoded for OLA before tda and itda */ + const Word16 element_mode, /* i : IVAS element mode */ + const Word16 *num_p, /* i : Number of peaks */ + const Word16 *plocs /* i : Peak locations */ +) +{ + const Word16 *pFftTbl; + Word16 Lprot, lprotLog2Minus1; + + /* Initialize to WB constants */ + Lprot = 512; + move16(); + lprotLog2Minus1 = 9 - 1; + move16(); + pFftTbl = FFT_W256; /* Table for 512-point real input FFT */ + IF( EQ_16( output_frame, L_FRAME48k ) ) + { + Lprot = L_PROT48k; /* 1536 = (2*output_frame)*1024/1280 */ + move16(); + } + ELSE IF( EQ_16( output_frame, L_FRAME32k ) ) + { + Lprot = L_PROT32k; /* 1024 */ + move16(); + lprotLog2Minus1 = 10 - 1; + move16(); + pFftTbl = FFT_W512; /* Table for 1024-point real input FFT */ + } + + /* extend spectrum and IDFT */ + IF( EQ_16( output_frame, L_FRAME48k ) ) + { + ifft3_fx( X, X, Lprot ); + } + ELSE + { + r_fft_fx_lc( pFftTbl, Lprot, shr( Lprot, 1 ), lprotLog2Minus1, X, X, 0 ); /* Inverse FFT */ + } + Scale_sig( X, Lprot, -Q ); + + ivas_rec_wtda_fx( X, ecu_rec, output_frame, Lprot, old_dec, element_mode, num_p, plocs ); + + return; +} +#endif + static void rec_frame_fx( Word16 *X, /* i : FFT spectrum */ Word32 *ecu_rec, /* o : Reconstructed frame in tda domain */ @@ -2379,6 +3709,117 @@ Word16 abs_iter_fx(Word16 re, Word16 im, Word16 N) * next power of 2 using linear interpolation. *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +static void ivas_fec_ecu_dft_fx( + const Word16 *prevsynth_LP, /*Qin */ + const Word16 N, + Word16 *Tfr, /*Qout */ + Word16 *Tfi, /*Qout */ + Word32 *sum_Tf_abs, /*Qout; */ + Word16 *Tf_abs, /*Qout */ + Word16 *Nfft, + Word16 *exp, /*Qout = Qin+exp */ + const Word16 element_mode /* i : IVAS element mode */ +) +{ + Word32 L_tmp, Tmp, Tfr32[512], Tfi32[512], fac, *Pt1, *Pt2; + Word16 i, tmp, tmp_short, N_LP, target[2 * L_FRAME48k], Tfr16[FEC_FFT_MAX_SIZE], *pt1, *pt2, *pt3, Lon20; + Word16 tmp_loop; + Word16 alignment_point; + + Lon20 = 8; + move16(); + IF( EQ_16( element_mode, EVS_MONO ) ) + { + alignment_point = sub( shl( 160, 1 ), i_mult( 3, Lon20 ) ); + } + ELSE + { + alignment_point = shl( 160, 1 ); + } + tmp = sub( alignment_point, N ); + Copy( &prevsynth_LP[tmp], target, N ); + + /* DFT */ + + L_tmp = L_deposit_l( N ); + FOR( tmp = 0; L_tmp <= 16384; tmp++ ) + { + L_tmp = L_shl( L_tmp, 1 ); + } + *Nfft = shl( 1, sub( 15, tmp ) ); + + set32_fx( Tfr32, 0, *Nfft ); + set32_fx( Tfi32, 0, *Nfft ); + Tfr16[0] = target[0]; + move16(); + Tfr16[*Nfft - 1] = target[N - 1]; + move16(); + + IF( EQ_16( *Nfft, N ) ) + { + Copy( &target[1], &Tfr16[1], *Nfft - 2 ); + } + ELSE + { + + tmp = div_s( sub( N, 1 ), sub( *Nfft, 1 ) ); + Tmp = L_deposit_l( tmp ); + fac = L_add( Tmp, 0 ); + tmp_loop = sub( *Nfft, 1 ); + FOR( i = 1; i < tmp_loop; i++ ) /* interpolation for FFT */ + { + tmp_short = extract_l( L_shr( Tmp, 15 ) ); + tmp = extract_l( L_msu( Tmp, tmp_short, 16384 ) ); +#ifdef BASOP_NOGLOB + L_tmp = L_mult( sub_sat( target[tmp_short + 1], target[tmp_short] ), tmp ); /*Qin+16 */ + Tfr16[i] = add_sat( target[tmp_short], round_fx_sat( L_tmp ) ); +#else + L_tmp = L_mult( sub( target[tmp_short + 1], target[tmp_short] ), tmp ); /*Qin+16 */ + Tfr16[i] = add( target[tmp_short], round_fx( L_tmp ) ); +#endif + move16(); /*Qin */ + Tmp = L_add( Tmp, fac ); + } + } + + + /*to avoid overflow in DoRTFTn_fx() */ + tmp = Exp16Array( *Nfft, Tfr16 ); + *exp = add( tmp, add( 2, norm_s( *Nfft ) ) ); + Copy_Scale_sig_16_32( Tfr16, Tfr32, *Nfft, *exp ); /*Qin+exp; */ + + DoRTFTn_fx( Tfr32, Tfi32, *Nfft ); + N_LP = shr( *Nfft, 1 ); + + + L_tmp = L_deposit_l( 0 ); + + pt1 = Tfr; + pt2 = Tfi; + pt3 = Tf_abs; + Pt1 = Tfr32; + Pt2 = Tfi32; + FOR( i = 0; i < N_LP; i++ ) + { + *pt1 = extract_h( *Pt1 ); /*Qin+exp-16 */ + *pt2 = extract_h( *Pt2 ); /*Qin+exp-16 */ + *pt3 = abs_iter_fx( Tfr[i], Tfi[i], 5 ); + move16(); /*Qin+exp-16 */ + L_tmp = L_mac0( L_tmp, *pt3, 1 ); /*Qin+exp-16 */ + pt1++; + pt2++; + pt3++; + Pt1++; + Pt2++; + } + *sum_Tf_abs = L_tmp; + move32(); + *exp = sub( *exp, 16 ); + return; +} +#endif + static void fec_ecu_dft_fx( const Word16 *prevsynth_LP, /*Qin */ @@ -2740,46 +4181,209 @@ void sinusoidal_synthesis_fx( } - /* sinusoidal synthesis */ + /* sinusoidal synthesis */ + + + set32_fx(synthesis_fx,0,Len); + + exp = add(exp,sN); + + + pt1 = a_re; + pt2 = a_im; + pt3 = freqi; + q = shr_r(N,2); + if (GT_16(N,shl(q,2))) + { + q = add(q,1); + } + + inv_den = i_mult2(N,decimate_factor); /*Q0 */ + + /*tmp = div_s(12868,inv_den);*/ /*Q15 */ + + + FOR ( i=0; ihHQ_core; + IF( EQ_16( st_fx->element_mode, EVS_MONO ) ) + { + fec_alg_input = prevsynth + NS2SA( output_frame * FRAMES_PER_SEC, ACELP_LOOK_NS / 2 - PH_ECU_LOOKAHEAD_NS ); + } + ELSE + { + fec_alg_input = prevsynth - NS2SA( output_frame * FRAMES_PER_SEC, PH_ECU_LOOKAHEAD_NS ); + } + /* init (values ar changed after) */ + decimatefactor = 4; + move16(); + N = shr( output_frame, 2 ); + + + /* find pitch and R value */ + + IF( !( LT_16( output_frame, L_FRAME16k ) ) ) + { + fec_ecu_pitch_fx( fec_alg_input, prevsynth_LP, output_frame, &N, &corr, &decimatefactor, ph_ecu_HqVoicing ); + } + ELSE + { + corr = 0; + move16(); /* just to avoid using uninitialized value in if statement below */ + } + + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + + evs_mode_selection = ( GE_32( st_fx->total_brate, 48000 ) && ( GE_16( output_frame, L_FRAME16k ) && !prev_bfi && ( !old_is_transient[0] || old_is_transient[1] ) && + ( ph_ecu_HqVoicing || ( ( ( GT_16( hHQ_core->env_stab_plc_fx, 16384 ) /* 0.5 in Q15 */ ) && ( LT_16( corr, 19661 ) /* 0.6 in Q15 */ ) ) || ( LT_16( hHQ_core->env_stab_plc_fx, 16384 ) /* 0.5 in Q15 */ && ( GT_16( corr, 27853 ) /* 0.85 in Q15 */ ) ) ) ) ) ) || + ( LT_32( st_fx->total_brate, 48000 ) && ( ( ph_ecu_HqVoicing || GT_16( corr, 27853 ) /* 0.85 in Q15 */ ) && !prev_bfi && ( !old_is_transient[0] || old_is_transient[1] ) ) ); + + test(); + ivas_mode_selection = ( LT_16( N, PH_ECU_N_LIMIT ) ) || ( LT_16( corr, PH_ECU_CORR_LIMIT_Q15 ) ); + test(); + test(); + test(); + test(); + IF( ( ( EQ_16( st_fx->element_mode, EVS_MONO ) ) && evs_mode_selection ) || + ( ( NE_16( st_fx->element_mode, EVS_MONO ) ) && evs_mode_selection && ivas_mode_selection ) ) + { + ivas_fec_alg_fx( fec_alg_input, prevsynth_LP, &st_fx->hHQ_core->ni_seed_forfec, ecu_rec, output_frame, N, decimatefactor, ph_ecu_HqVoicing, gapsynth, st_fx->element_mode, st_fx->hHQ_core->old_out_fx ); + *last_fec = 1; + move16(); + *ph_ecu_active = 0; + move16(); + *time_offs = output_frame; + move16(); + } + ELSE + { + ivas_hq_phase_ecu_fx( prevsynth - NS2SA( output_frame * FRAMES_PER_SEC, PH_ECU_LOOKAHEAD_NS ), ecu_rec, time_offs, X_sav, Q_spec, num_p, plocs, plocsi, + env_stab, last_fec, ph_ecu_active, prev_bfi, old_is_transient, + mag_chg_1st, Xavg, beta_mute, st_fx->bwidth, output_frame, corr, st_fx->element_mode ); + + *last_fec = 0; + move16(); + *ph_ecu_active = 1; + move16(); + } + return; +} +#endif + void hq_ecu_fx( const Word16 *prevsynth, /* i : buffer of previously synthesized signal */ Word32 *ecu_rec, /* o : reconstructed frame in tda domain */ diff --git a/lib_dec/dec_tcx_fx.c b/lib_dec/dec_tcx_fx.c index 71f4bfe90..2843132ed 100644 --- a/lib_dec/dec_tcx_fx.c +++ b/lib_dec/dec_tcx_fx.c @@ -26,36 +26,6 @@ static Word32 CalculateAbsEnergy( /* o : normalized result Q31 */ Word16 * exp /* o : exponent of result in [-32,31] Q0 */ ); -static void IMDCT(Word32 *x, Word16 x_e, - Word16 *old_syn_overl, - Word16 *syn_Overl_TDAC, - Word16 *xn_buf, - const Word16 *tcx_aldo_window_1, - const PWord16 *tcx_aldo_window_1_trunc, - const PWord16 *tcx_aldo_window_2, - const PWord16 *tcx_mdct_window_half, - const PWord16 *tcx_mdct_window_minimum, - const PWord16 *tcx_mdct_window_trans, - Word16 tcx_mdct_window_half_length, - Word16 tcx_mdct_window_min_length, - Word16 index, - Word16 left_rect, - Word16 tcx_offset, - Word16 overlap, - Word16 L_frame, - Word16 L_frameTCX, - Word16 L_spec_TCX5, - Word16 L_frame_glob, - Word16 frame_cnt, - Word16 bfi, - Word16 *old_out, - Word16 *Q_old_wtda, - Decoder_State *st - ,Word16 fullbandScale - ,Word16 *acelp_zir - ); - - void decoder_tcx( TCX_CONFIG_HANDLE hTcxCfg, Word16 prm[], /* input: parameters */ @@ -1675,7 +1645,7 @@ static Word32 CalculateAbsEnergy( /* o : normalized result Q31 */ } -static void IMDCT(Word32 *x, Word16 x_e, +void IMDCT(Word32 *x, Word16 x_e, Word16 *old_syn_overl, Word16 *syn_Overl_TDAC, Word16 *xn_buf, diff --git a/lib_dec/hq_classifier_dec_fx.c b/lib_dec/hq_classifier_dec_fx.c index 893e613d0..af6521ae8 100644 --- a/lib_dec/hq_classifier_dec_fx.c +++ b/lib_dec/hq_classifier_dec_fx.c @@ -5,6 +5,9 @@ #include "options.h" /* Compilation switches */ #include "prot_fx1.h" /* Function prototypes */ #include "prot_fx2.h" /* Function prototypes */ +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*--------------------------------------------------------------------------* * hq_classifier_dec() @@ -12,6 +15,76 @@ * HQ mode selector (decision_matrix) *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +Word16 ivas_hq_classifier_dec_fx( /* o : Consumed bits Q0 */ + Decoder_State *st_fx, /* i/o: decoder state structure */ + const Word32 core_brate, /* i : Core bit rate Q0 */ + const Word16 length, /* i : Frame length Q0 */ + Word16 *is_transient, /* o : Transient flag Q0 */ + Word16 *hqswb_clas /* o : HQ class Q0 */ +) +{ + Word16 bits; + Word32 max_brate; + + max_brate = HQ_32k; + move32(); + IF( GT_16( st_fx->element_mode, EVS_MONO ) ) + { + max_brate = HQ_48k; + move32(); + } + test(); + test(); + test(); + IF( ( EQ_16( length, L_SPEC32k ) || EQ_16( length, L_SPEC48k ) ) && LE_32( core_brate, max_brate ) ) + { + *hqswb_clas = get_next_indice( st_fx, 2 ); + bits = 2; + move16(); + } + ELSE IF( EQ_16( length, L_SPEC16k_EXT ) || EQ_16( length, L_SPEC48k_EXT ) ) + { + *hqswb_clas = HQ_NORMAL; + bits = 0; + move16(); + move16(); + } + ELSE + { + *hqswb_clas = get_next_indice( st_fx, 1 ); + bits = 1; + move16(); + } + + *is_transient = 0; + move16(); + IF( EQ_16( *hqswb_clas, HQ_TRANSIENT ) ) + { + *is_transient = 1; + move16(); + } + + test(); + IF( LE_32( st_fx->core_brate, HQ_32k ) && EQ_16( *hqswb_clas, HQ_NORMAL ) ) + { + move16(); + IF( EQ_16( length, L_SPEC32k ) ) + { + *hqswb_clas = HQ_GEN_SWB; + move16(); + } + ELSE IF( EQ_16( length, L_SPEC48k ) ) + { + *hqswb_clas = HQ_GEN_FB; + move16(); + } + } + + return bits; +} +#endif + Word16 hq_classifier_dec_fx( /* o : Consumed bits Q0 */ Decoder_State *st_fx, /* i/o: decoder state structure */ const Word32 core_brate, /* i : Core bit rate Q0 */ diff --git a/lib_dec/hq_core_dec.c b/lib_dec/hq_core_dec.c index 1cfea1f47..7fee85f69 100644 --- a/lib_dec/hq_core_dec.c +++ b/lib_dec/hq_core_dec.c @@ -42,6 +42,11 @@ #include "rom_com.h" #include "wmc_auto.h" #include "ivas_prot.h" +#ifdef IVAS_FLOAT_FIXED +#include "prot_fx1.h" +#include "prot_fx2.h" +#include "ivas_prot_fx.h" +#endif /*-------------------------------------------------------------------------- @@ -145,10 +150,17 @@ void hq_core_dec( } } +#ifdef IVAS_FLOAT_FIXED + IF( hq_recovery_flag ) + { + acelp_plc_mdct_transition_fx( st ); + } +#else if ( hq_recovery_flag ) { acelp_plc_mdct_transition( st ); } +#endif /* subtract signaling bits */ num_bits -= st->next_bit_pos; @@ -310,6 +322,88 @@ void hq_core_dec( * Pre-echo reduction *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED + IF( st->element_mode > EVS_MONO && ( core_switching_flag || hq_recovery_flag ) ) + { + // Float to fix code + Word32 t_audio_q_fx[L_FRAME48k_EXT]; /* Q12 */ + Word16 Q_audio = Q12; + Word16 E_audio = 31 - Q_audio; + Word16 wtda_audio_16_fx[2 * L_FRAME48k]; + Word16 acelp_zir_fx[L_FRAME_MAX / 2]; + Word16 output_fx[L_FRAME48k]; + Word16 synth_fx[L_FRAME48k]; + + Word16 Q_old_syn_Overl = -1; + Word16 Q_old_Aq_12_8 = 12; + floatToFixed_arrL( t_audio_q, t_audio_q_fx, Q_audio, L_FRAME48k_EXT ); + floatToFixed_arr( hHQ_core->old_out, hHQ_core->old_out_fx, hHQ_core->Q_old_wtda, L_FRAME48k ); + floatToFixed_arr( hHQ_core->old_outLB, hHQ_core->old_out_LB_fx, hHQ_core->Q_old_wtda_LB, L_FRAME32k ); + floatToFixed_arr( st->hTcxDec->old_syn_Overl_float, st->hTcxDec->old_syn_Overl, Q_old_syn_Overl, L_FRAME32k / 2 ); + floatToFixed_arr( st->old_Aq_12_8, st->old_Aq_12_8_fx, Q_old_Aq_12_8, M + 1 ); + + /* Initializations for TCX MDCT framework, to be used for switching frame */ + tcx_cfg = st->hTcxCfg; + L_frameTCX_glob = hTcxDec->L_frameTCX; + L_frame_glob = st->L_frame; + L_spec = hTcxDec->L_frameTCX; + st->fscale = sr2fscale( st->sr_core ); + fscaleFB = sr2fscale( st->output_Fs ); + encoderLookahead = ( L_LOOK_12k8 * st->fscale ) / FSCALE_DENOM; + encoderLookaheadFB = ( L_LOOK_12k8 * fscaleFB ) / FSCALE_DENOM; + mdctWindowLength = getMdctWindowLength( st->fscale ); + mdctWindowLengthFB = (int16_t) ( mdctWindowLength * st->output_Fs / st->sr_core ); + IF( core_switching_flag ) + { + tcx_cfg->tcx_last_overlap_mode = TRANSITION_OVERLAP; + tcx_cfg->tcx_curr_overlap_mode = FULL_OVERLAP; + } + ELSE + { + tcx_cfg->tcx_last_overlap_mode = ALDO_WINDOW; + tcx_cfg->tcx_curr_overlap_mode = ALDO_WINDOW; + st->last_core = HQ_CORE; /* Needed to decode non-transition frame */ + } + + init_tcx_window_cfg_fx( tcx_cfg, st->sr_core, st->output_Fs, st->L_frame, hTcxDec->L_frameTCX, encoderLookahead, encoderLookaheadFB, mdctWindowLength, mdctWindowLengthFB, st->element_mode ); + + init_tcx_info_fx( st, L_frame_glob, L_frameTCX_glob, 0, st->bfi, &tcx_offset, &tcx_offsetFB, &L_frame, &L_frameTCX, &left_rect, &L_spec ); + + overlap = tcx_cfg->tcx_mdct_window_length; + overlapFB = tcx_cfg->tcx_mdct_window_lengthFB; + index = tcx_cfg->tcx_last_overlap_mode; + + /* LB synthesis */ + + IMDCT( t_audio_q_fx, E_audio, hTcxDec->syn_Overl, hTcxDec->syn_Overl_TDAC, wtda_audio_16_fx, tcx_cfg->tcx_aldo_window_1, tcx_cfg->tcx_aldo_window_1_trunc, tcx_cfg->tcx_aldo_window_2, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, tcx_cfg->tcx_mdct_window_trans, tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, index, + left_rect, tcx_offset, overlap, L_frame, L_frameTCX, max( L_frameTCX, L_spec ) >> 1, L_frame_glob, 0, st->bfi, hHQ_core->old_out_LB_fx, &hHQ_core->Q_old_wtda_LB, st, 0, acelp_zir_fx ); + + Scale_sig( wtda_audio_16_fx + L_frame, overlap, Q1 ); + + Copy( wtda_audio_16_fx + ( overlap >> 1 ) - tcx_offset, output_fx, L_frame_glob ); // output Q - Q0 + + /* FB synthesis */ + + IMDCT( t_audio_q_fx, E_audio, hTcxDec->syn_OverlFB, hTcxDec->syn_Overl_TDACFB, wtda_audio_16_fx, tcx_cfg->tcx_aldo_window_1_FB, tcx_cfg->tcx_aldo_window_1_FB_trunc, tcx_cfg->tcx_aldo_window_2_FB, tcx_cfg->tcx_mdct_window_halfFB, tcx_cfg->tcx_mdct_window_minimumFB, tcx_cfg->tcx_mdct_window_transFB, tcx_cfg->tcx_mdct_window_half_lengthFB, tcx_cfg->tcx_mdct_window_min_lengthFB, index, + left_rect, tcx_offsetFB, overlapFB, L_frameTCX, L_frameTCX, max( L_frameTCX, L_spec ) >> 1, L_frameTCX_glob, 0, st->bfi, hHQ_core->old_out_fx, &hHQ_core->Q_old_wtda, st, FSCALE_DENOM * L_frameTCX_glob / L_frame_glob, acelp_zir_fx ); + + Scale_sig( wtda_audio_16_fx + L_frameTCX, overlapFB, Q1 ); + + Copy( wtda_audio_16_fx + ( overlapFB >> 1 ) - tcx_offsetFB, synth_fx, L_frameTCX_glob ); + + IF( !core_switching_flag ) + { + st->last_core = ACELP_CORE; /* Restore last core */ + } + // Fixed to Float + fixedToFloat_arrL( t_audio_q_fx, t_audio_q, Q_audio, L_FRAME48k_EXT ); + fixedToFloat_arr( st->hTcxDec->old_syn_Overl, st->hTcxDec->old_syn_Overl_float, Q_old_syn_Overl, L_FRAME32k / 2 ); + fixedToFloat_arr( hHQ_core->old_out_LB_fx, hHQ_core->old_outLB, hHQ_core->Q_old_wtda_LB, L_FRAME32k ); + fixedToFloat_arr( hHQ_core->old_out_fx, hHQ_core->old_out, hHQ_core->Q_old_wtda, L_FRAME48k ); + fixedToFloat_arr( output_fx, output, 0, L_frame_glob ); + fixedToFloat_arr( synth_fx, synth, 0, L_frameTCX_glob ); + } +#else if ( st->element_mode > EVS_MONO && ( core_switching_flag || hq_recovery_flag ) ) { /* Initializations for TCX MDCT framework, to be used for switching frame */ @@ -362,6 +456,7 @@ void hq_core_dec( st->last_core = ACELP_CORE; /* Restore last core */ } } +#endif else { if ( output_frame == L_FRAME8k || st->bfi == 0 ) @@ -378,6 +473,33 @@ void hq_core_dec( if ( st->element_mode > EVS_MONO ) { +#ifdef IVAS_FLOAT_FIXED + Word16 ener_match_fx; /* Q13 */ + Word32 t_audio_q_fx[L_FRAME48k_EXT]; /* Q12 */ + Word16 Q_audio = Q12; + Word32 wtda_audio_LB_fx[2 * L_FRAME16k]; + Word16 tmp, tmp_e; + floatToFixed_arrL( t_audio_q, t_audio_q_fx, Q_audio, L_FRAME48k_EXT ); + IF( st->bfi ) + { + /* Rough resampling, but reduces energy loss in case of switch to ACELP in first good frame */ + L_lerp_fx_q11( t_audio_q_fx, wtda_audio_LB_fx, st->L_frame, inner_frame ); + v_multc_fixed_16( t_audio_q_fx, ONE_IN_Q14, wtda_audio_LB_fx, st->L_frame ); + } + ELSE + { + /* LB synthesis for potential switch to ACELP */ + tmp = BASOP_Util_Divide1616_Scale( st->L_frame, output_frame, &tmp_e ); + tmp = Sqrt16( tmp, &tmp_e ); + ener_match_fx = shr( tmp, 2 - tmp_e ); // Q13 + + v_multc_fixed_16( t_audio_q_fx, ener_match_fx, t_audio_q_fx, inner_frame ); // Q + + Scale_sig32( t_audio_q_fx, inner_frame, Q2 ); + Inverse_Transform( t_audio_q_fx, &Q_audio, wtda_audio_LB_fx, is_transient, st->L_frame, inner_frame, st->element_mode ); + } + fixedToFloat_arrL( wtda_audio_LB_fx, wtda_audio_LB, Q_audio, 2 * L_FRAME16k ); +#else if ( st->bfi ) { /* Rough resampling, but reduces energy loss in case of switch to ACELP in first good frame */ @@ -391,6 +513,7 @@ void hq_core_dec( v_multc( t_audio_q, ener_match, t_audio_q, inner_frame ); inverse_transform( t_audio_q, wtda_audio_LB, is_transient, st->L_frame, inner_frame, st->element_mode ); } +#endif } if ( output_frame == L_FRAME8k ) @@ -433,7 +556,27 @@ void hq_core_dec( if ( st->element_mode > EVS_MONO ) { /* LB synthesis for potential switch to ACELP */ +#ifdef IVAS_FLOAT_FIXED + Word16 Q_audio = Q15; + Word32 wtda_audio_LB_fx[2 * L_FRAME16k]; + Word16 output_fx[L_FRAME48k]; + Word16 Q_output, Q_oldgapsynth, Q_wtda_audio; + Q_wtda_audio = Q_audio; + + Q_output = Q_factor_arr( output, L_FRAME48k ); + Q_oldgapsynth = Q_factor_arr( hHQ_core->oldgapsynth, L_FRAME48k ); + floatToFixed_arrL( wtda_audio_LB, wtda_audio_LB_fx, Q_wtda_audio, 2 * L_FRAME16k ); + floatToFixed_arr( output, output_fx, Q_output, L_FRAME48k ); + floatToFixed_arr( hHQ_core->old_outLB, hHQ_core->old_out_LB_fx, hHQ_core->Q_old_wtda_LB, L_FRAME32k ); + floatToFixed_arr( hHQ_core->oldgapsynth, hHQ_core->oldgapsynth_fx, Q_oldgapsynth, L_FRAME32k ); + + window_ola_fx( wtda_audio_LB_fx, output_fx, &Q_output, hHQ_core->old_out_LB_fx, &hHQ_core->Q_old_wtda_LB, L_FRAME16k, st->hTcxCfg->tcx_last_overlap_mode, st->hTcxCfg->tcx_curr_overlap_mode, st->prev_bfi && !hHQ_core->ph_ecu_active, hHQ_core->oldHqVoicing, hHQ_core->oldgapsynth_fx ); + + fixedToFloat_arr( output_fx, output, Q_output, L_FRAME48k ); + fixedToFloat_arr( hHQ_core->old_out_LB_fx, hHQ_core->old_outLB, hHQ_core->Q_old_wtda_LB, L_FRAME32k ); +#else window_ola( wtda_audio_LB, output, hHQ_core->old_outLB, L_FRAME16k, st->hTcxCfg->tcx_last_overlap_mode, st->hTcxCfg->tcx_curr_overlap_mode, st->prev_bfi && !hHQ_core->ph_ecu_active, hHQ_core->oldHqVoicing, hHQ_core->oldgapsynth ); +#endif } if ( ( !st->bfi && !st->prev_bfi ) || ( !( output_frame >= L_FRAME16k ) ) ) @@ -514,6 +657,11 @@ void HQ_core_dec_init_flt( set_f( hHQ_core->old_outLB, 0, L_FRAME32k ); set_s( hHQ_core->old_is_transient, 0, 3 ); +#ifdef IVAS_FLOAT_FIXED + hHQ_core->Q_old_wtda = 0; + hHQ_core->Q_old_wtda_LB = 0; +#endif + hHQ_core->oldHqVoicing = 0; set_f( hHQ_core->prev_noise_level, 0.0f, 2 ); diff --git a/lib_dec/hq_core_dec_fx.c b/lib_dec/hq_core_dec_fx.c index f8eb4a25d..bcb57e436 100644 --- a/lib_dec/hq_core_dec_fx.c +++ b/lib_dec/hq_core_dec_fx.c @@ -7,6 +7,11 @@ #include "prot_fx1.h" /* Function prototypes */ #include "prot_fx2.h" /* Function prototypes */ #include "rom_com.h" /* Static table prototypes */ +#ifdef IVAS_FLOAT_FIXED +#include "prot.h" +#include "ivas_prot_fx.h" +#endif + /*-------------------------------------------------------------------------- * hq_core_dec() * @@ -579,6 +584,619 @@ void hq_core_dec_fx( #endif return; } + +#ifdef IVAS_FLOAT_FIXED +void ivas_hq_core_dec_fx( + Decoder_State *st_fx, /* i/o: decoder state structure fx */ + Word16 synth[], /* o : output synthesis */ + Word16 *Q_synth, /* o : Q value of synth */ + const Word16 output_frame, /* i : output frame length */ + const Word16 hq_core_type, /* i : HQ core type */ + const Word16 core_switching_flag, /* i : ACELP->HQ switching frame flag */ + Word16 output[], + Word16 *Q_output ) +{ + Word16 num_bits, is_transient, hqswb_clas, inner_frame; + Word16 i, j, flag_uv, num_Sb, nb_sfm; + Word16 ynrm[NB_SFM], num_bands_p[MAX_SB_NB]; + Word16 ener_match; /* Q13 */ + Word32 t_audio_q[L_FRAME48k_EXT]; /* Q12 */ + Word16 Q_audio, E_audio, Q_G_audio; + Word32 wtda_audio[2 * L_FRAME48k]; + Word16 wtda_audio_16[2 * L_FRAME48k]; + Word32 wtda_audio_LB[2 * L_FRAME16k]; + Word16 delay_comp; + Word32 normq_fx[NB_SFM]; + Word16 mean_en_high_fx; + Word16 SWB_fenv_fx[SWB_FENV + DIM_FB]; + const Word16 *sfmsize, *sfm_start, *sfm_end; + Word16 gapsynth_fx[L_FRAME48k]; + Word16 tmp, tmp_loop; + Word32 L_tmp; + UWord16 lsb; + Word16 L_spec; + HQ_NBFEC_HANDLE hHQ_nbfec; + HQ_DEC_HANDLE hHQ_core; + hHQ_nbfec = st_fx->hHQ_nbfec; + hHQ_core = st_fx->hHQ_core; + + TCX_DEC_HANDLE hTcxDec; + TCX_CONFIG_HANDLE tcx_cfg; + Word16 index, left_rect, tcx_offsetFB, overlapFB, L_frameTCX; + Word16 tcx_offset, overlap, L_frame, fscaleFB; + Word16 L_frameTCX_glob, L_frame_glob; + Word16 acelp_zir[L_FRAME_MAX / 2]; + Word16 encoderLookahead, encoderLookaheadFB; + Word16 hq_recovery_flag; + Word16 mdctWindowLength; + Word16 mdctWindowLengthFB; + Word16 tmp_e; + Word16 tmp_out[L_FRAME48k]; + + /*-------------------------------------------------------------------------- + * Initializations + *--------------------------------------------------------------------------*/ + + set32_fx( t_audio_q, 0, L_FRAME48k_EXT ); + set16_fx( gapsynth_fx, 0, L_FRAME48k ); + set16_fx( num_bands_p, 0, MAX_SB_NB ); + set16_fx( ynrm, 39, NB_SFM ); /* Initialize to the smallest value */ + mean_en_high_fx = 0; + move16(); + Q_audio = 12; + move16(); + Q_G_audio = 12; + move16(); + sfm_start = sfm_end = NULL; + num_Sb = nb_sfm = 0; + move16(); + move16(); + + hTcxDec = st_fx->hTcxDec; + + st_fx->hTcxCfg->tcx_last_overlap_mode = st_fx->hTcxCfg->tcx_curr_overlap_mode; + move16(); + IF( EQ_16( st_fx->hTcxCfg->tcx_curr_overlap_mode, FULL_OVERLAP ) ) + { + st_fx->hTcxCfg->tcx_last_overlap_mode = ALDO_WINDOW; + move16(); + } + st_fx->hTcxCfg->tcx_curr_overlap_mode = ALDO_WINDOW; + move16(); + hq_recovery_flag = ( EQ_16( st_fx->last_core, ACELP_CORE ) ) && st_fx->prev_bfi && ( GT_16( st_fx->element_mode, EVS_MONO ) ); /* ACELP -> HQtrans -> HQ; with HQtrans lost */ + /*-------------------------------------------------------------------------- + * Find the number of bits for transform-domain coding + *--------------------------------------------------------------------------*/ + + /* set the total bit-budget */ + /*num_bits = (short)(st->total_brate / 50); */ + Mpy_32_16_ss( st_fx->total_brate, 5243, &L_tmp, &lsb ); /* 5243 is 1/50 in Q18. (0+18-15=3) */ + num_bits = extract_l( L_shr( L_tmp, 3 ) ); /*Q0 */ + + /* Set default spectrum length */ + L_spec = l_spec_tbl[st_fx->bwidth]; + move16(); + IF( !st_fx->bfi ) + { + IF( EQ_16( core_switching_flag, 1 ) ) + { + IF( NE_16( st_fx->element_mode, EVS_MONO ) ) + { + L_spec = l_spec_ext_tbl[st_fx->bwidth]; + } + ELSE + { + core_switching_hq_prepare_dec_fx( st_fx, &num_bits, output_frame ); + + /* During ACELP->HQ core switching, limit the HQ core bitrate to 48kbps */ + IF( GT_16( num_bits, HQ_48k / 50 ) ) + { + num_bits = (Word16) ( HQ_48k / 50 ); + move16(); + } + } + } + IF( hq_recovery_flag ) + { + acelp_plc_mdct_transition_fx( st_fx ); + } + /* subtract signalling bits */ + num_bits = sub( num_bits, st_fx->next_bit_pos ); + + /* set FEC parameters */ + flag_uv = sub( 1, hHQ_core->HqVoicing_fx ); + + /* subtract the number of bits for pitch & gain at higher bitrates */ + test(); + IF( !( core_switching_flag ) && GT_32( st_fx->core_brate, MINIMUM_RATE_TO_ENCODE_VOICING_FLAG ) ) + { + hHQ_core->HqVoicing_fx = get_next_indice( st_fx, 1 ); + num_bits = sub( num_bits, 1 ); + } + ELSE + { + hHQ_core->HqVoicing_fx = 0; + move16(); + IF( GT_32( st_fx->core_brate, MINIMUM_RATE_TO_ENCODE_VOICING_FLAG ) ) + { + hHQ_core->HqVoicing_fx = 1; + move16(); + } + } + } + ELSE + { + flag_uv = 0; + move16(); + } + + /* set inner frame (== coded bandwidth) length */ + inner_frame = inner_frame_tbl[st_fx->bwidth]; + move16(); + + IF( EQ_16( st_fx->bfi, 0 ) ) + { + hHQ_core->ph_ecu_HqVoicing_fx = 0; + move16(); + IF( GE_16( output_frame, L_FRAME16k ) ) + { + hHQ_core->ph_ecu_HqVoicing_fx = hHQ_core->HqVoicing_fx; + move16(); + } + } + + IF( EQ_16( output_frame, L_FRAME8k ) ) + { + hq_configure_bfi_fx( &nb_sfm, &num_Sb, num_bands_p, &sfmsize, &sfm_start, &sfm_end ); + } + + /*-------------------------------------------------------------------------- + * transform-domain decoding + *--------------------------------------------------------------------------*/ + + IF( EQ_16( st_fx->bfi, 1 ) ) + { + is_transient = hHQ_core->old_is_transient_fx[0]; + move16(); + IF( GE_16( output_frame, L_FRAME16k ) ) /* Apply phase ecu for WB, SWB and FB */ + { + /* ecu_rec sent to OLA, env_stab passed in ph_ecu_st */ + ivas_hq_ecu_fx( st_fx->hTcxDec->prev_good_synth_fx, t_audio_q, &hHQ_core->time_offs_fx, hHQ_core->X_sav_fx, &hHQ_core->Q_X_sav, &hHQ_core->num_p_fx, hHQ_core->plocs_fx, hHQ_core->plocsi_fx, hHQ_core->env_stab_fx, + &hHQ_core->last_fec_fx, hHQ_core->ph_ecu_HqVoicing_fx, &hHQ_core->ph_ecu_active_fx, gapsynth_fx, st_fx->prev_bfi, hHQ_core->old_is_transient_fx, hHQ_core->mag_chg_1st_fx, + hHQ_core->Xavg_fx, &hHQ_core->beta_mute_fx, output_frame, st_fx ); + } + ELSE + { + HQ_FEC_processing_fx( st_fx, t_audio_q, is_transient, hHQ_nbfec->ynrm_values_fx, hHQ_nbfec->r_p_values_fx, num_Sb, nb_sfm, num_bands_p, + output_frame, sfm_start, sfm_end ); + } + + hHQ_core->old_is_transient_fx[2] = hHQ_core->old_is_transient_fx[1]; + move16(); + hHQ_core->old_is_transient_fx[1] = hHQ_core->old_is_transient_fx[0]; + move16(); + + IF( GE_16( output_frame, L_FRAME16k ) ) + { + /* keep st->previoussynth updated as in FEC_HQ_pitch_analysis but no LP analysis */ + delay_comp = NS2SA_fx2( st_fx->output_Fs, DELAY_CLDFB_NS ); + + Copy( st_fx->previoussynth_fx + delay_comp, st_fx->previoussynth_fx, sub( output_frame, delay_comp ) ); + Copy( st_fx->delay_buf_out_fx, st_fx->previoussynth_fx + output_frame - delay_comp, delay_comp ); + + flag_uv = 1; + move16(); /* disable costly pitch out synthesis in bfi frame */ + hHQ_core->HqVoicing_fx = sub( 1, flag_uv ); /* safety setting for HQ->ACELP switch logic */ + set16_fx( hHQ_core->fer_samples_fx, 0, L_FRAME48k ); /* safety, create a known signal state for HQ->ACELP switch logic */ + } + } + ELSE + { + IF( EQ_16( hq_core_type, LOW_RATE_HQ_CORE ) ) + { + IF( EQ_16( st_fx->prev_bfi, 1 ) ) + { + set32_fx( hHQ_core->last_ni_gain_fx, 0, BANDS_MAX ); + set16_fx( hHQ_core->last_env_fx, 0, BANDS_MAX ); + hHQ_core->last_max_pos_pulse_fx = 0; + move16(); + } + + /* HQ low rate decoder */ + hq_lr_dec_fx( st_fx, t_audio_q, inner_frame, num_bits, &is_transient ); + hqswb_clas = is_transient; + move16(); + Q_audio = 12; + move16(); + Q_G_audio = Q_audio; + move16(); + } + ELSE + { + /* HQ high rate decoder */ + ivas_hq_hr_dec_fx( st_fx, t_audio_q, L_spec, num_bits, ynrm, &is_transient, &hqswb_clas, SWB_fenv_fx, core_switching_flag ); + Q_audio = 12; + move16(); + Q_G_audio = Q_audio; + move16(); + } + + test(); + test(); + test(); + IF( EQ_16( st_fx->element_mode, EVS_MONO ) || ( !core_switching_flag && !hq_recovery_flag ) ) + { + /* scaling (coefficients are in nominal level) */ + IF( NE_16( output_frame, NORM_MDCT_FACTOR ) ) + { + IF( EQ_16( output_frame, L_FRAME32k ) ) + { + Q_audio = sub( Q_audio, 1 ); /* Multiply by 2 */ + Q_G_audio = Q_G_audio - 1; + } + ELSE + { + tmp = mult_r( output_frame, 410 / 2 ); /* 1/8000 in Q15 */ + ener_match = hq_nominal_scaling_inv[tmp]; + FOR( i = 0; i < inner_frame; i++ ) + { + /*t_audio_q[i] *= ener_match;*/ + Mpy_32_16_ss( t_audio_q[i], ener_match, &L_tmp, &lsb ); /*12+13-15=10 */ +#ifdef BASOP_NOGLOB + t_audio_q[i] = L_add_sat( L_shl_sat( L_tmp, 2 ), lshr( lsb, 14 ) ); +#else + t_audio_q[i] = L_add( L_shl( L_tmp, 2 ), lshr( lsb, 14 ) ); +#endif + move16(); /* Q12 */ + } + } + } + } + ivas_HQ_FEC_Mem_update_fx( st_fx, t_audio_q, normq_fx, ynrm, num_bands_p, is_transient, hqswb_clas, + core_switching_flag, nb_sfm, num_Sb, &mean_en_high_fx, hq_core_type, output_frame ); + } + /*-------------------------------------------------------------------------- + * Attenuate HFs in case of band-width switching (from higher BW to lower BW) + *--------------------------------------------------------------------------*/ + /* attenuate HFs in case of band-width switching */ + IF( GT_16( st_fx->bws_cnt1_fx, 0 ) ) + { + IF( EQ_16( st_fx->bws_cnt1_fx, N_NS2W_FRAMES ) ) + { + ener_match = 32767; + move16(); /*Q15*/ + } + ELSE + { + ener_match = div_s( st_fx->bws_cnt1_fx, N_NS2W_FRAMES ); /*Q15*/ + } + + IF( is_transient ) + { + FOR( i = 0; i < NUM_TIME_SWITCHING_BLOCKS; i++ ) + { + tmp_loop = mult( inner_frame, 8192 ); + FOR( j = mult( inner_frame_tbl[sub( st_fx->bwidth, 1 )], 8192 ); j < tmp_loop; j++ ) + { + tmp = i_mult( i, inner_frame ); /*Q0*/ + tmp = mult( tmp, 8192 ); /*Q0*/ + tmp = add( tmp, j ); + t_audio_q[tmp] = Mult_32_16( t_audio_q[tmp], ener_match ); + move32(); /*Q12*/ + } + } + } + ELSE + { + FOR( i = inner_frame_tbl[sub( st_fx->bwidth, 1 )]; i < inner_frame; i++ ) + { + t_audio_q[i] = Mult_32_16( t_audio_q[i], ener_match ); /*Q12*/ + move32(); + } + } + } + + /* WB/SWB bandwidth switching */ + IF( is_transient ) + { + Copy_Scale_sig_32_16( &t_audio_q[240], st_fx->t_audio_q_fx, 80, -13 ); + } + ELSE + { + Copy_Scale_sig_32_16( t_audio_q, st_fx->t_audio_q_fx, L_FRAME, -13 ); + } + + + /*-------------------------------------------------------------------------- + * Inverse transform + * Overlap-add + * Pre-echo reduction + *--------------------------------------------------------------------------*/ + IF( GT_16( st_fx->element_mode, EVS_MONO ) && ( core_switching_flag || hq_recovery_flag ) ) + { + /* Initializations for TCX MDCT framework, to be used for switching frame */ + tcx_cfg = st_fx->hTcxCfg; + L_frameTCX_glob = hTcxDec->L_frameTCX; + move16(); + L_frame_glob = st_fx->L_frame; + move16(); + L_spec = hTcxDec->L_frameTCX; + move16(); + st_fx->fscale = sr2fscale( st_fx->sr_core ); + fscaleFB = sr2fscale( st_fx->output_Fs ); + encoderLookahead = ( L_LOOK_12k8 * st_fx->fscale ) / FSCALE_DENOM; + encoderLookaheadFB = ( L_LOOK_12k8 * fscaleFB ) / FSCALE_DENOM; + mdctWindowLength = getMdctWindowLength( st_fx->fscale ); + mdctWindowLengthFB = (int16_t) ( mdctWindowLength * st_fx->output_Fs / st_fx->sr_core ); + IF( core_switching_flag ) + { + tcx_cfg->tcx_last_overlap_mode = TRANSITION_OVERLAP; + move16(); + tcx_cfg->tcx_curr_overlap_mode = FULL_OVERLAP; + move16(); + } + ELSE + { + tcx_cfg->tcx_last_overlap_mode = ALDO_WINDOW; + move16(); + tcx_cfg->tcx_curr_overlap_mode = ALDO_WINDOW; + move16(); + st_fx->last_core = HQ_CORE; /* Needed to decode non-transition frame */ + move16(); + } + + init_tcx_window_cfg_fx( tcx_cfg, st_fx->sr_core, st_fx->output_Fs, st_fx->L_frame, hTcxDec->L_frameTCX, encoderLookahead, encoderLookaheadFB, mdctWindowLength, mdctWindowLengthFB, st_fx->element_mode ); + + init_tcx_info_fx( st_fx, L_frame_glob, L_frameTCX_glob, 0, st_fx->bfi, &tcx_offset, &tcx_offsetFB, &L_frame, &L_frameTCX, &left_rect, &L_spec ); + + overlap = tcx_cfg->tcx_mdct_window_length; + move16(); + overlapFB = tcx_cfg->tcx_mdct_window_lengthFB; + move16(); + index = tcx_cfg->tcx_last_overlap_mode; + move16(); + + Copy_Scale_sig_32_16( wtda_audio, wtda_audio_16, 2 * L_FRAME48k, -13 ); + + /* LB synthesis */ + E_audio = 31 - Q_audio; + move16(); + IMDCT( t_audio_q, E_audio, hTcxDec->syn_Overl, hTcxDec->syn_Overl_TDAC, wtda_audio_16, tcx_cfg->tcx_aldo_window_1, tcx_cfg->tcx_aldo_window_1_trunc, tcx_cfg->tcx_aldo_window_2, tcx_cfg->tcx_mdct_window_half, tcx_cfg->tcx_mdct_window_minimum, tcx_cfg->tcx_mdct_window_trans, tcx_cfg->tcx_mdct_window_half_length, tcx_cfg->tcx_mdct_window_min_length, index, + left_rect, tcx_offset, overlap, L_frame, L_frameTCX, max( L_frameTCX, L_spec ) >> 1, L_frame_glob, 0, st_fx->bfi, hHQ_core->old_out_LB_fx, &hHQ_core->Q_old_wtda_LB, st_fx, 0, acelp_zir ); + + // values till L_frame same + Scale_sig( wtda_audio_16 + L_frame, overlap, Q1 ); + + Copy( wtda_audio_16 + ( overlap >> 1 ) - tcx_offset, output, L_frame_glob ); + + /* FB synthesis */ + + IMDCT( t_audio_q, E_audio, hTcxDec->syn_OverlFB, hTcxDec->syn_Overl_TDACFB, wtda_audio_16, tcx_cfg->tcx_aldo_window_1_FB, tcx_cfg->tcx_aldo_window_1_FB_trunc, tcx_cfg->tcx_aldo_window_2_FB, tcx_cfg->tcx_mdct_window_halfFB, tcx_cfg->tcx_mdct_window_minimumFB, tcx_cfg->tcx_mdct_window_transFB, tcx_cfg->tcx_mdct_window_half_lengthFB, tcx_cfg->tcx_mdct_window_min_lengthFB, index, + left_rect, tcx_offsetFB, overlapFB, L_frameTCX, L_frameTCX, max( L_frameTCX, L_spec ) >> 1, L_frameTCX_glob, 0, st_fx->bfi, hHQ_core->old_out_fx, &hHQ_core->Q_old_wtda, st_fx, FSCALE_DENOM * L_frameTCX_glob / L_frame_glob, acelp_zir ); + + Scale_sig( wtda_audio_16 + L_frameTCX, overlapFB, Q1 ); + + Copy( wtda_audio_16 + ( overlapFB >> 1 ) - tcx_offsetFB, synth, L_frameTCX_glob ); + + Copy_Scale_sig_16_32( wtda_audio_16, wtda_audio, 2 * L_FRAME48k, 12 ); + IF( !core_switching_flag ) + { + st_fx->last_core = ACELP_CORE; /* Restore last core */ + move16(); + } + } + ELSE + { + test(); + IF( EQ_16( output_frame, L_FRAME8k ) || EQ_16( st_fx->bfi, 0 ) ) + { + test(); + Q_audio = Q_G_audio; + move16(); + IF( NE_16( inner_frame, output_frame ) && EQ_16( st_fx->bfi, 1 ) ) + { + Inverse_Transform( t_audio_q, &Q_audio, wtda_audio, is_transient, output_frame, output_frame, st_fx->element_mode ); + } + ELSE + { + Inverse_Transform( t_audio_q, &Q_audio, wtda_audio, is_transient, output_frame, inner_frame, st_fx->element_mode ); + } + *Q_synth = Q_audio; + move16(); + } + + IF( GT_16( st_fx->element_mode, EVS_MONO ) ) + { + IF( st_fx->bfi ) + { + /* Rough resampling, but reduces energy loss in case of switch to ACELP in first good frame */ + L_lerp_fx_q11( t_audio_q, wtda_audio_LB, st_fx->L_frame, inner_frame ); + v_multc_fixed_16( t_audio_q, ONE_IN_Q14, wtda_audio_LB, st_fx->L_frame ); + } + ELSE + { + /* LB synthesis for potential switch to ACELP */ + tmp = BASOP_Util_Divide1616_Scale( st_fx->L_frame, output_frame, &tmp_e ); + tmp = Sqrt16( tmp, &tmp_e ); + ener_match = shr( tmp, 2 - tmp_e ); // Q13 + + v_multc_fixed_16( t_audio_q, ener_match, t_audio_q, inner_frame ); // Q + + Scale_sig32( t_audio_q, inner_frame, Q2 ); + Q_audio = Q_G_audio; + Inverse_Transform( t_audio_q, &Q_audio, wtda_audio_LB, is_transient, st_fx->L_frame, inner_frame, st_fx->element_mode ); + } + *Q_output = Q_audio; + move16(); + } + + IF( EQ_16( output_frame, L_FRAME8k ) ) + { + test(); + IF( EQ_16( st_fx->bfi, 0 ) && EQ_16( st_fx->prev_bfi, 0 ) ) + { + Copy_Scale_sig( hHQ_core->old_out_fx + N_ZERO_NB, hHQ_nbfec->prev_oldauOut_fx, output_frame - N_ZERO_NB, negate( hHQ_core->Q_old_wtda ) ); + } + ELSE IF( EQ_16( st_fx->prev_bfi, 1 ) ) + { + set16_fx( hHQ_nbfec->prev_oldauOut_fx, 0, output_frame ); + } + + test(); + test(); + test(); + test(); + IF( ( EQ_16( st_fx->prev_bfi, 1 ) || EQ_16( st_fx->bfi, 1 ) ) && EQ_16( hHQ_core->old_is_transient_fx[2], 0 ) && EQ_16( st_fx->last_core, HQ_CORE ) && EQ_16( st_fx->last_codec_mode, MODE1 ) ) + { + time_domain_FEC_HQ_fx( st_fx, wtda_audio, synth, mean_en_high_fx, output_frame, Q_synth ); + } + ELSE + { + window_ola_fx( wtda_audio, synth, Q_synth, hHQ_core->old_out_fx, &hHQ_core->Q_old_wtda, output_frame, + st_fx->hTcxCfg->tcx_last_overlap_mode, st_fx->hTcxCfg->tcx_curr_overlap_mode, st_fx->prev_bfi, hHQ_core->oldHqVoicing_fx, hHQ_core->oldgapsynth_fx ); + hHQ_nbfec->phase_mat_next_fx = 0; + move16(); + } + + test(); + test(); + IF( ( EQ_16( st_fx->bfi, 0 ) && EQ_16( st_fx->prev_bfi, 0 ) ) || !( GE_16( output_frame, L_FRAME16k ) ) ) + { + preecho_sb_fx( st_fx->core_brate, wtda_audio, Q_audio, synth, *Q_synth, output_frame, &hHQ_core->memfilt_lb_fx, + &hHQ_core->mean_prev_hb_fx, &hHQ_core->smoothmem_fx, &hHQ_core->mean_prev_fx, &hHQ_core->mean_prev_nc_fx, &hHQ_core->wmold_hb_fx, &hHQ_core->prevflag_fx, &hHQ_core->pastpre_fx, st_fx->bwidth ); + } + } + ELSE + { + test(); + IF( EQ_16( st_fx->bfi, 1 ) && GE_16( output_frame, L_FRAME16k ) ) + { + /* PHASE_ECU active */ + Q_audio = 15; + move16(); + window_ola_fx( t_audio_q, synth, &Q_audio, hHQ_core->old_out_fx, &hHQ_core->Q_old_wtda, output_frame, + ALDO_WINDOW, ALDO_WINDOW, st_fx->prev_bfi && !hHQ_core->ph_ecu_active_fx, hHQ_core->oldHqVoicing_fx, hHQ_core->oldgapsynth_fx ); + *Q_synth = Q_audio; + move16(); + } + ELSE + { + /* no BFI or baseline PLC active */ + window_ola_fx( wtda_audio, synth, Q_synth, hHQ_core->old_out_fx, &hHQ_core->Q_old_wtda, output_frame, + st_fx->hTcxCfg->tcx_last_overlap_mode, st_fx->hTcxCfg->tcx_curr_overlap_mode, st_fx->prev_bfi && !hHQ_core->ph_ecu_active_fx, hHQ_core->oldHqVoicing_fx, hHQ_core->oldgapsynth_fx ); + } + IF( st_fx->element_mode > EVS_MONO ) + { + /* LB synthesis for potential switch to ACELP */ + window_ola_fx( wtda_audio_LB, output, Q_output, hHQ_core->old_out_LB_fx, &hHQ_core->Q_old_wtda_LB, L_FRAME16k, st_fx->hTcxCfg->tcx_last_overlap_mode, st_fx->hTcxCfg->tcx_curr_overlap_mode, st_fx->prev_bfi && !hHQ_core->ph_ecu_active, hHQ_core->oldHqVoicing, hHQ_core->oldgapsynth_fx ); + } + test(); + test(); + IF( ( EQ_16( st_fx->bfi, 0 ) && EQ_16( st_fx->prev_bfi, 0 ) ) || !( GE_16( output_frame, L_FRAME16k ) ) ) + { + preecho_sb_fx( st_fx->core_brate, wtda_audio, Q_audio, synth, *Q_synth, output_frame, &hHQ_core->memfilt_lb_fx, + &hHQ_core->mean_prev_hb_fx, &hHQ_core->smoothmem_fx, &hHQ_core->mean_prev_fx, &hHQ_core->mean_prev_nc_fx, + &hHQ_core->wmold_hb_fx, &hHQ_core->prevflag_fx, &hHQ_core->pastpre_fx, st_fx->bwidth ); + } + } + } + + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + IF( !st_fx->bfi && st_fx->prev_bfi && GE_32( st_fx->last_total_brate, HQ_48k ) && EQ_16( st_fx->last_codec_mode, MODE2 ) && ( EQ_16( st_fx->last_core_bfi, TCX_20_CORE ) || EQ_16( st_fx->last_core_bfi, TCX_10_CORE ) ) && EQ_16( st_fx->plcInfo.concealment_method, TCX_NONTONAL ) && LT_32( st_fx->plcInfo.nbLostCmpt, 4 ) ) + { +#ifdef BASOP_NOGLOB + st_fx->plcInfo.recovery_gain = shl_sat( st_fx->plcInfo.recovery_gain, *Q_synth ); +#else + st_fx->plcInfo.recovery_gain = shl( st_fx->plcInfo.recovery_gain, *Q_synth ); +#endif + waveform_adj2_fix( st_fx->tonalMDCTconceal.secondLastPcmOut, + synth, + st_fx->plcInfo.data_noise, + &st_fx->plcInfo.outx_new_n1_fx, + &st_fx->plcInfo.nsapp_gain_fx, + &st_fx->plcInfo.nsapp_gain_n_fx, + &st_fx->plcInfo.recovery_gain, + st_fx->plcInfo.step_concealgain_fx, + st_fx->plcInfo.Pitch_fx, + st_fx->plcInfo.FrameSize, + 0, + add( extract_l( st_fx->plcInfo.nbLostCmpt ), 1 ), + st_fx->bfi ); + } + + IF( GE_16( output_frame, L_FRAME16k ) ) + { + IF( EQ_16( hHQ_core->ph_ecu_HqVoicing_fx, 1 ) ) + { + hHQ_core->oldHqVoicing_fx = 1; + move16(); + Copy( gapsynth_fx, hHQ_core->oldgapsynth_fx, L_FRAME48k ); + } + ELSE + { + hHQ_core->oldHqVoicing_fx = 0; + move16(); + } + } + ELSE + { + hHQ_core->oldHqVoicing_fx = 0; + move16(); + } + + IF( EQ_16( st_fx->nbLostCmpt, FRAMECTTOSTART_MDCT ) ) + { + hHQ_core->HqVoicing_fx = 0; + move16(); + } + + IF( EQ_16( output_frame, L_FRAME8k ) ) + { + Copy32( wtda_audio, hHQ_nbfec->oldIMDCTout_fx, L_FRAME8k / 2 ); + Copy( &hHQ_nbfec->old_auOut_2fr_fx[output_frame], hHQ_nbfec->old_auOut_2fr_fx, output_frame ); + Copy_Scale_sig( synth, &hHQ_nbfec->old_auOut_2fr_fx[output_frame], output_frame, negate( *Q_synth ) ); + } + + /* prepare synthesis output buffer (as recent as possible) for HQ FEC */ + + { + Word16 nbsubfr; + /*nbsubfr = extract_l(L_mult0(st_fx->L_frame,FL2WORD16(1/L_SUBFR)));*/ + nbsubfr = 4; + IF( EQ_16( st_fx->L_frame, 320 ) ) + { + nbsubfr = 5; + move16(); + } + + /* update buffer of old subframe pitch values */ + test(); + IF( EQ_16( st_fx->last_core, HQ_CORE ) && NE_16( st_fx->L_frame, st_fx->last_L_frame ) ) + { + set32_fx( &st_fx->old_pitch_buf_fx[nbsubfr], ( L_SUBFR << 16 ), nbsubfr ); + } + Copy32( &st_fx->old_pitch_buf_fx[nbsubfr], &st_fx->old_pitch_buf_fx[0], nbsubfr ); + set32_fx( &st_fx->old_pitch_buf_fx[nbsubfr], ( L_SUBFR << 16 ), nbsubfr ); + Copy( &st_fx->mem_pitch_gain[2], &st_fx->mem_pitch_gain[nbsubfr + 2], nbsubfr ); + set16_fx( &st_fx->mem_pitch_gain[2], 0, nbsubfr ); + } + /* Move LB excitation to old_exc memory in case of switch HQ->ACELP */ + IF( GT_16( st_fx->element_mode, EVS_MONO ) ) + { + Copy_Scale_sig( output, tmp_out, st_fx->L_frame, -( *Q_output ) ); + Copy( tmp_out, st_fx->old_exc_fx + L_EXC_MEM_DEC - st_fx->L_frame, st_fx->L_frame ); + } + return; +} +#endif + /*-------------------------------------------------------------------* * hq_core_dec_init() * diff --git a/lib_dec/hq_hr_dec_fx.c b/lib_dec/hq_hr_dec_fx.c index 768572fa5..06b1d056a 100644 --- a/lib_dec/hq_hr_dec_fx.c +++ b/lib_dec/hq_hr_dec_fx.c @@ -6,6 +6,9 @@ #include "prot_fx1.h" /* Function prototypes */ #include "prot_fx2.h" /* Function prototypes */ #include "rom_com.h" /* Static table prototypes */ +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*--------------------------------------------------------------------------* * hq_pred_hb_bws() @@ -13,6 +16,60 @@ * HQ core HB band-width switching handling *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_hq_pred_hb_bws_fx( + Decoder_State *st_fx, /* i/o: decoder state structure */ + const Word16 *ynrm, /* i : norm quantization index vector */ + const Word16 length, /* i : frame length */ + const Word16 hqswb_clas, /* i : HQ SWB class */ + const Word16 *SWB_fenv /* i : SWB frequency envelopes Q1 */ +) +{ + Word16 i; + Word32 L_tmp; + + IF( GE_16( length, L_FRAME32k ) ) + { + /* calculate the switching parameters */ + test(); + test(); + IF( ( NE_16( hqswb_clas, HQ_GEN_SWB ) && LE_32( st_fx->core_brate, HQ_32k ) ) || GT_32( st_fx->core_brate, HQ_32k ) ) + { + st_fx->prev_ener_shb_fx = 0; + move16(); + L_tmp = L_deposit_l( 0 ); + FOR( i = 25; i < SFM_N_HARM; i++ ) + { + L_tmp = L_add( L_tmp, dicn_fx[ynrm[i]] ); /*Q14*/ + } + L_tmp = L_min( 8191, L_shr( L_tmp, 13 ) ); + st_fx->prev_ener_shb_fx = extract_l( L_tmp ); /*Q1*/ + st_fx->prev_ener_shb_fx = mult( st_fx->prev_ener_shb_fx, 5461 ); /*Q1*/ + } + ELSE + { + // EVS_FUNC_MODIFIED + st_fx->prev_ener_shb_fx = 0; + move16(); + L_tmp = L_deposit_l( 0 ); + FOR( i = 0; i < SWB_FENV - 3; i++ ) + { + L_tmp = L_add( L_tmp, SWB_fenv[i] ); /*Q1*/ + } + L_tmp = Mpy_32_16_1( L_tmp, 2979 ); // Q1 + st_fx->prev_ener_shb_fx = extract_l( L_tmp ); /*Q1*/ + } + } + + IF( GE_16( st_fx->last_inner_frame, L_FRAME32k ) && st_fx->hBWE_FD != NULL ) + { + set16_fx( st_fx->prev_SWB_fenv_fx, st_fx->prev_ener_shb_fx, SWB_FENV ); + } + + return; +} +#endif + void hq_pred_hb_bws_fx( Decoder_State *st_fx, /* i/o: decoder state structure */ const Word16 *ynrm, /* i : norm quantization index vector */ @@ -44,6 +101,17 @@ void hq_pred_hb_bws_fx( } ELSE { +#ifdef EVS_FUNC_MODIFIED + st_fx->prev_ener_shb_fx = 0; + move16(); + L_tmp = L_deposit_l( 0 ); + FOR( i = 0; i < SWB_FENV - 3; i++ ) + { + L_tmp = L_add( L_tmp, SWB_fenv[i] ); /*Q1*/ + } + L_tmp = Mpy_32_16_1( L_tmp, 2979 ); // Q1 + st_fx->prev_ener_shb_fx = extract_l( L_tmp ); /*Q1*/ +#else st_fx->prev_ener_shb_fx = 0; move16(); FOR(i=0; iprev_ener_shb_fx = add(st_fx->prev_ener_shb_fx,SWB_fenv[i]);/*Q1*/ } st_fx->prev_ener_shb_fx = mult(st_fx->prev_ener_shb_fx, 2979); /*Q1*/ +#endif } } @@ -67,6 +136,272 @@ void hq_pred_hb_bws_fx( * * HQ High rate decoding routine *--------------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +void ivas_hq_hr_dec_fx( + Decoder_State *st_fx, /* i/o: decoder state structure fx */ + Word32 *t_audio_q, /* o : transform-domain coefficients Q12 */ + const Word16 length, /* i : frame length Q0 */ + Word16 num_bits, /* i : number of available bits Q0 */ + Word16 *ynrm, /* o : norm quantization index vector Q0 */ + Word16 *is_transient, /* o : transient flag Q0 */ + Word16 *hqswb_clas, /* o : HQ SWB class Q0 */ + Word16 *SWB_fenv, /* o : SWB frequency envelopes Q1 */ + const Word16 core_switching_flag /* i : Core switching flag */ +) +{ + Word16 nb_sfm; + Word16 sum, hcode_l; + Word16 sfmsize[NB_SFM], sfm_start[NB_SFM], sfm_end[NB_SFM]; + Word16 num_sfm, numnrmibits; + Word16 nf_idx; + Word16 normqlg2[NB_SFM], R[NB_SFM]; + Word16 pulses[NB_SFM], maxpulse[NB_SFM]; + Word16 env_stab; /*Q15*/ + Word16 Rsubband[NB_SFM]; /*Q3*/ + Word16 start_norm, Npeaks = 0; + Word16 noise_level[HVQ_BWE_NOISE_BANDS]; /*Q15*/ + Word16 peak_idx[HVQ_MAX_PEAKS]; + Word16 hq_generic_offset; + Word16 num_env_bands; + Word16 hq_generic_exc_clas = 0; + Word16 core_sfm; + Word16 har_freq_est1, har_freq_est2; + Word16 flag_dis; + const Word16 *subband_search_offset; + Word16 wBands[2]; + Word16 bits, i; + Word16 t_audio_q_norm[L_FRAME48k_EXT]; + Word16 Q_audio; + Word16 b_delta_env; + Word16 tmp, n_band; + Word16 Q_shift; + Word16 bits_left; + Word16 csw_flag1, csw_flag2; + + HQ_DEC_HANDLE hHQ_core = st_fx->hHQ_core; + + move16(); + + Q_audio = 0; /* to avoid compilation warnings */ + + /*------------------------------------------------------------------* + * Initializations + *------------------------------------------------------------------*/ + + set16_fx( pulses, 0, NB_SFM ); + set16_fx( maxpulse, 0, NB_SFM ); + flag_dis = 1; + move16(); + har_freq_est1 = 0; + move16(); + har_freq_est2 = 0; + move16(); + set16_fx( peak_idx, 0, HVQ_MAX_PEAKS ); + + /*------------------------------------------------------------------* + * Decode classification + *------------------------------------------------------------------*/ + + bits = ivas_hq_classifier_dec_fx( st_fx, st_fx->core_brate, length, is_transient, hqswb_clas ); + bits_left = sub( num_bits, bits ); + + /*------------------------------------------------------------------* + * set quantization parameters + *------------------------------------------------------------------*/ + ivas_hq_configure_fx( length, *hqswb_clas, st_fx->core_brate, &num_sfm, &nb_sfm, &start_norm, + &num_env_bands, &numnrmibits, &hq_generic_offset, sfmsize, sfm_start, sfm_end ); + + /*------------------------------------------------------------------* + * Unpacking bitstream + *------------------------------------------------------------------*/ + + nf_idx = 0; + move16(); + test(); + test(); + test(); + IF( !*is_transient && NE_16( *hqswb_clas, HQ_HVQ ) && !( EQ_16( length, L_FRAME16k ) && LE_32( st_fx->core_brate, HQ_32k ) ) ) + { + nf_idx = get_next_indice( st_fx, 2 ); + } + + /*------------------------------------------------------------------* + * Decode envelope + *------------------------------------------------------------------*/ + + hcode_l = decode_envelope_indices_fx( st_fx, start_norm, num_env_bands, numnrmibits, ynrm, NORMAL_HQ_CORE, *is_transient ); + bits_left = sub( bits_left, add( hcode_l, NORM0_BITS + FLAGS_BITS ) ); + + dequantize_norms_fx( st_fx, start_norm, num_env_bands, *is_transient, ynrm, normqlg2 ); + + test(); + IF( EQ_16( *hqswb_clas, HQ_GEN_SWB ) || EQ_16( *hqswb_clas, HQ_GEN_FB ) ) + { + hq_generic_exc_clas = swb_bwe_gain_deq_fx( st_fx, HQ_CORE, NULL, SWB_fenv, st_fx->core_brate >= HQ_32k, *hqswb_clas ); /* Use (st->core_brate >= HQ_32k) to be consistent with hq_configure */ + IF( EQ_16( hq_generic_exc_clas, HQ_GENERIC_SP_EXC ) ) + { + bits_left = add( bits_left, 1 ); /* conditional 1 bit saving for representing HQ GENERIC excitation class */ + } + map_hq_generic_fenv_norm_fx( *hqswb_clas, SWB_fenv, ynrm, normqlg2, num_env_bands, nb_sfm, hq_generic_offset ); + } + + env_stab = 0; + move16(); + + csw_flag1 = s_and( core_switching_flag, (Word16) NE_16( st_fx->element_mode, EVS_MONO ) ); + csw_flag2 = s_and( csw_flag1, (Word16) EQ_16( length, L_SPEC32k_EXT ) ); + test(); + IF( EQ_16( *hqswb_clas, HQ_HVQ ) ) + { + hHQ_core->mem_env_delta_fx = 0; + move16(); + } + ELSE IF( EQ_16( length, L_FRAME32k ) || csw_flag2 ) + { + env_stab = env_stability_fx( ynrm, SFM_N_ENV_STAB, hHQ_core->mem_norm_fx, &hHQ_core->mem_env_delta_fx, csw_flag1 ); + } + ELSE + { + hHQ_core->mem_norm_fx[0] = 31; + move16(); + hHQ_core->mem_env_delta_fx = 0; + move16(); + } + + IF( EQ_16( *hqswb_clas, HQ_HVQ ) ) + { + hHQ_core->env_stab_fx = 32767; + move16(); /* 1 in Q15, stable by definition */ + } + ELSE + { + IF( EQ_16( length, L_FRAME32k ) || csw_flag2 ) + { + move16(); /* calculated stability */ + hHQ_core->env_stab_fx = env_stab; + } + ELSE + { + hHQ_core->env_stab_fx = env_stability_fx( ynrm, SFM_N_ENV_STAB_WB, hHQ_core->mem_norm_hqfec_fx, &hHQ_core->mem_env_delta_hqfec_fx, csw_flag1 ); + } + } + hHQ_core->env_stab_plc_fx = env_stab_smo_fx( s_min( hHQ_core->env_stab_fx, sub( 32767, stab_trans_fx[L_STAB_TBL - 1] ) ), hHQ_core->env_stab_state_p_fx, &hHQ_core->envstabplc_hocnt_fx ); + + /*------------------------------------------------------------------* + * Bit allocation + *------------------------------------------------------------------*/ + + ivas_hq_bit_allocation_fx( st_fx->core_brate, length, *hqswb_clas, &bits_left, normqlg2, nb_sfm, sfmsize, noise_level, + R, Rsubband, &sum, &core_sfm, num_env_bands ); + + test(); + test(); + IF( EQ_16( *hqswb_clas, HQ_GEN_SWB ) && GT_16(st_fx->bws_cnt1_fx, 0) && LT_32( st_fx->core_brate, HQ_32k ) ) + { + tmp = i_mult( st_fx->bws_cnt1_fx, 1638 ); + move16(); + IF( EQ_16( st_fx->L_frame, L_FRAME16k ) ) + { + FOR( n_band = 0; n_band < 4; n_band++ ) + { + SWB_fenv[n_band] = mult_r( SWB_fenv[n_band], tmp ); + move16(); + } + } + + FOR( n_band = 4; n_band < SWB_FENV; n_band++ ) + { + SWB_fenv[n_band] = mult_r( SWB_fenv[n_band], tmp ); + move16(); + } + } + + test(); + IF( EQ_16( *hqswb_clas, HQ_GEN_SWB ) || EQ_16( *hqswb_clas, HQ_GEN_FB ) ) + { + b_delta_env = get_nor_delta_hf_fx( st_fx, ynrm, Rsubband, num_env_bands, nb_sfm, core_sfm ); + sum = sub( sum, b_delta_env ); + } + + /*------------------------------------------------------------------* + * Decode spectral fine structure using HVQ/PVQ + *------------------------------------------------------------------*/ + + IF( EQ_16( *hqswb_clas, HQ_HVQ ) ) + { + hvq_dec_fx( st_fx, bits_left, st_fx->core_brate, ynrm, R, noise_level, peak_idx, &Npeaks, t_audio_q, st_fx->core ); + } + ELSE + { + ivas_pvq_core_dec_fx( st_fx, sfm_start, sfm_end, sfmsize, t_audio_q_norm, &Q_audio, sum, nb_sfm, Rsubband, R, pulses, maxpulse, HQ_CORE ); + } + + test(); + IF( EQ_16( *hqswb_clas, HQ_HVQ ) || EQ_16( *hqswb_clas, HQ_HARMONIC ) ) + { + subband_search_offset = subband_search_offsets_13p2kbps_Har; + wBands[0] = SWB_SB_BW_LEN0_16KBPS_HAR; + move16(); + wBands[1] = SWB_SB_BW_LEN1_16KBPS_HAR; + move16(); + + IF( EQ_16( *hqswb_clas, HQ_HARMONIC ) ) + { + Q_shift = sub( SWB_BWE_LR_Qs, Q_audio ); + FOR( i = 0; i < 300; i++ ) + { + t_audio_q[i] = L_shl( L_deposit_l( t_audio_q_norm[i] ), Q_shift ); /* Q12 */ + } + } + + har_est_fx( t_audio_q, 300, &har_freq_est1, &har_freq_est2, &flag_dis, &hHQ_core->prev_frm_hfe2_fx, subband_search_offset, wBands, &hHQ_core->prev_stab_hfe2_fx ); + + hHQ_core->prev_frm_hfe2_fx = har_freq_est2; + move16(); + } + + test(); + test(); +#if 0 + IF ( NE_16(*hqswb_clas, HQ_HARMONIC)||NE_16(*hqswb_clas,HQ_HVQ)||flag_dis==0) // TV2VE -> always reset in floating point code, is it OK +#endif + { + hHQ_core->prev_frm_hfe2_fx = 0; /*reset*/ + move16(); + hHQ_core->prev_stab_hfe2_fx = 0; /*reset*/ + move16(); + } + + /*------------------------------------------------------------------* + * Spectral filling + *------------------------------------------------------------------*/ + ivas_fill_spectrum_fx( t_audio_q_norm, t_audio_q, R, *is_transient, ynrm, SWB_fenv, hq_generic_offset, nf_idx, length, env_stab, + &hHQ_core->no_att_hangover_fx, &hHQ_core->energy_lt_fx, &hHQ_core->hq_generic_seed_fx, hq_generic_exc_clas, + core_sfm, *hqswb_clas, noise_level, st_fx->core_brate, hHQ_core->prev_noise_level_fx, &hHQ_core->prev_R_fx, hHQ_core->prev_coeff_out_fx, peak_idx, Npeaks, pulses, hHQ_core->old_is_transient_fx[0], + hHQ_core->prev_normq_fx, hHQ_core->prev_env_fx, st_fx->prev_bfi, sfmsize, sfm_start, sfm_end, + &st_fx->hBWE_FD->prev_L_swb_norm_fx, hHQ_core->prev_hqswb_clas_fx, num_sfm, hHQ_core->prev_env_Q, num_env_bands, st_fx->element_mode ); + + enforce_zero_for_min_envelope_fx( *hqswb_clas, ynrm, t_audio_q, nb_sfm, sfm_start, sfm_end ); + + + IF( EQ_16( *is_transient, 1 ) ) + { + ivas_de_interleave_spectrum_fx( t_audio_q, length ); + } + + /*------------------------------------------------------------------* + * WB/SWB bandwidth switching + *------------------------------------------------------------------*/ + ivas_hq_pred_hb_bws_fx( st_fx, ynrm, length, *hqswb_clas, SWB_fenv ); + + /* update */ + hHQ_core->prev_hqswb_clas_fx = *hqswb_clas; + move16(); + + return; +} +#endif + void hq_hr_dec_fx( Decoder_State *st_fx, /* i/o: decoder state structure fx */ Word32 *t_audio_q, /* o : transform-domain coefficients Q12 */ diff --git a/lib_dec/init_dec.c b/lib_dec/init_dec.c index 1affc9b9e..1d9fe75ca 100644 --- a/lib_dec/init_dec.c +++ b/lib_dec/init_dec.c @@ -43,6 +43,11 @@ #include "prot_fx1.h" #include "prot_fx2.h" #include "wmc_auto.h" +#ifdef IVAS_FLOAT_FIXED +#include "prot_fx1.h" +#include "prot_fx2.h" +#include "ivas_prot_fx.h" +#endif /*----------------------------------------------------------------------* * init_decoder() @@ -332,6 +337,9 @@ ivas_error init_decoder( } /* HQ core initialization */ +#ifdef IVAS_FLOAT_FIXED + HQ_core_dec_init( st->hHQ_core ); +#endif HQ_core_dec_init_flt( st->hHQ_core ); if ( st->element_mode == EVS_MONO ) @@ -603,6 +611,9 @@ ivas_error init_decoder( st->hTcxDec->old_synthFB_fx = st->hTcxDec->synth_history_fx + NS2SA( st->output_Fs, PH_ECU_MEM_NS ); #endif st->hTcxDec->prev_good_synth = st->hTcxDec->old_synthFB + NS2SA( st->output_Fs, PH_ECU_LOOKAHEAD_NS ); +#ifdef IVAS_FLOAT_FIXED + st->hTcxDec->prev_good_synth_fx = st->hTcxDec->old_synthFB_fx + NS2SA(st->output_Fs, PH_ECU_LOOKAHEAD_NS); +#endif } else { diff --git a/lib_dec/ivas_core_dec.c b/lib_dec/ivas_core_dec.c index 666d5840c..eaa9b94c5 100644 --- a/lib_dec/ivas_core_dec.c +++ b/lib_dec/ivas_core_dec.c @@ -396,7 +396,159 @@ ivas_error ivas_core_dec( if ( st->core == HQ_CORE ) { /* HQ core decoder */ +#ifdef IVAS_FLOAT_FIXED + Word16 synth_fx[L_FRAME48k]; + Word16 output_fx[L_FRAME48k]; + Word16 Q_synth = 0, Q_output = 0; + HQ_DEC_HANDLE hHQ_core; + Word16 tmp_size = NS2SA( output_frame * FRAMES_PER_SEC, PH_ECU_LOOKAHEAD_NS ); + + hHQ_core = st->hHQ_core; + + st->Q_syn = 0; + st->Q_exc = 0; + + st->hHQ_core->Q_old_wtda = -1; + st->hHQ_core->Q_old_wtda_LB = -1; + + floatToFixed_arr( synth[n], synth_fx, st->Q_syn, L_FRAME48k ); + floatToFixed_arr( output[n], output_fx, st->Q_syn, L_FRAME48k ); + +#ifndef IVAS_FLOAT_CONV_TO_BE_REMOVED + floatToFixed_arr( hHQ_core->old_out, hHQ_core->old_out_fx, hHQ_core->Q_old_wtda, L_FRAME48k ); + floatToFixed_arr( hHQ_core->old_outLB, hHQ_core->old_out_LB_fx, hHQ_core->Q_old_wtda_LB, L_FRAME32k ); + floatToFixed_arr( st->hTcxDec->old_syn_Overl_float, st->hTcxDec->old_syn_Overl, -1, L_FRAME32k / 2 ); + floatToFixed_arr( hHQ_core->oldgapsynth, hHQ_core->oldgapsynth_fx, 0, L_FRAME32k ); + floatToFixed_arr( st->old_Aq_12_8, st->old_Aq_12_8_fx, Q12, M + 1 ); + floatToFixed_arrL( st->old_pitch_buf, st->old_pitch_buf_fx, Q16, 2 * NB_SUBFR16k + 2 ); + floatToFixed_arr( st->mem_pitch_gain_float, st->mem_pitch_gain, Q14, 2 * NB_SUBFR16k + 2 ); + floatToFixed_arr( st->old_exc, st->old_exc_fx, st->Q_exc, L_EXC_MEM_DEC ); + floatToFixed_arrL( hHQ_core->prev_normq, hHQ_core->prev_normq_fx, Q14, SFM_N_WB ); + FOR( i = 0; i < SFM_N_WB; ++i ) + { + hHQ_core->prev_env_fx[i] = floatToFixed( hHQ_core->prev_env[i], hHQ_core->prev_env_Q[i] ); + } + hHQ_core->energy_lt_fx = floatToFixed( hHQ_core->energy_lt, Q13 ); + floatToFixed_arr( hHQ_core->prev_noise_level, hHQ_core->prev_noise_level_fx, Q15, 2 ); + floatToFixed_arrL( hHQ_core->prev_coeff_out, hHQ_core->prev_coeff_out_fx, Q12, L_HQ_WB_BWE ); + FOR( i = 0; i < 3; ++i ) + { + hHQ_core->old_is_transient_fx[i] = hHQ_core->old_is_transient[i]; + } + hHQ_core->prev_ni_ratio_fx = (Word16) floatToFixed( hHQ_core->prev_ni_ratio, Q15 ); + hHQ_core->mean_prev_nc_fx = floatToFixed( hHQ_core->mean_prev_nc, 0 ); + hHQ_core->wmold_hb_fx = (Word16) floatToFixed( hHQ_core->wmold_hb, Q15 ); + hHQ_core->mean_prev_hb_fx = floatToFixed( hHQ_core->mean_prev_hb, 0 ); + hHQ_core->memfilt_lb_fx = (Word16) floatToFixed( hHQ_core->memfilt_lb, 0 ); + st->hBWE_FD->prev_L_swb_norm_fx = st->hBWE_FD->prev_L_swb_norm; + hHQ_core->HqVoicing_fx = hHQ_core->HqVoicing; + hHQ_core->ph_ecu_HqVoicing_fx = hHQ_core->ph_ecu_HqVoicing; + hHQ_core->prev_hqswb_clas_fx = hHQ_core->prev_hqswb_clas; + hHQ_core->hq_generic_seed_fx = hHQ_core->hq_generic_seed; + FOR( i = 0; i < SFM_N_ENV_STAB; ++i ) + { + hHQ_core->mem_norm_fx[i] = hHQ_core->mem_norm[i]; + hHQ_core->mem_norm_hqfec_fx[i] = hHQ_core->mem_norm_hqfec[i]; + } + hHQ_core->mem_env_delta_fx = hHQ_core->mem_env_delta; + hHQ_core->mem_env_delta_hqfec_fx = hHQ_core->mem_env_delta_hqfec; + hHQ_core->no_att_hangover_fx = hHQ_core->no_att_hangover; + hHQ_core->pastpre_fx = hHQ_core->pastpre; + hHQ_core->prevflag_fx = hHQ_core->prevflag; + hHQ_core->oldHqVoicing_fx = hHQ_core->oldHqVoicing; + floatToFixed_arr( hHQ_core->env_stab_state_p, hHQ_core->env_stab_state_p_fx, Q15, NUM_ENV_STAB_PLC_STATES ); + hHQ_core->envstabplc_hocnt_fx = hHQ_core->envstabplc_hocnt; + floatToFixed_arr( st->hTcxDec->prev_good_synth - tmp_size, st->hTcxDec->prev_good_synth_fx - tmp_size, 0, 2 * output_frame + tmp_size ); + hHQ_core->time_offs_fx = hHQ_core->time_offs; + floatToFixed_arr( hHQ_core->X_sav, hHQ_core->X_sav_fx, hHQ_core->Q_X_sav, PH_ECU_SPEC_SIZE ); + hHQ_core->num_p_fx = hHQ_core->num_p; + FOR( i = 0; i < MAX_PLOCS; ++i ) + { + hHQ_core->plocs_fx[i] = hHQ_core->plocs[i]; + } + floatToFixed_arrL( hHQ_core->plocsi, hHQ_core->plocsi_fx, Q16, MAX_PLOCS ); + hHQ_core->env_stab_fx = (Word16) floatToFixed( hHQ_core->env_stab, Q15 ); + hHQ_core->last_fec_fx = hHQ_core->last_fec; + hHQ_core->ph_ecu_HqVoicing_fx = hHQ_core->ph_ecu_HqVoicing; + hHQ_core->ph_ecu_active_fx = hHQ_core->ph_ecu_active; + floatToFixed_arr( hHQ_core->mag_chg_1st, hHQ_core->mag_chg_1st_fx, Q15, LGW_MAX ); + floatToFixed_arr( hHQ_core->Xavg, hHQ_core->Xavg_fx, 0, LGW_MAX ); + hHQ_core->beta_mute_fx = (Word16) floatToFixed( hHQ_core->beta_mute, Q15 ); + hHQ_core->env_stab_plc_fx = (Word16) floatToFixed( hHQ_core->env_stab_plc, Q15 ); + floatToFixed_arr( st->t_audio_q, st->t_audio_q_fx, -1, L_FRAME ); +#endif + + ivas_hq_core_dec_fx( st, synth_fx, &Q_synth, output_frame, NORMAL_HQ_CORE, core_switching_flag[n], output_fx, &Q_output ); + + fixedToFloat_arr( synth_fx, synth[n], Q_synth, L_FRAME48k ); + fixedToFloat_arr( output_fx, output[n], Q_output, L_FRAME48k ); + +#ifndef IVAS_FLOAT_CONV_TO_BE_REMOVED + fixedToFloat_arr( hHQ_core->old_out_fx, hHQ_core->old_out, hHQ_core->Q_old_wtda, L_FRAME48k ); + fixedToFloat_arr( hHQ_core->old_out_LB_fx, hHQ_core->old_outLB, hHQ_core->Q_old_wtda_LB, L_FRAME32k ); + fixedToFloat_arr( st->hTcxDec->old_syn_Overl, st->hTcxDec->old_syn_Overl_float, -1, L_FRAME32k / 2 ); + fixedToFloat_arr( hHQ_core->oldgapsynth_fx, hHQ_core->oldgapsynth, 0, L_FRAME32k ); // Check + fixedToFloat_arr( st->old_Aq_12_8_fx, st->old_Aq_12_8, Q12, M + 1 ); // Check + fixedToFloat_arrL( st->old_pitch_buf_fx, st->old_pitch_buf, Q16, 2 * NB_SUBFR16k + 2 ); + fixedToFloat_arr( st->mem_pitch_gain, st->mem_pitch_gain_float, Q14, 2 * NB_SUBFR16k + 2 ); + fixedToFloat_arr( st->old_exc_fx, st->old_exc, st->Q_exc, L_EXC_MEM_DEC ); + fixedToFloat_arrL( hHQ_core->prev_normq_fx, hHQ_core->prev_normq, Q14, SFM_N_WB ); + FOR( i = 0; i < SFM_N_WB; ++i ) + { + hHQ_core->prev_env[i] = fixedToFloat( hHQ_core->prev_env_fx[i], hHQ_core->prev_env_Q[i] ); + } + hHQ_core->energy_lt = fixedToFloat( hHQ_core->energy_lt_fx, Q13 ); + fixedToFloat_arr( hHQ_core->prev_noise_level_fx, hHQ_core->prev_noise_level, Q15, 2 ); + fixedToFloat_arrL( hHQ_core->prev_coeff_out_fx, hHQ_core->prev_coeff_out, Q12, L_HQ_WB_BWE ); + FOR( i = 0; i < 3; ++i ) + { + hHQ_core->prev_coeff_out[i] = hHQ_core->old_is_transient_fx[i]; + } + hHQ_core->prev_ni_ratio = fixedToFloat( hHQ_core->prev_ni_ratio_fx, Q15 ); + hHQ_core->mean_prev_nc = fixedToFloat( hHQ_core->mean_prev_nc_fx, 0 ); + hHQ_core->wmold_hb = fixedToFloat( hHQ_core->wmold_hb_fx, Q15 ); + hHQ_core->mean_prev_hb = fixedToFloat( hHQ_core->mean_prev_hb_fx, 0 ); + hHQ_core->memfilt_lb = fixedToFloat( hHQ_core->memfilt_lb_fx, 0 ); + st->hBWE_FD->prev_L_swb_norm = st->hBWE_FD->prev_L_swb_norm_fx; + hHQ_core->HqVoicing = hHQ_core->HqVoicing_fx; + hHQ_core->ph_ecu_HqVoicing = hHQ_core->ph_ecu_HqVoicing_fx; + hHQ_core->prev_hqswb_clas = hHQ_core->prev_hqswb_clas_fx; + hHQ_core->hq_generic_seed = hHQ_core->hq_generic_seed_fx; + FOR( i = 0; i < SFM_N_ENV_STAB; ++i ) + { + hHQ_core->mem_norm[i] = hHQ_core->mem_norm_fx[i]; + hHQ_core->mem_norm_hqfec[i] = hHQ_core->mem_norm_hqfec_fx[i]; + } + hHQ_core->mem_env_delta = hHQ_core->mem_env_delta_fx; + hHQ_core->mem_env_delta_hqfec = hHQ_core->mem_env_delta_hqfec_fx; + hHQ_core->no_att_hangover = hHQ_core->no_att_hangover_fx; + hHQ_core->pastpre = hHQ_core->pastpre_fx; + hHQ_core->prevflag = hHQ_core->prevflag_fx; + hHQ_core->oldHqVoicing = hHQ_core->oldHqVoicing_fx; + fixedToFloat_arr( hHQ_core->env_stab_state_p_fx, hHQ_core->env_stab_state_p, Q15, NUM_ENV_STAB_PLC_STATES ); + hHQ_core->envstabplc_hocnt = hHQ_core->envstabplc_hocnt_fx; + fixedToFloat_arr( st->hTcxDec->prev_good_synth_fx - tmp_size, st->hTcxDec->prev_good_synth - tmp_size, 0, 2 * output_frame + tmp_size ); + hHQ_core->time_offs = hHQ_core->time_offs_fx; + fixedToFloat_arr( hHQ_core->X_sav_fx, hHQ_core->X_sav, hHQ_core->Q_X_sav, PH_ECU_SPEC_SIZE ); + hHQ_core->num_p = hHQ_core->num_p_fx; + FOR( i = 0; i < MAX_PLOCS; ++i ) + { + hHQ_core->plocs[i] = hHQ_core->plocs_fx[i]; + } + fixedToFloat_arrL( hHQ_core->plocsi_fx, hHQ_core->plocsi, Q16, MAX_PLOCS ); + hHQ_core->env_stab = fixedToFloat( hHQ_core->env_stab_fx, Q15 ); + hHQ_core->last_fec = hHQ_core->last_fec_fx; + hHQ_core->ph_ecu_HqVoicing = hHQ_core->ph_ecu_HqVoicing_fx; + hHQ_core->ph_ecu_active = hHQ_core->ph_ecu_active_fx; + fixedToFloat_arr( hHQ_core->mag_chg_1st_fx, hHQ_core->mag_chg_1st, Q15, LGW_MAX ); + fixedToFloat_arr( hHQ_core->Xavg_fx, hHQ_core->Xavg, 0, LGW_MAX ); + hHQ_core->beta_mute = fixedToFloat( hHQ_core->beta_mute_fx, Q15 ); + hHQ_core->env_stab_plc = fixedToFloat( hHQ_core->env_stab_plc_fx, Q15 ); + fixedToFloat_arr( st->t_audio_q_fx, st->t_audio_q, -1, L_FRAME ); +#endif +#else hq_core_dec( st, synth[n], output_frame, NORMAL_HQ_CORE, core_switching_flag[n], output[n] ); +#endif } /*---------------------------------------------------------------------* diff --git a/lib_dec/pvq_core_dec_fx.c b/lib_dec/pvq_core_dec_fx.c index 634215f08..333576db2 100644 --- a/lib_dec/pvq_core_dec_fx.c +++ b/lib_dec/pvq_core_dec_fx.c @@ -8,6 +8,9 @@ #include "prot_fx1.h" /* Function prototypes */ #include "prot_fx2.h" /* Function prototypes */ #include "rom_com.h" /* Static table prototypes */ +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif /*-------------------------------------------------------------------* * Local prototypes @@ -202,6 +205,87 @@ void pvq_decode_frame_fx( * *-------------------------------------------------------------------*/ +#ifdef IVAS_FLOAT_FIXED +Word16 ivas_pvq_core_dec_fx( + Decoder_State *st_fx, + const Word16 *sfm_start, + const Word16 *sfm_end, + const Word16 *sfmsize, + Word16 coefs_quant[], /* o : output MDCT */ + Word16 *Q_coefs, + Word16 bits_tot, + Word16 nb_sfm, + Word16 *R, /* Q3 */ + Word16 *Rs, + Word16 *npulses, + Word16 *maxpulse, + const Word16 core ) +{ + Word16 i; + Word16 R_upd; + Word16 ord[NB_SFM_MAX]; + Word16 pulse_vector[L_SPEC48k_EXT]; + Word16 pvq_bits; + Word16 gain_bits_array[NB_SFM]; + Word16 fg_pred[NB_SFM_MAX]; + + IF( st_fx->hHQ_core != NULL ) + { + st_fx->hHQ_core->ber_occured_in_pvq = 0; + move16(); + } + + R_upd = shl( bits_tot, 3 ); + ivas_assign_gain_bits_fx( core, nb_sfm, sfmsize, R, gain_bits_array, &R_upd ); + + pvq_bits = shr( R_upd, 3 ); + + pvq_decode_frame_fx( st_fx, coefs_quant, npulses, pulse_vector, sfm_start, + sfm_end, sfmsize, nb_sfm, R, pvq_bits, core ); + + IF( Rs != NULL ) + { + FOR( i = 0; i < nb_sfm; i++ ) + { + IF( LE_16( npulses[i], 0 ) ) + { + Rs[i] = 0; + move16(); /* Update Rs in case no pulses were assigned */ + } + } + } + + FOR( i = 0; i < nb_sfm; i++ ) + { + ord[i] = i; + move16(); + IF( LE_16( npulses[i], 0 ) ) + { + R[i] = 0; + move16(); /* Update in case no pulses were assigned */ + } + } + + get_max_pulses_fx( sfm_start, sfm_end, ord, npulses, nb_sfm, pulse_vector, maxpulse ); + + ivas_fine_gain_pred_fx( sfm_start, sfm_end, sfmsize, ord, npulses, maxpulse, R, + nb_sfm, coefs_quant, pulse_vector, fg_pred, core ); + + fine_gain_dec_fx( st_fx, ord, nb_sfm, gain_bits_array, fg_pred ); + IF( st_fx->hHQ_core != NULL ) + { + IF( NE_16( st_fx->hHQ_core->ber_occured_in_pvq, 0 ) ) + { + set16_fx( fg_pred, 1, nb_sfm ); /* low complex ECU action in case of detetected BER in PVQ decoding */ + } + } + apply_gain_fx( ord, sfm_start, sfm_end, nb_sfm, fg_pred, coefs_quant ); + *Q_coefs = 12; + + return bits_tot; +} +#endif + Word16 pvq_core_dec_fx( Decoder_State *st_fx, const Word16 *sfm_start, diff --git a/lib_dec/rom_dec.c b/lib_dec/rom_dec.c index 90d76175e..0888ebfeb 100644 --- a/lib_dec/rom_dec.c +++ b/lib_dec/rom_dec.c @@ -386,6 +386,34 @@ const float w_hamm_sana32k_2[L_PROT_HAMM_LEN2_32k] = 0.996522520331626f, 0.997387205951684f, 0.998128797691797f, 0.998747095971820f, 0.999241934392838f, 0.999613179781951f, 0.999860732228111f, 0.999984525109009f }; +const Word16 w_hamm_sana32k_2_fx[L_PROT_HAMM_LEN2_32k] = /* Q15 */ +{ + 2621, 2623, 2630, 2640, 2654, 2672, 2694, 2721, + 2751, 2785, 2824, 2866, 2913, 2963, 3017, 3076, + 3138, 3204, 3274, 3348, 3426, 3507, 3593, 3682, + 3775, 3871, 3972, 4076, 4184, 4295, 4410, 4529, + 4651, 4777, 4906, 5039, 5175, 5314, 5457, 5603, + 5752, 5904, 6060, 6219, 6381, 6546, 6714, 6884, + 7058, 7235, 7414, 7596, 7781, 7969, 8159, 8352, + 8547, 8745, 8945, 9148, 9353, 9560, 9769, 9980, + 10194, 10409, 10627, 10846, 11067, 11290, 11515, 11741, + 11969, 12199, 12430, 12662, 12896, 13131, 13367, 13605, + 13843, 14083, 14323, 14565, 14807, 15050, 15294, 15538, + 15783, 16029, 16275, 16521, 16768, 17015, 17262, 17509, + 17757, 18004, 18251, 18498, 18745, 18991, 19238, 19483, + 19729, 19973, 20217, 20461, 20704, 20945, 21186, 21427, + 21666, 21904, 22140, 22376, 22611, 22844, 23075, 23306, + 23534, 23762, 23987, 24211, 24433, 24653, 24872, 25088, + 25303, 25515, 25725, 25934, 26140, 26343, 26545, 26744, + 26940, 27134, 27326, 27515, 27701, 27884, 28065, 28243, + 28419, 28591, 28760, 28927, 29090, 29250, 29408, 29562, + 29712, 29860, 30004, 30146, 30283, 30418, 30548, 30676, + 30800, 30920, 31037, 31150, 31260, 31366, 31468, 31567, + 31662, 31753, 31840, 31924, 32003, 32079, 32151, 32219, + 32283, 32344, 32400, 32452, 32501, 32545, 32585, 32622, + 32654, 32682, 32707, 32727, 32743, 32755, 32763, 32767 +}; + const float w_hamm_sana16k_2[L_PROT_HAMM_LEN2_16k] = { 0.080000000000000f, 0.080248875229243f, 0.080995231617495f, 0.082238261557724f, 0.083976620009229f, 0.086208425953062f, 0.088931264427414f, 0.092142189140766f, @@ -401,6 +429,23 @@ const float w_hamm_sana16k_2[L_PROT_HAMM_LEN2_16k] = 0.941486723514159f, 0.948653981707932f, 0.955379049234843f, 0.961654649126531f, 0.967473990768381f, 0.972830777247415f, 0.977719212165966f, 0.982134005913770f, 0.986070381391670f, 0.989524079180756f, 0.992491362151336f, 0.994969019506760f, 0.996954370257714f, 0.998445266123226f, 0.999440093855253f, 0.999937776984316f }; + +const Word16 w_hamm_sana16k_2_fx[L_PROT_HAMM_LEN2_16k] = /* Q15 */ +{ + 2621, 2630, 2654, 2695, 2752, 2825, 2914, 3019, + 3140, 3277, 3430, 3598, 3781, 3979, 4192, 4420, + 4662, 4918, 5188, 5471, 5768, 6077, 6400, 6734, + 7080, 7438, 7807, 8186, 8576, 8976, 9385, 9803, + 10230, 10665, 11107, 11556, 12012, 12475, 12943, 13416, + 13893, 14375, 14861, 15349, 15840, 16333, 16827, 17323, + 17819, 18314, 18809, 19303, 19795, 20285, 20772, 21256, + 21735, 22211, 22681, 23147, 23606, 24059, 24505, 24943, + 25374, 25796, 26210, 26615, 27009, 27394, 27768, 28132, + 28484, 28824, 29153, 29468, 29772, 30062, 30338, 30602, + 30851, 31085, 31306, 31512, 31702, 31878, 32038, 32183, + 32312, 32425, 32522, 32603, 32668, 32717, 32750, 32766 +}; + const Word16 swb_hr_inv_frm_len[4] = /* in Q19 */ { 26214, /* 1/(160/8) */ diff --git a/lib_dec/rom_dec.h b/lib_dec/rom_dec.h index 86b095167..0ec9edbaf 100644 --- a/lib_dec/rom_dec.h +++ b/lib_dec/rom_dec.h @@ -77,6 +77,8 @@ extern const Word16 inv_tbl_2n_minus1[]; extern const Word16 w_hamm_sana48k_2_fx[]; +extern const Word16 w_hamm_sana32k_2_fx[]; +extern const Word16 w_hamm_sana16k_2_fx[]; extern const float h_high3_32_flt[L_FIR_FER2]; extern const float h_high3_16_flt[L_FIR_FER2]; extern const Word16 h_high3_32[L_FIR_FER2]; -- GitLab