summaryrefslogtreecommitdiffstats
path: root/libSBRenc/src/ton_corr.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
commit2228e360595641dd906bf1773307f43d304f5b2e (patch)
tree57f3d390ebb0782cc0de0fb984c8ea7e45b4f386 /libSBRenc/src/ton_corr.cpp
downloadODR-AudioEnc-2228e360595641dd906bf1773307f43d304f5b2e.tar.gz
ODR-AudioEnc-2228e360595641dd906bf1773307f43d304f5b2e.tar.bz2
ODR-AudioEnc-2228e360595641dd906bf1773307f43d304f5b2e.zip
Snapshot 2bda038c163298531d47394bc2c09e1409c5d0db
Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54
Diffstat (limited to 'libSBRenc/src/ton_corr.cpp')
-rw-r--r--libSBRenc/src/ton_corr.cpp883
1 files changed, 883 insertions, 0 deletions
diff --git a/libSBRenc/src/ton_corr.cpp b/libSBRenc/src/ton_corr.cpp
new file mode 100644
index 0000000..3142870
--- /dev/null
+++ b/libSBRenc/src/ton_corr.cpp
@@ -0,0 +1,883 @@
+
+/* -----------------------------------------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© Copyright 1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
+ All rights reserved.
+
+ 1. INTRODUCTION
+The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
+the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
+This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
+
+AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
+audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
+independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
+of the MPEG specifications.
+
+Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
+may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
+individually for the purpose of encoding or decoding bit streams in products that are compliant with
+the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
+these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
+software may already be covered under those patent licenses when it is used for those licensed purposes only.
+
+Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
+are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
+applications information and documentation.
+
+2. COPYRIGHT LICENSE
+
+Redistribution and use in source and binary forms, with or without modification, are permitted without
+payment of copyright license fees provided that you satisfy the following conditions:
+
+You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
+your modifications thereto in source code form.
+
+You must retain the complete text of this software license in the documentation and/or other materials
+provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
+You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
+modifications thereto to recipients of copies in binary form.
+
+The name of Fraunhofer may not be used to endorse or promote products derived from this library without
+prior written permission.
+
+You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
+software or your modifications thereto.
+
+Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
+and the date of any change. For modified versions of the FDK AAC Codec, the term
+"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
+"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
+
+3. NO PATENT LICENSE
+
+NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
+ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
+respect to this software.
+
+You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
+by appropriate patent licenses.
+
+4. DISCLAIMER
+
+This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
+"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
+of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
+including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
+or business interruption, however caused and on any theory of liability, whether in contract, strict
+liability, or tort (including negligence), arising in any way out of the use of this software, even if
+advised of the possibility of such damage.
+
+5. CONTACT INFORMATION
+
+Fraunhofer Institute for Integrated Circuits IIS
+Attention: Audio and Multimedia Departments - FDK AAC LL
+Am Wolfsmantel 33
+91058 Erlangen, Germany
+
+www.iis.fraunhofer.de/amm
+amm-info@iis.fraunhofer.de
+----------------------------------------------------------------------------------------------------------- */
+
+#include "ton_corr.h"
+
+#include "sbr_ram.h"
+#include "sbr_misc.h"
+#include "genericStds.h"
+#include "autocorr2nd.h"
+
+
+
+/***************************************************************************
+
+ Send autoCorrSecondOrder to mlfile
+
+****************************************************************************/
+
+/**************************************************************************/
+/*!
+ \brief Calculates the tonal to noise ration for different frequency bands
+ and time segments.
+
+ The ratio between the predicted energy (tonal energy A) and the total
+ energy (A + B) is calculated. This is converted to the ratio between
+ the predicted energy (tonal energy A) and the non-predictable energy
+ (noise energy B). Hence the quota-matrix contains A/B = q/(1-q).
+
+ The samples in nrgVector are scaled by 1.0/16.0
+ The samples in pNrgVectorFreq are scaled by 1.0/2.0
+ The samples in quotaMatrix are scaled by RELAXATION
+
+ \return none.
+
+*/
+/**************************************************************************/
+
+void
+FDKsbrEnc_CalculateTonalityQuotas( HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */
+ FIXP_DBL **RESTRICT sourceBufferReal, /*!< The real part of the QMF-matrix. */
+ FIXP_DBL **RESTRICT sourceBufferImag, /*!< The imaginary part of the QMF-matrix. */
+ INT usb, /*!< upper side band, highest + 1 QMF band in the SBR range. */
+ INT qmfScale /*!< sclefactor of QMF subsamples */
+ )
+{
+ INT i, k, r, r2, timeIndex, autoCorrScaling;
+
+ INT startIndexMatrix = hTonCorr->startIndexMatrix;
+ INT totNoEst = hTonCorr->numberOfEstimates;
+ INT noEstPerFrame = hTonCorr->numberOfEstimatesPerFrame;
+ INT move = hTonCorr->move;
+ INT noQmfChannels = hTonCorr->noQmfChannels; /* Numer of Bands */
+ INT buffLen = hTonCorr->bufferLength; /* Numer of Slots */
+ INT stepSize = hTonCorr->stepSize;
+ INT *pBlockLength = hTonCorr->lpcLength;
+ INT** RESTRICT signMatrix = hTonCorr->signMatrix;
+ FIXP_DBL* RESTRICT nrgVector = hTonCorr->nrgVector;
+ FIXP_DBL** RESTRICT quotaMatrix = hTonCorr->quotaMatrix;
+ FIXP_DBL* RESTRICT pNrgVectorFreq = hTonCorr->nrgVectorFreq;
+
+#define BAND_V_SIZE QMF_MAX_TIME_SLOTS
+#define NUM_V_COMBINE 8 /* Must be a divisor of 64 and fulfill the ASSERTs below */
+
+ FIXP_DBL *realBuf;
+ FIXP_DBL *imagBuf;
+
+ FIXP_DBL alphar[2],alphai[2],fac;
+
+ C_ALLOC_SCRATCH_START(ac, ACORR_COEFS, 1);
+ C_ALLOC_SCRATCH_START(realBufRef, FIXP_DBL, 2*BAND_V_SIZE*NUM_V_COMBINE);
+
+ realBuf = realBufRef;
+ imagBuf = realBuf + BAND_V_SIZE*NUM_V_COMBINE;
+
+
+ FDK_ASSERT(buffLen <= BAND_V_SIZE);
+ FDK_ASSERT(sizeof(FIXP_DBL)*NUM_V_COMBINE*BAND_V_SIZE*2 < (1024*sizeof(FIXP_DBL)-sizeof(ACORR_COEFS)) );
+
+ /*
+ * Buffering of the quotaMatrix and the quotaMatrixTransp.
+ *********************************************************/
+ for(i = 0 ; i < move; i++){
+ FDKmemcpy(quotaMatrix[i],quotaMatrix[i + noEstPerFrame],noQmfChannels * sizeof(FIXP_DBL));
+ FDKmemcpy(signMatrix[i],signMatrix[i + noEstPerFrame],noQmfChannels * sizeof(INT));
+ }
+
+ FDKmemmove(nrgVector,nrgVector+noEstPerFrame,move*sizeof(FIXP_DBL));
+ FDKmemclear(nrgVector+startIndexMatrix,(totNoEst-startIndexMatrix)*sizeof(FIXP_DBL));
+ FDKmemclear(pNrgVectorFreq,noQmfChannels * sizeof(FIXP_DBL));
+
+ /*
+ * Calculate the quotas for the current time steps.
+ **************************************************/
+
+ for (r = 0; r < usb; r++)
+ {
+ int blockLength;
+
+ k = hTonCorr->nextSample; /* startSample */
+ timeIndex = startIndexMatrix;
+ /* Copy as many as possible Band accross all Slots at once */
+ if (realBuf != realBufRef) {
+ realBuf -= BAND_V_SIZE;
+ imagBuf -= BAND_V_SIZE;
+ } else {
+ realBuf += BAND_V_SIZE*(NUM_V_COMBINE-1);
+ imagBuf += BAND_V_SIZE*(NUM_V_COMBINE-1);
+ for (i = 0; i < buffLen; i++) {
+ int v;
+ FIXP_DBL *ptr;
+ ptr = realBuf+i;
+ for (v=0; v<NUM_V_COMBINE; v++)
+ {
+ ptr[0] = sourceBufferReal[i][r+v];
+ ptr[0+BAND_V_SIZE*NUM_V_COMBINE] = sourceBufferImag[i][r+v];
+ ptr -= BAND_V_SIZE;
+ }
+ }
+ }
+
+ blockLength = pBlockLength[0];
+
+ while(k <= buffLen - blockLength)
+ {
+ autoCorrScaling = fixMin(getScalefactor(&realBuf[k-LPC_ORDER], LPC_ORDER+blockLength), getScalefactor(&imagBuf[k-LPC_ORDER], LPC_ORDER+blockLength));
+ autoCorrScaling = fixMax(0, autoCorrScaling-1);
+
+ scaleValues(&realBuf[k-LPC_ORDER], LPC_ORDER+blockLength, autoCorrScaling);
+ scaleValues(&imagBuf[k-LPC_ORDER], LPC_ORDER+blockLength, autoCorrScaling);
+
+ autoCorrScaling <<= 1; /* consider qmf buffer scaling twice */
+ autoCorrScaling += autoCorr2nd_cplx ( ac, realBuf+k, imagBuf+k, blockLength );
+
+
+ if(ac->det == FL2FXCONST_DBL(0.0f)){
+ alphar[1] = alphai[1] = FL2FXCONST_DBL(0.0f);
+
+ alphar[0] = (ac->r01r)>>2;
+ alphai[0] = (ac->r01i)>>2;
+
+ fac = fMultDiv2(ac->r00r, ac->r11r)>>1;
+ }
+ else{
+ alphar[1] = (fMultDiv2(ac->r01r, ac->r12r)>>1) - (fMultDiv2(ac->r01i, ac->r12i)>>1) - (fMultDiv2(ac->r02r, ac->r11r)>>1);
+ alphai[1] = (fMultDiv2(ac->r01i, ac->r12r)>>1) + (fMultDiv2(ac->r01r, ac->r12i)>>1) - (fMultDiv2(ac->r02i, ac->r11r)>>1);
+
+ alphar[0] = (fMultDiv2(ac->r01r, ac->det)>>(ac->det_scale+1)) + fMult(alphar[1], ac->r12r) + fMult(alphai[1], ac->r12i);
+ alphai[0] = (fMultDiv2(ac->r01i, ac->det)>>(ac->det_scale+1)) + fMult(alphai[1], ac->r12r) - fMult(alphar[1], ac->r12i);
+
+ fac = fMultDiv2(ac->r00r, fMult(ac->det, ac->r11r))>>(ac->det_scale+1);
+ }
+
+ if(fac == FL2FXCONST_DBL(0.0f)){
+ quotaMatrix[timeIndex][r] = FL2FXCONST_DBL(0.0f);
+ signMatrix[timeIndex][r] = 0;
+ }
+ else {
+ /* quotaMatrix is scaled with the factor RELAXATION
+ parse RELAXATION in fractional part and shift factor: 1/(1/0.524288 * 2^RELAXATION_SHIFT) */
+ FIXP_DBL tmp,num,denom;
+ INT numShift,denomShift,commonShift;
+ INT sign;
+
+ num = fMultDiv2(alphar[0], ac->r01r) + fMultDiv2(alphai[0], ac->r01i) - fMultDiv2(alphar[1], fMult(ac->r02r, ac->r11r)) - fMultDiv2(alphai[1], fMult(ac->r02i, ac->r11r));
+ num = fixp_abs(num);
+
+ denom = (fac>>1) + (fMultDiv2(fac,RELAXATION_FRACT)>>RELAXATION_SHIFT) - num;
+ denom = fixp_abs(denom);
+
+ num = fMult(num,RELAXATION_FRACT);
+
+ numShift = CountLeadingBits(num) - 2;
+ num = scaleValue(num, numShift);
+
+ denomShift = CountLeadingBits(denom);
+ denom = (FIXP_DBL)denom << denomShift;
+
+ if ((num > FL2FXCONST_DBL(0.0f)) && (denom != FL2FXCONST_DBL(0.0f))) {
+ commonShift = fixMin(numShift - denomShift + RELAXATION_SHIFT, DFRACT_BITS-1);
+ if (commonShift < 0) {
+ commonShift = -commonShift;
+ tmp = schur_div(num,denom,16);
+ commonShift = fixMin(commonShift,CountLeadingBits(tmp));
+ quotaMatrix[timeIndex][r] = tmp << commonShift;
+ }
+ else {
+ quotaMatrix[timeIndex][r] = schur_div(num,denom,16) >> commonShift;
+ }
+ }
+ else {
+ quotaMatrix[timeIndex][r] = FL2FXCONST_DBL(0.0f);
+ }
+
+ if (ac->r11r != FL2FXCONST_DBL(0.0f)) {
+ if ( ( (ac->r01r >= FL2FXCONST_DBL(0.0f) ) && ( ac->r11r >= FL2FXCONST_DBL(0.0f) ) )
+ ||( (ac->r01r < FL2FXCONST_DBL(0.0f) ) && ( ac->r11r < FL2FXCONST_DBL(0.0f) ) ) ) {
+ sign = 1;
+ }
+ else {
+ sign = -1;
+ }
+ }
+ else {
+ sign = 1;
+ }
+
+ if(sign < 0) {
+ r2 = r; /* (INT) pow(-1, band); */
+ }
+ else {
+ r2 = r + 1; /* (INT) pow(-1, band+1); */
+ }
+ signMatrix[timeIndex][r] = 1 - 2*(r2 & 0x1);
+ }
+
+ nrgVector[timeIndex] += ((ac->r00r) >> fixMin(DFRACT_BITS-1,(2*qmfScale+autoCorrScaling + SCALE_NRGVEC)));
+ /* pNrgVectorFreq[r] finally has to be divided by noEstPerFrame, replaced division by shifting with one */
+ pNrgVectorFreq[r] = pNrgVectorFreq[r] + ((ac->r00r) >> fixMin(DFRACT_BITS-1,(2*qmfScale+autoCorrScaling + SCALE_NRGVEC)));
+
+ blockLength = pBlockLength[1];
+ k += stepSize;
+ timeIndex++;
+ }
+ }
+
+ FDK_ASSERT(noEstPerFrame == 2);
+
+
+ C_ALLOC_SCRATCH_END(realBuf, FIXP_DBL, 2*BAND_V_SIZE*NUM_V_COMBINE);
+ C_ALLOC_SCRATCH_END(ac, ACORR_COEFS, 1);
+}
+
+/**************************************************************************/
+/*!
+ \brief Extracts the parameters required in the decoder to obtain the
+ correct tonal to noise ratio after SBR.
+
+ Estimates the tonal to noise ratio of the original signal (using LPC).
+ Predicts the tonal to noise ration of the SBR signal (in the decoder) by
+ patching the tonal to noise ratio values similar to the patching of the
+ lowband in the decoder. Given the tonal to noise ratio of the original
+ and the SBR signal, it estimates the required amount of inverse filtering,
+ additional noise as well as any additional sines.
+
+ \return none.
+
+*/
+/**************************************************************************/
+void
+FDKsbrEnc_TonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr,/*!< Handle to SBR_TON_CORR struct. */
+ INVF_MODE* infVec, /*!< Vector where the inverse filtering levels will be stored. */
+ FIXP_DBL * noiseLevels, /*!< Vector where the noise levels will be stored. */
+ INT* missingHarmonicFlag, /*!< Flag set to one or zero, dependent on if any strong sines are missing.*/
+ UCHAR * missingHarmonicsIndex, /*!< Vector indicating where sines are missing. */
+ UCHAR * envelopeCompensation, /*!< Vector to store compensation values for the energies in. */
+ const SBR_FRAME_INFO *frameInfo, /*!< Frame info struct, contains the time and frequency grid of the current frame.*/
+ UCHAR* transientInfo, /*!< Transient info.*/
+ UCHAR* freqBandTable, /*!< Frequency band tables for high-res.*/
+ INT nSfb, /*!< Number of scalefactor bands for high-res. */
+ XPOS_MODE xposType, /*!< Type of transposer used in the decoder.*/
+ UINT sbrSyntaxFlags
+ )
+{
+ INT band;
+ INT transientFlag = transientInfo[1] ; /*!< Flag indicating if a transient is present in the current frame. */
+ INT transientPos = transientInfo[0]; /*!< Position of the transient.*/
+ INT transientFrame, transientFrameInvfEst;
+ INVF_MODE* infVecPtr;
+
+
+ /* Determine if this is a frame where a transient starts...
+
+ The detection of noise-floor, missing harmonics and invf_est, is not in sync for the
+ non-buf-opt decoder such as AAC. Hence we need to keep track on the transient in the
+ present frame as well as in the next.
+ */
+ transientFrame = 0;
+ if(hTonCorr->transientNextFrame){ /* The transient was detected in the previous frame, but is actually */
+ transientFrame = 1;
+ hTonCorr->transientNextFrame = 0;
+
+ if(transientFlag){
+ if(transientPos + hTonCorr->transientPosOffset >= frameInfo->borders[frameInfo->nEnvelopes]){
+ hTonCorr->transientNextFrame = 1;
+ }
+ }
+ }
+ else{
+ if(transientFlag){
+ if(transientPos + hTonCorr->transientPosOffset < frameInfo->borders[frameInfo->nEnvelopes]){
+ transientFrame = 1;
+ hTonCorr->transientNextFrame = 0;
+ }
+ else{
+ hTonCorr->transientNextFrame = 1;
+ }
+ }
+ }
+ transientFrameInvfEst = transientFrame;
+
+
+ /*
+ Estimate the required invese filtereing level.
+ */
+ if (hTonCorr->switchInverseFilt)
+ FDKsbrEnc_qmfInverseFilteringDetector(&hTonCorr->sbrInvFilt,
+ hTonCorr->quotaMatrix,
+ hTonCorr->nrgVector,
+ hTonCorr->indexVector,
+ hTonCorr->frameStartIndexInvfEst,
+ hTonCorr->numberOfEstimatesPerFrame + hTonCorr->frameStartIndexInvfEst,
+ transientFrameInvfEst,
+ infVec);
+
+ /*
+ Detect what tones will be missing.
+ */
+ if (xposType == XPOS_LC ){
+ FDKsbrEnc_SbrMissingHarmonicsDetectorQmf(&hTonCorr->sbrMissingHarmonicsDetector,
+ hTonCorr->quotaMatrix,
+ hTonCorr->signMatrix,
+ hTonCorr->indexVector,
+ frameInfo,
+ transientInfo,
+ missingHarmonicFlag,
+ missingHarmonicsIndex,
+ freqBandTable,
+ nSfb,
+ envelopeCompensation,
+ hTonCorr->nrgVectorFreq);
+ }
+ else{
+ *missingHarmonicFlag = 0;
+ FDKmemclear(missingHarmonicsIndex,nSfb*sizeof(UCHAR));
+ }
+
+
+
+ /*
+ Noise floor estimation
+ */
+
+ infVecPtr = hTonCorr->sbrInvFilt.prevInvfMode;
+
+ FDKsbrEnc_sbrNoiseFloorEstimateQmf(&hTonCorr->sbrNoiseFloorEstimate,
+ frameInfo,
+ noiseLevels,
+ hTonCorr->quotaMatrix,
+ hTonCorr->indexVector,
+ *missingHarmonicFlag,
+ hTonCorr->frameStartIndex,
+ hTonCorr->numberOfEstimatesPerFrame,
+ transientFrame,
+ infVecPtr,
+ sbrSyntaxFlags);
+
+
+ /* Store the invfVec data for the next frame...*/
+ for(band = 0 ; band < hTonCorr->sbrInvFilt.noDetectorBands; band++){
+ hTonCorr->sbrInvFilt.prevInvfMode[band] = infVec[band];
+ }
+}
+
+/**************************************************************************/
+/*!
+ \brief Searches for the closest match in the frequency master table.
+
+
+
+ \return closest entry.
+
+*/
+/**************************************************************************/
+static INT
+findClosestEntry(INT goalSb,
+ UCHAR *v_k_master,
+ INT numMaster,
+ INT direction)
+{
+ INT index;
+
+ if( goalSb <= v_k_master[0] )
+ return v_k_master[0];
+
+ if( goalSb >= v_k_master[numMaster] )
+ return v_k_master[numMaster];
+
+ if(direction) {
+ index = 0;
+ while( v_k_master[index] < goalSb ) {
+ index++;
+ }
+ } else {
+ index = numMaster;
+ while( v_k_master[index] > goalSb ) {
+ index--;
+ }
+ }
+
+ return v_k_master[index];
+}
+
+
+/**************************************************************************/
+/*!
+ \brief resets the patch
+
+
+
+ \return errorCode, noError if successful.
+
+*/
+/**************************************************************************/
+static INT
+resetPatch(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */
+ INT xposctrl, /*!< Different patch modes. */
+ INT highBandStartSb, /*!< Start band of the SBR range. */
+ UCHAR *v_k_master, /*!< Master frequency table from which all other table are derived.*/
+ INT numMaster, /*!< Number of elements in the master table. */
+ INT fs, /*!< Sampling frequency. */
+ INT noChannels) /*!< Number of QMF-channels. */
+{
+ INT patch,k,i;
+ INT targetStopBand;
+
+ PATCH_PARAM *patchParam = hTonCorr->patchParam;
+
+ INT sbGuard = hTonCorr->guard;
+ INT sourceStartBand;
+ INT patchDistance;
+ INT numBandsInPatch;
+
+ INT lsb = v_k_master[0]; /* Lowest subband related to the synthesis filterbank */
+ INT usb = v_k_master[numMaster]; /* Stop subband related to the synthesis filterbank */
+ INT xoverOffset = highBandStartSb - v_k_master[0]; /* Calculate distance in subbands between k0 and kx */
+
+ INT goalSb;
+
+
+ /*
+ * Initialize the patching parameter
+ */
+
+ if (xposctrl == 1) {
+ lsb += xoverOffset;
+ xoverOffset = 0;
+ }
+
+ goalSb = (INT)( (2 * noChannels * 16000 + (fs>>1)) / fs ); /* 16 kHz band */
+ goalSb = findClosestEntry(goalSb, v_k_master, numMaster, 1); /* Adapt region to master-table */
+
+ /* First patch */
+ sourceStartBand = hTonCorr->shiftStartSb + xoverOffset;
+ targetStopBand = lsb + xoverOffset;
+
+ /* even (odd) numbered channel must be patched to even (odd) numbered channel */
+ patch = 0;
+ while(targetStopBand < usb) {
+
+ /* To many patches */
+ if (patch >= MAX_NUM_PATCHES)
+ return(1); /*Number of patches to high */
+
+ patchParam[patch].guardStartBand = targetStopBand;
+ targetStopBand += sbGuard;
+ patchParam[patch].targetStartBand = targetStopBand;
+
+ numBandsInPatch = goalSb - targetStopBand; /* get the desired range of the patch */
+
+ if ( numBandsInPatch >= lsb - sourceStartBand ) {
+ /* desired number bands are not available -> patch whole source range */
+ patchDistance = targetStopBand - sourceStartBand; /* get the targetOffset */
+ patchDistance = patchDistance & ~1; /* rounding off odd numbers and make all even */
+ numBandsInPatch = lsb - (targetStopBand - patchDistance);
+ numBandsInPatch = findClosestEntry(targetStopBand + numBandsInPatch, v_k_master, numMaster, 0) -
+ targetStopBand; /* Adapt region to master-table */
+ }
+
+ /* desired number bands are available -> get the minimal even patching distance */
+ patchDistance = numBandsInPatch + targetStopBand - lsb; /* get minimal distance */
+ patchDistance = (patchDistance + 1) & ~1; /* rounding up odd numbers and make all even */
+
+ if (numBandsInPatch <= 0) {
+ patch--;
+ } else {
+ patchParam[patch].sourceStartBand = targetStopBand - patchDistance;
+ patchParam[patch].targetBandOffs = patchDistance;
+ patchParam[patch].numBandsInPatch = numBandsInPatch;
+ patchParam[patch].sourceStopBand = patchParam[patch].sourceStartBand + numBandsInPatch;
+
+ targetStopBand += patchParam[patch].numBandsInPatch;
+ }
+
+ /* All patches but first */
+ sourceStartBand = hTonCorr->shiftStartSb;
+
+ /* Check if we are close to goalSb */
+ if( fixp_abs(targetStopBand - goalSb) < 3) {
+ goalSb = usb;
+ }
+
+ patch++;
+
+ }
+
+ patch--;
+
+ /* if highest patch contains less than three subband: skip it */
+ if ( patchParam[patch].numBandsInPatch < 3 && patch > 0 ) {
+ patch--;
+ targetStopBand = patchParam[patch].targetStartBand + patchParam[patch].numBandsInPatch;
+ }
+
+ hTonCorr->noOfPatches = patch + 1;
+
+
+ /* Assign the index-vector, so we know where to look for the high-band.
+ -1 represents a guard-band. */
+ for(k = 0; k < hTonCorr->patchParam[0].guardStartBand; k++)
+ hTonCorr->indexVector[k] = k;
+
+ for(i = 0; i < hTonCorr->noOfPatches; i++)
+ {
+ INT sourceStart = hTonCorr->patchParam[i].sourceStartBand;
+ INT targetStart = hTonCorr->patchParam[i].targetStartBand;
+ INT numberOfBands = hTonCorr->patchParam[i].numBandsInPatch;
+ INT startGuardBand = hTonCorr->patchParam[i].guardStartBand;
+
+ for(k = 0; k < (targetStart- startGuardBand); k++)
+ hTonCorr->indexVector[startGuardBand+k] = -1;
+
+ for(k = 0; k < numberOfBands; k++)
+ hTonCorr->indexVector[targetStart+k] = sourceStart+k;
+ }
+
+ return (0);
+}
+
+/**************************************************************************/
+/*!
+ \brief Creates an instance of the tonality correction parameter module.
+
+ The module includes modules for inverse filtering level estimation,
+ missing harmonics detection and noise floor level estimation.
+
+ \return errorCode, noError if successful.
+*/
+/**************************************************************************/
+INT
+FDKsbrEnc_CreateTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */
+ INT chan) /*!< Channel index, needed for mem allocation */
+{
+ INT i;
+ FIXP_DBL* quotaMatrix = GetRam_Sbr_quotaMatrix(chan);
+ INT* signMatrix = GetRam_Sbr_signMatrix(chan);
+
+ FDKmemclear(hTonCorr, sizeof(SBR_TON_CORR_EST));
+
+ for (i=0; i<MAX_NO_OF_ESTIMATES; i++) {
+ hTonCorr->quotaMatrix[i] = quotaMatrix + (i*QMF_CHANNELS);
+ hTonCorr->signMatrix[i] = signMatrix + (i*QMF_CHANNELS);
+ }
+
+ FDKsbrEnc_CreateSbrMissingHarmonicsDetector (&hTonCorr->sbrMissingHarmonicsDetector, chan);
+
+ return 0;
+}
+
+
+
+/**************************************************************************/
+/*!
+ \brief Initialize an instance of the tonality correction parameter module.
+
+ The module includes modules for inverse filtering level estimation,
+ missing harmonics detection and noise floor level estimation.
+
+ \return errorCode, noError if successful.
+*/
+/**************************************************************************/
+INT
+FDKsbrEnc_InitTonCorrParamExtr (INT frameSize, /*!< Current SBR frame size. */
+ HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */
+ HANDLE_SBR_CONFIG_DATA sbrCfg, /*!< Pointer to SBR configuration parameters. */
+ INT timeSlots, /*!< Number of time-slots per frame */
+ INT xposCtrl, /*!< Different patch modes. */
+ INT ana_max_level, /*!< Maximum level of the adaptive noise. */
+ INT noiseBands, /*!< Number of noise bands per octave. */
+ INT noiseFloorOffset, /*!< Noise floor offset. */
+ UINT useSpeechConfig) /*!< Speech or music tuning. */
+{
+ INT nCols = sbrCfg->noQmfSlots;
+ INT fs = sbrCfg->sampleFreq;
+ INT noQmfChannels = sbrCfg->noQmfBands;
+
+ INT highBandStartSb = sbrCfg->freqBandTable[LOW_RES][0];
+ UCHAR *v_k_master = sbrCfg->v_k_master;
+ INT numMaster = sbrCfg->num_Master;
+
+ UCHAR **freqBandTable = sbrCfg->freqBandTable;
+ INT *nSfb = sbrCfg->nSfb;
+
+ INT i;
+
+ /*
+ Reset the patching and allocate memory for the quota matrix.
+ Assing parameters for the LPC analysis.
+ */
+ if (sbrCfg->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
+ switch (timeSlots) {
+ case NUMBER_TIME_SLOTS_1920:
+ hTonCorr->lpcLength[0] = 8 - LPC_ORDER;
+ hTonCorr->lpcLength[1] = 7 - LPC_ORDER;
+ hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LD;
+ hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 7;
+ hTonCorr->frameStartIndexInvfEst = 0;
+ hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_512LD;
+ break;
+ case NUMBER_TIME_SLOTS_2048:
+ hTonCorr->lpcLength[0] = 8 - LPC_ORDER;
+ hTonCorr->lpcLength[1] = 8 - LPC_ORDER;
+ hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LD;
+ hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 8;
+ hTonCorr->frameStartIndexInvfEst = 0;
+ hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_512LD;
+ break;
+ }
+ } else
+ switch (timeSlots) {
+ case NUMBER_TIME_SLOTS_2048:
+ hTonCorr->lpcLength[0] = 16 - LPC_ORDER; /* blockLength[0] */
+ hTonCorr->lpcLength[1] = 16 - LPC_ORDER; /* blockLength[0] */
+ hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LC;
+ hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 16;
+ hTonCorr->frameStartIndexInvfEst = 0;
+ hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_2048;
+ break;
+ case NUMBER_TIME_SLOTS_1920:
+ hTonCorr->lpcLength[0] = 15 - LPC_ORDER; /* blockLength[0] */
+ hTonCorr->lpcLength[1] = 15 - LPC_ORDER; /* blockLength[0] */
+ hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LC;
+ hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 15;
+ hTonCorr->frameStartIndexInvfEst = 0;
+ hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_1920;
+ break;
+ default:
+ return -1;
+ }
+
+ hTonCorr->bufferLength = nCols;
+ hTonCorr->stepSize = hTonCorr->lpcLength[0] + LPC_ORDER; /* stepSize[0] implicitly 0. */
+
+ hTonCorr->nextSample = LPC_ORDER; /* firstSample */
+ hTonCorr->move = hTonCorr->numberOfEstimates - hTonCorr->numberOfEstimatesPerFrame; /* Number of estimates to move when buffering.*/
+ hTonCorr->startIndexMatrix = hTonCorr->numberOfEstimates - hTonCorr->numberOfEstimatesPerFrame; /* Where to store the latest estimations in the tonality Matrix.*/
+ hTonCorr->frameStartIndex = 0; /* Where in the tonality matrix the current frame (to be sent to the decoder) starts. */
+ hTonCorr->prevTransientFlag = 0;
+ hTonCorr->transientNextFrame = 0;
+
+ hTonCorr->noQmfChannels = noQmfChannels;
+
+ for (i=0; i<hTonCorr->numberOfEstimates; i++) {
+ FDKmemclear (hTonCorr->quotaMatrix[i] , sizeof(FIXP_DBL)*noQmfChannels);
+ FDKmemclear (hTonCorr->signMatrix[i] , sizeof(INT)*noQmfChannels);
+ }
+
+ /* Reset the patch.*/
+ hTonCorr->guard = 0;
+ hTonCorr->shiftStartSb = 1;
+
+ if(resetPatch(hTonCorr,
+ xposCtrl,
+ highBandStartSb,
+ v_k_master,
+ numMaster,
+ fs,
+ noQmfChannels))
+ return(1);
+
+ if(FDKsbrEnc_InitSbrNoiseFloorEstimate (&hTonCorr->sbrNoiseFloorEstimate,
+ ana_max_level,
+ freqBandTable[LO],
+ nSfb[LO],
+ noiseBands,
+ noiseFloorOffset,
+ timeSlots,
+ useSpeechConfig))
+ return(1);
+
+
+ if(FDKsbrEnc_initInvFiltDetector(&hTonCorr->sbrInvFilt,
+ hTonCorr->sbrNoiseFloorEstimate.freqBandTableQmf,
+ hTonCorr->sbrNoiseFloorEstimate.noNoiseBands,
+ useSpeechConfig))
+ return(1);
+
+
+
+ if(FDKsbrEnc_InitSbrMissingHarmonicsDetector(
+ &hTonCorr->sbrMissingHarmonicsDetector,
+ fs,
+ frameSize,
+ nSfb[HI],
+ noQmfChannels,
+ hTonCorr->numberOfEstimates,
+ hTonCorr->move,
+ hTonCorr->numberOfEstimatesPerFrame,
+ sbrCfg->sbrSyntaxFlags))
+ return(1);
+
+
+
+ return (0);
+}
+
+
+
+/**************************************************************************/
+/*!
+ \brief resets tonality correction parameter module.
+
+
+
+ \return errorCode, noError if successful.
+
+*/
+/**************************************************************************/
+INT
+FDKsbrEnc_ResetTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */
+ INT xposctrl, /*!< Different patch modes. */
+ INT highBandStartSb, /*!< Start band of the SBR range. */
+ UCHAR *v_k_master, /*!< Master frequency table from which all other table are derived.*/
+ INT numMaster, /*!< Number of elements in the master table. */
+ INT fs, /*!< Sampling frequency (of the SBR part). */
+ UCHAR ** freqBandTable, /*!< Frequency band table for low-res and high-res. */
+ INT* nSfb, /*!< Number of frequency bands (hig-res and low-res). */
+ INT noQmfChannels /*!< Number of QMF channels. */
+ )
+{
+
+ /* Reset the patch.*/
+ hTonCorr->guard = 0;
+ hTonCorr->shiftStartSb = 1;
+
+ if(resetPatch(hTonCorr,
+ xposctrl,
+ highBandStartSb,
+ v_k_master,
+ numMaster,
+ fs,
+ noQmfChannels))
+ return(1);
+
+
+
+ /* Reset the noise floor estimate.*/
+ if(FDKsbrEnc_resetSbrNoiseFloorEstimate (&hTonCorr->sbrNoiseFloorEstimate,
+ freqBandTable[LO],
+ nSfb[LO]))
+ return(1);
+
+ /*
+ Reset the inveerse filtereing detector.
+ */
+ if(FDKsbrEnc_resetInvFiltDetector(&hTonCorr->sbrInvFilt,
+ hTonCorr->sbrNoiseFloorEstimate.freqBandTableQmf,
+ hTonCorr->sbrNoiseFloorEstimate.noNoiseBands))
+ return(1);
+/* Reset the missing harmonics detector. */
+ if(FDKsbrEnc_ResetSbrMissingHarmonicsDetector (&hTonCorr->sbrMissingHarmonicsDetector,
+ nSfb[HI]))
+ return(1);
+
+ return (0);
+}
+
+
+
+
+
+/**************************************************************************/
+/*!
+ \brief Deletes the tonality correction paramtere module.
+
+
+
+ \return none
+
+*/
+/**************************************************************************/
+void
+FDKsbrEnc_DeleteTonCorrParamExtr (HANDLE_SBR_TON_CORR_EST hTonCorr) /*!< Handle to SBR_TON_CORR struct. */
+{
+
+ if (hTonCorr) {
+
+ FreeRam_Sbr_quotaMatrix(hTonCorr->quotaMatrix);
+
+ FreeRam_Sbr_signMatrix(hTonCorr->signMatrix);
+
+ FDKsbrEnc_DeleteSbrMissingHarmonicsDetector (&hTonCorr->sbrMissingHarmonicsDetector);
+ }
+}