| /* ----------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2018 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 |
| ----------------------------------------------------------------------------- */ |
| |
| /**************************** SBR encoder library ****************************** |
| |
| Author(s): |
| |
| Description: |
| |
| *******************************************************************************/ |
| |
| #include "ton_corr.h" |
| |
| #include "sbrenc_ram.h" |
| #include "sbr_misc.h" |
| #include "genericStds.h" |
| #include "autocorr2nd.h" |
| |
| #define BAND_V_SIZE 32 |
| #define NUM_V_COMBINE \ |
| 8 /* Must be a divisor of 64 and fulfill the ASSERTs below */ |
| |
| /**************************************************************************/ |
| /*! |
| \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; /* Number of Bands */ |
| INT buffLen = hTonCorr->bufferLength; /* Number 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; |
| |
| 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 across 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++; |
| } |
| } |
| |
| C_ALLOC_SCRATCH_END(realBufRef, 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--; |
| } |
| |
| 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); |
| |
| if ((NULL == quotaMatrix) || (NULL == signMatrix)) { |
| goto bail; |
| } |
| |
| FDKmemclear(hTonCorr, sizeof(SBR_TON_CORR_EST)); |
| |
| for (i = 0; i < MAX_NO_OF_ESTIMATES; i++) { |
| hTonCorr->quotaMatrix[i] = quotaMatrix + (i * 64); |
| hTonCorr->signMatrix[i] = signMatrix + (i * 64); |
| } |
| |
| if (0 != FDKsbrEnc_CreateSbrMissingHarmonicsDetector( |
| &hTonCorr->sbrMissingHarmonicsDetector, chan)) { |
| goto bail; |
| } |
| |
| return 0; |
| |
| bail: |
| hTonCorr->quotaMatrix[0] = quotaMatrix; |
| hTonCorr->signMatrix[0] = signMatrix; |
| |
| FDKsbrEnc_DeleteTonCorrParamExtr(hTonCorr); |
| |
| return -1; |
| } |
| |
| /**************************************************************************/ |
| /*! |
| \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. |
| Assuming 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 = 2; /* 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 = 2; /* 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.*/ |
| if (hTonCorr->move < 0) { |
| return -1; |
| } |
| 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); |
| } |
| } |