/*==================================================================================== EVS Codec 3GPP TS26.443 Jun 30, 2015. Version CR 26.443-0006 ====================================================================================*/ #include #include #include "options.h" #include "cnst.h" #include "prot.h" #include "rom_com.h" #include "stat_com.h" /*--------------------------------------------------------------------------* * GetSubbandCorrIndex2_har() * * Finds the index of best correlation between highband (*inBuf) and lowband (*predBuf) for current subband of length (fLen) *--------------------------------------------------------------------------*/ static short GetSubbandCorrIndex2_har( /* o : best correlation index */ const float *inBuf, /* i : target buffer (i.e., highband signal) */ const float *predBuf, /* i : prediction buffer (i.e., lowband) */ const short fLen, /* i : window length */ const short maxLag, /* i : search length */ const GainItem *G_item, /* i : nZero nonzero components (value+index) */ const short nZero, /* i : number of nonzero components used in */ short *prev_frame_bstindx /* i : previous frame best Indices */ ) { short bestIdx, i, j; float corr, energy, corr_sq; float lagCorr_sq, lagEnergy, eOld; short absPos; short N1, N2; absPos = 0; bestIdx = 0; lagCorr_sq = 0.0f; lagEnergy = 1e30f; for( i = 0, energy = 0.0f; i < fLen - 1; i++, predBuf++ ) { energy += *predBuf **predBuf; } predBuf -= fLen-1; eOld = 0.0f; N1 = max(0, *prev_frame_bstindx-maxLag/2); if( *prev_frame_bstindx < 0 ) { N2 = maxLag-1; } else { N2 = min(maxLag-1, *prev_frame_bstindx+maxLag/2); } predBuf +=N1; /* find the best lag */ for( i = N1; i <= N2; i++ ) { corr = 0.0f; /* get the energy, remove the old and update with the new energy index */ for(j = 0, energy = 0.0f; j < fLen; j++, predBuf++) { energy += *predBuf **predBuf; } predBuf -= fLen; /* energy to be removed in the next lag */ eOld = *predBuf; eOld *= eOld; /* get cross-correlation */ if( energy ) { for(j = 0, corr = 0.0f; j < nZero; j++) { corr += inBuf[G_item[j].gainIndex]* predBuf[G_item[j].gainIndex]; } corr_sq = corr*corr; if( (double)lagCorr_sq*(double)energy < (double)corr_sq*(double)lagEnergy ) { bestIdx = i; lagCorr_sq = corr_sq; lagEnergy = energy; } } predBuf++; absPos++; } if( lagCorr_sq == 0.0f && *prev_frame_bstindx < 0 ) { bestIdx = 0; } else { if( lagCorr_sq == 0.0f ) { bestIdx = *prev_frame_bstindx; } } *prev_frame_bstindx = bestIdx; return bestIdx; } /*--------------------------------------------------------------------------* * getswbindices_har() * * Finds the pulse index of best correlation between highband (*yos) and lowband (*y2) for two groups of length sbLen *--------------------------------------------------------------------------*/ static void getswbindices_har( float *yos, /* i : original input spectrum */ float *y2, /* i : decoded spectrum */ const short nBands_search, /* i : number of bands */ short *lagIndices, /* o : pulse index */ short *prev_frame_bstindx, /* i/o: prev frame index */ const short swb_lowband, /* i : length of the LF spectrum */ const short *subband_offsets, const short *sbWidth, const short *subband_search_offset ) { GainItem Nbiggest[(NB_SWB_SUBBANDS_HAR_SEARCH_SB)*N_NBIGGEST_PULSEARCH]; const float *refBuf,*predBuf; short search_offset[NB_SWB_SUBBANDS_HAR_SEARCH_SB]; short nlags[NB_SWB_SUBBANDS_HAR_SEARCH_SB]; short j, k, sb; short n_nbiggestsearch[NB_SWB_SUBBANDS_HAR]; float low_freqsgnl[L_FRAME32k]; /* Initializations */ predBuf = y2; /* Get the number of HF groups for performing Similarity search */ for( sb = 0; sb < nBands_search; sb++ ) { nlags[sb] = (short)pow(2, bits_lagIndices_mode0_Har[sb]); } for( sb=0; sb search_offset[sb] - sbWidth[sb] - nlags[sb]/2; j-- ) { low_freqsgnl[k] = predBuf[j]; k++; } } /* correlation b/w HF spectrum Group1 of length sbLen and decoded LF spectrum */ lagIndices[sb] = GetSubbandCorrIndex2_har( yos + swb_lowband + subband_offsets[sb], low_freqsgnl, sbWidth[sb], nlags[sb], Nbiggest+(sb*N_NBIGGEST_PULSEARCH), n_nbiggestsearch[sb], &prev_frame_bstindx[sb] ); } return; } static short GetSubbandCorrIndex2_pulsestep( const float *inBuf, const float *predBuf, const float *predBufMa, const short fLen, const short maxLag, const GainItem *G_item, const short nZero, short ssearch_buflim, const float *predBuf_ni ) { short bestIdx, i, j; float corr, energy, corr_sq; float lagCorr_sq, lagEnergy; short absPos; short ib_flag = 0; absPos = 0; bestIdx = -1; lagCorr_sq = 0.0f; lagEnergy = 1e30f; /* Get the initial energy for zero lag */ while( *predBuf == 0.0f && absPos < ssearch_buflim ) { predBuf++; absPos++; predBuf_ni++; } if( absPos == ssearch_buflim ) { predBuf--; absPos--; predBuf_ni--; } for( i = 0, energy = 0.0f; i < fLen; i++, predBuf_ni++ ) { energy += *predBuf_ni **predBuf_ni; } predBuf_ni -= fLen; lagEnergy = energy; /* Find the best lag */ for( i = 0; i < maxLag; i++ ) { corr = 0.0f; /* Get the energy, remove the old and update with the new energy index */ for(j = 0, energy = 0.0f; j < fLen; j++, predBuf_ni++) { energy += *predBuf_ni **predBuf_ni; } predBuf_ni -= fLen; /* Get cross-correlation */ if( energy ) { for(j = 0, corr = 0.0f; j < nZero; j++) { corr += inBuf[G_item[j].gainIndex]* predBufMa[G_item[j].gainIndex]; } corr_sq = corr*corr; if( (lagCorr_sq == 0.0f && corr_sq == 0.0f) || (double)lagCorr_sq*(double)energy < (double)corr_sq*(double)lagEnergy ) { bestIdx = i; lagCorr_sq = corr_sq; lagEnergy = energy; } } predBuf++; absPos++; predBuf_ni++; while( *predBuf == 0.0f && absPos < ssearch_buflim ) { predBuf++; absPos++; predBuf_ni++; } if( absPos >= ssearch_buflim ) { if( bestIdx == -1 ) { ib_flag = 1; } break; } } if( ib_flag ) { bestIdx = 0; } return bestIdx; } /*--------------------------------------------------------------------------* * GetSWBIndices() * * Finds the subband lags for subband coding. Each lag corresponds to * the section that is copied and scaled from the low-frequency band * to form the high-frequency subband. * * The subbands are searched in two steps to reduce the complexity of * the search relative to full search. In first step, a most representative * subband is selected based on the similarity of the subbands.Full search * is performed for the selected subband.Based on the lagIndice value for * this subband, the region of highest interest is selected. A partial * search is performed for rest of the subbands around this region of the * low-frequency range. *--------------------------------------------------------------------------*/ static void GetSWBIndices( const float *predBuf, /* i : low-frequency band */ const float *targetBuf, /* i : high-frequency band */ const short nBands_search, /* i : number of search subbands */ const short *sbWidth, /* i : subband lengths */ short *lagIndices, /* o : selected lags for subband coding */ const short predBufLen, /* i : low-frequency band length */ GainItem *Nbiggest, /* o : most representative region */ const short *subband_offsets, /* o : N biggest components */ float *predBuf_ni /* i : low-frequency band filled noise */ ) { const float *refBuf; short search_offset[NB_SWB_SUBBANDS]; short nlags[NB_SWB_SUBBANDS]; short sbLen; short j, sb; short n_nbiggestsearch[NB_SWB_SUBBANDS]; short ssearch_buflim; float sspectra_ma[L_FRAME32k]; /* Initializations */ for (sb = 0; sb < nBands_search; sb++) { j = sb * N_NBIGGEST_PULSEARCH; sbLen = sbWidth[sb]; refBuf = targetBuf + subband_offsets[sb]; FindNBiggest2_simple(refBuf, Nbiggest+j, sbLen, &n_nbiggestsearch[sb],N_NBIGGEST_PULSEARCH); } /* Selection of most representative subband (full search) */ for ( sb = 0; sb < nBands_search; sb++ ) { nlags[sb] = (short)pow(2, bits_lagIndices[sb]); } for ( sb = 0; sb < nBands_search; sb++ ) { search_offset[sb] = subband_search_offsets[sb]; } sspectra_ma[0] = (predBuf_ni[0]+predBuf_ni[1])/2.0f; for( sb=1; sb < predBufLen-1; sb++ ) { sspectra_ma[sb] = (predBuf_ni[sb-1] + predBuf_ni[sb] + predBuf_ni[sb+1])/3.0f; } sspectra_ma[sb] = (predBuf_ni[sb-1]+predBuf_ni[sb])/2.0f; /* Partial search for rest of subbands except the last which is fixed */ for( sb = 0; sb < nBands_search; sb++ ) { sbLen = sbWidth[sb]; ssearch_buflim = predBufLen - (sbLen + search_offset[sb]); lagIndices[sb] = GetSubbandCorrIndex2_pulsestep( targetBuf + subband_offsets[sb], predBuf + search_offset[sb], sspectra_ma + search_offset[sb], sbLen, nlags[sb], Nbiggest+(sb*N_NBIGGEST_PULSEARCH),n_nbiggestsearch[sb], ssearch_buflim, predBuf_ni + search_offset[sb]); } return; } static void gethar_noisegn( Encoder_State *st, float spectra[], float noise_flr[], float xSynth_har[], const short sbWidth[], const short lagIndices[], const short bands, const short har_bands, const short fLenLow, const short fLenHigh, const short subband_offsets[], const short subband_search_offset[], short band_start[], short band_end[], short band_width[], float band_energy[], float be_tonal[], float *sspectra, const short har_freq_est2, const short pos_max_hfe2, short *pul_res, GainItem pk_sf[] ) { GainItem get_pk[N_NBIGGEST_SEARCH_LRG_B]; short n_nbiggestsearch,imin,gqlevs; short i; float hfspec[L_FRAME32k]; float g,g1,g2,dmin,d; /*Generate HF noise*/ genhf_noise( noise_flr, xSynth_har, sspectra, bands, har_bands, har_freq_est2, pos_max_hfe2, pul_res, pk_sf, fLenLow, fLenHigh, sbWidth, lagIndices, subband_offsets, subband_search_offset ); mvr2r(spectra+fLenLow,hfspec,fLenHigh); FindNBiggest2_simple(hfspec, get_pk, fLenHigh, &n_nbiggestsearch,N_NBIGGEST_SEARCH_LRG_B); for(i=0; iprev_hqswb_clas, &st->prev_ni_ratio ); /* Find best indices for each group */ getswbindices_har(spectra, sspectra_ni,nBands_search, lagIndices, prev_frm_index,fLenLow,subband_offsets, sbWidth , subband_search_offset); /* Write the indices into the bitstream */ for (k = 0; k < nBands_search; k++) { push_indice( st,IND_LAGINDICES, lagIndices[k], bits_lagIndices_mode0_Har[k]); } if(flag_dis == 0) { if(har_freq_est2 != SWB_HAR_RAN1 || har_freq_est2 != *prev_frm_hfe2) { har_freq_est2 += lagIndices[0]; } } /*noise generation*/ gethar_noisegn( st, spectra, sspectra_diff, xSynth_har, sbWidth, lagIndices, BANDS, har_bands, fLenLow, fLenHigh, subband_offsets, subband_search_offset, band_start, band_end, band_width, band_energy, be_tonal, sspectra, har_freq_est2, pos_max_hfe2, pul_res, pk_sf ); /*HF Spectrum Generation*/ Gettonl_scalfact( xSynth_har, spectra_ni, fLenLow, fLenHigh, har_bands, BANDS, band_energy, band_start, band_end, p2a_flags, be_tonal, pk_sf, pul_res ); if(flag_dis == 0) { *prev_frm_hfe2 = 0; } else { *prev_frm_hfe2 = har_freq_est2; } for( k = har_bands; k < BANDS; k++ ) { for( i = band_start[k]; i <= band_end[k]; i++ ) { spectra[i] = xSynth_har[i-fLenLow]; } } } else { /* Spectrum normalization for the corecoder*/ ss_min = spectrumsmooth_noiseton(spectra,spectra_ni,sspectra,sspectra_diff,sspectra_ni,fLenLow, ni_seed); /* Get lag indices */ GetSWBIndices( sspectra, spectra + fLenLow, nBands, sbWidth, lagIndices, fLenLow, Nbiggest, subband_offsets, sspectra ); /* Bitstream operations */ for (k = 0; k < nBands; k++) { if( p2a_flags[BANDS-NB_SWB_SUBBANDS+k] == 0 ) { push_indice( st,IND_LAGINDICES,lagIndices[k], bits_lagIndices[k]); } else { lagIndices[k] = 0; } } convert_lagIndices_pls2smp( lagIndices, nBands, lagIndices, sspectra, sbWidth, fLenLow ); /*get levels for missing bands*/ GetlagGains( sspectra_ni, &band_energy[BANDS-NB_SWB_SUBBANDS], nBands, sbWidth, lagIndices, fLenLow, lagGains ); for(k=0; kprev_En_sb, p2a_flags, BANDS, band_start, band_end, fLenLow ); for( k = BANDS - NB_SWB_SUBBANDS; k < BANDS; k++ ) { if( p2a_flags[k] == 0 ) { for( i = band_start[k]; i <= band_end[k]; i++ ) { spectra[i] = xSynth_har[i-fLenLow]; } } else { for( i = band_start[k]; i <= band_end[k]; i++ ) { spectra[i] = spectra_ni[i]; } } } } return; } /*--------------------------------------------------------------------------* * swb_bwe_enc_lr() * * Main encoding routine of SWB BWE for the LR MDCT core *--------------------------------------------------------------------------*/ void swb_bwe_enc_lr( Encoder_State *st, /* i/o: encoder state structure */ const float m_core[], /* i : lowband synthesis */ const float m_orig[], /* i/o: scaled orig signal (MDCT) */ float m[], /* o : highband synthesis with lowband zeroed */ const long total_brate, /* i : total bitrate for selecting subband pattern */ short BANDS, /* i : Total number of Subbands in a frame */ short *band_start, /* i : band start of each SB */ short *band_end, /* i : band end of each SB */ float *band_energy, /* i : band_energy of each SB */ short *p2a_flags, /* i : HF tonal indicator */ const short hqswb_clas, /* i : HQ_NORMAL or HQ_HARMONIC mode */ short lowlength, /* i : lowband length */ short highlength, /* i : highband length */ short *prev_frm_index, /* i/o: previous frame lag index for harmonic mode */ const short har_bands, /* i : Number of LF harmonic bands */ short *prev_frm_hfe2, short *prev_stab_hfe2, short band_width[], /* i : subband bandwidths */ const float y2_ni[], /* i/o: Sparse filled core coder */ short *ni_seed /* i/o: random seed for search buffer NI */ ) { short k; short nBands; short nBands_search; short wBands[NB_SWB_SUBBANDS]; short lagIndices[NB_SWB_SUBBANDS]; float lagGains[NB_SWB_SUBBANDS]; const short *subband_offsets; short swb_lowband, swb_highband; const short *subband_search_offset; subband_search_offset = subband_search_offsets_13p2kbps_Har; subband_offsets = subband_offsets_sub5_13p2kbps_Har; hf_parinitiz(total_brate,hqswb_clas,lowlength,highlength,wBands,&subband_search_offset,&subband_offsets,&nBands,&nBands_search,&swb_lowband,&swb_highband); /* Prepare m[], low part from WB core, high part from 32k input */ mvr2r( m_core, m, swb_lowband ); mvr2r( m_orig + swb_lowband, m + swb_lowband, swb_highband ); /* SWB BWE encoding */ EncodeSWBSubbands( st, m, swb_lowband, swb_highband, nBands, nBands_search, wBands, subband_offsets, lagIndices, lagGains, BANDS, band_start, band_end, band_energy, p2a_flags, hqswb_clas, prev_frm_index, har_bands, subband_search_offset, prev_frm_hfe2, prev_stab_hfe2,band_width, y2_ni, ni_seed ); m[swb_lowband+swb_highband-1] *= 0.0625f; m[swb_lowband+swb_highband-2] *= 0.125f; m[swb_lowband+swb_highband-3] *= 0.25f; m[swb_lowband+swb_highband-4] *= 0.5f; /* set frequencies below 6.4 kHz to zero */ if(hqswb_clas == HQ_NORMAL) { for (k=0; k < swb_lowband; k++) { m[k] = 0.0f; } } return; }