mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-02-17 03:30:35 +01:00
Bug: 71430241 Test: CTS DecoderTest and DecoderTestAacDrc original-Change-Id: Iaa20f749b8a04d553b20247cfe1a8930ebbabe30 Apply clang-format also on header files. original-Change-Id: I14de1ef16bbc79ec0283e745f98356a10efeb2e4 Fixes for MPEG-D DRC original-Change-Id: If1de2d74bbbac84b3f67de3b88b83f6a23b8a15c Catch unsupported tw_mdct at an early stage original-Change-Id: Ied9dd00d754162a0e3ca1ae3e6b854315d818afe Fixing PVC transition frames original-Change-Id: Ib75725abe39252806c32d71176308f2c03547a4e Move qmf bands sanity check original-Change-Id: Iab540c3013c174d9490d2ae100a4576f51d8dbc4 Initialize scaling variable original-Change-Id: I3c4087101b70e998c71c1689b122b0d7762e0f9e Add 16 qmf band configuration to getSlotNrgHQ() original-Change-Id: I49a5d30f703a1b126ff163df9656db2540df21f1 Always apply byte alignment at the end of the AudioMuxElement original-Change-Id: I42d560287506d65d4c3de8bfe3eb9a4ebeb4efc7 Setup SBR element only if no parse error exists original-Change-Id: I1915b73704bc80ab882b9173d6bec59cbd073676 Additional array index check in HCR original-Change-Id: I18cc6e501ea683b5009f1bbee26de8ddd04d8267 Fix fade-in index selection in concealment module original-Change-Id: Ibf802ed6ed8c05e9257e1f3b6d0ac1162e9b81c1 Enable explicit backward compatible parser for AAC_LD original-Change-Id: I27e9c678dcb5d40ed760a6d1e06609563d02482d Skip spatial specific config in explicit backward compatible ASC original-Change-Id: Iff7cc365561319e886090cedf30533f562ea4d6e Update flags description in decoder API original-Change-Id: I9a5b4f8da76bb652f5580cbd3ba9760425c43830 Add QMF domain reset function original-Change-Id: I4f89a8a2c0277d18103380134e4ed86996e9d8d6 DRC upgrade v2.1.0 original-Change-Id: I5731c0540139dab220094cd978ef42099fc45b74 Fix integer overflow in sqrtFixp_lookup() original-Change-Id: I429a6f0d19aa2cc957e0f181066f0ca73968c914 Fix integer overflow in invSqrtNorm2() original-Change-Id: I84de5cbf9fb3adeb611db203fe492fabf4eb6155 Fix integer overflow in GenerateRandomVector() original-Change-Id: I3118a641008bd9484d479e5b0b1ee2b5d7d44d74 Fix integer overflow in adjustTimeSlot_EldGrid() original-Change-Id: I29d503c247c5c8282349b79df940416a512fb9d5 Fix integer overflow in FDKsbrEnc_codeEnvelope() original-Change-Id: I6b34b61ebb9d525b0c651ed08de2befc1f801449 Follow-up on: Fix integer overflow in adjustTimeSlot_EldGrid() original-Change-Id: I6f8f578cc7089e5eb7c7b93e580b72ca35ad689a Fix integer overflow in get_pk_v2() original-Change-Id: I63375bed40d45867f6eeaa72b20b1f33e815938c Fix integer overflow in Syn_filt_zero() original-Change-Id: Ie0c02fdfbe03988f9d3b20d10cd9fe4c002d1279 Fix integer overflow in CFac_CalcFacSignal() original-Change-Id: Id2d767c40066c591b51768e978eb8af3b803f0c5 Fix integer overflow in FDKaacEnc_FDKaacEnc_calcPeNoAH() original-Change-Id: Idcbd0f4a51ae2550ed106aa6f3d678d1f9724841 Fix integer overflow in sbrDecoder_calculateGainVec() original-Change-Id: I7081bcbe29c5cede9821b38d93de07c7add2d507 Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I4a95ddc18de150102352d4a1845f06094764c881 Fix integer overflow in Pred_Lt4() original-Change-Id: I4dbd012b2de7d07c3e70a47b92e3bfae8dbc750a Fix integer overflow in FDKsbrEnc_InitSbrFastTransientDetector() original-Change-Id: I788cbec1a4a00f44c2f3a72ad7a4afa219807d04 Fix unsigned integer overflow in FDKaacEnc_WriteBitstream() original-Change-Id: I68fc75166e7d2cd5cd45b18dbe3d8c2a92f1822a Fix unsigned integer overflow in FDK_MetadataEnc_Init() original-Change-Id: Ie8d025f9bcdb2442c704bd196e61065c03c10af4 Fix overflow in pseudo random number generators original-Change-Id: I3e2551ee01356297ca14e3788436ede80bd5513c Fix unsigned integer overflow in sbrDecoder_Parse() original-Change-Id: I3f231b2f437e9c37db4d5b964164686710eee971 Fix unsigned integer overflow in longsub() original-Change-Id: I73c2bc50415cac26f1f5a29e125bbe75f9180a6e Fix unsigned integer overflow in CAacDecoder_DecodeFrame() original-Change-Id: Ifce2db4b1454b46fa5f887e9d383f1cc43b291e4 Fix overflow at CLpdChannelStream_Read() original-Change-Id: Idb9d822ce3a4272e4794b643644f5434e2d4bf3f Fix unsigned integer overflow in Hcr_State_BODY_SIGN_ESC__ESC_WORD() original-Change-Id: I1ccf77c0015684b85534c5eb97162740a870b71c Fix unsigned integer overflow in UsacConfig_Parse() original-Change-Id: Ie6d27f84b6ae7eef092ecbff4447941c77864d9f Fix unsigned integer overflow in aacDecoder_drcParse() original-Change-Id: I713f28e883eea3d70b6fa56a7b8f8c22bcf66ca0 Fix unsigned integer overflow in aacDecoder_drcReadCompression() original-Change-Id: Ia34dfeb88c4705c558bce34314f584965cafcf7a Fix unsigned integer overflow in CDataStreamElement_Read() original-Change-Id: Iae896cc1d11f0a893d21be6aa90bd3e60a2c25f0 Fix unsigned integer overflow in transportDec_AdjustEndOfAccessUnit() original-Change-Id: I64cf29a153ee784bb4a16fdc088baabebc0007dc Fix unsigned integer overflow in transportDec_GetAuBitsRemaining() original-Change-Id: I975b3420faa9c16a041874ba0db82e92035962e4 Fix unsigned integer overflow in extractExtendedData() original-Change-Id: I2a59eb09e2053cfb58dfb75fcecfad6b85a80a8f Fix signed integer overflow in CAacDecoder_ExtPayloadParse() original-Change-Id: I4ad5ca4e3b83b5d964f1c2f8c5e7b17c477c7929 Fix unsigned integer overflow in CAacDecoder_DecodeFrame() original-Change-Id: I29a39df77d45c52a0c9c5c83c1ba81f8d0f25090 Follow-up on: Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I8fb194ffc073a3432a380845be71036a272d388f Fix signed integer overflow in _interpolateDrcGain() original-Change-Id: I879ec9ab14005069a7c47faf80e8bc6e03d22e60 Fix unsigned integer overflow in FDKreadBits() original-Change-Id: I1f47a6a8037ff70375aa8844947d5681bb4287ad Fix unsigned integer overflow in FDKbyteAlign() original-Change-Id: Id5f3a11a0c9e50fc6f76ed6c572dbd4e9f2af766 Fix unsigned integer overflow in FDK_get32() original-Change-Id: I9d33b8e97e3d38cbb80629cb859266ca0acdce96 Fix unsigned integer overflow in FDK_pushBack() original-Change-Id: Ic87f899bc8c6acf7a377a8ca7f3ba74c3a1e1c19 Fix unsigned integer overflow in FDK_pushForward() original-Change-Id: I3b754382f6776a34be1602e66694ede8e0b8effc Fix unsigned integer overflow in ReadPsData() original-Change-Id: I25361664ba8139e32bbbef2ca8c106a606ce9c37 Fix signed integer overflow in E_UTIL_residu() original-Change-Id: I8c3abd1f437ee869caa8fb5903ce7d3d641b6aad REVERT: Follow-up on: Integer overflow in CLpc_SynthesisLattice(). original-Change-Id: I3d340099acb0414795c8dfbe6362bc0a8f045f9b Follow-up on: Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I4aedb8b3a187064e9f4d985175aa55bb99cc7590 Follow-up on: Fix unsigned integer overflow in aacDecoder_drcParse() original-Change-Id: I2aa2e13916213bf52a67e8b0518e7bf7e57fb37d Fix integer overflow in acelp original-Change-Id: Ie6390c136d84055f8b728aefbe4ebef6e029dc77 Fix unsigned integer overflow in aacDecoder_UpdateBitStreamCounters() original-Change-Id: I391ffd97ddb0b2c184cba76139bfb356a3b4d2e2 Adjust concealment default settings original-Change-Id: I6a95db935a327c47df348030bcceafcb29f54b21 Saturate estimatedStartPos original-Change-Id: I27be2085e0ae83ec9501409f65e003f6bcba1ab6 Negative shift exponent in _interpolateDrcGain() original-Change-Id: I18edb26b26d002aafd5e633d4914960f7a359c29 Negative shift exponent in calculateICC() original-Change-Id: I3dcd2ae98d2eb70ee0d59750863cbb2a6f4f8aba Too large shift exponent in FDK_put() original-Change-Id: Ib7d9aaa434d2d8de4a13b720ca0464b31ca9b671 Too large shift exponent in CalcInvLdData() original-Change-Id: I43e6e78d4cd12daeb1dcd5d82d1798bdc2550262 Member access within null pointer of type SBR_CHANNEL original-Change-Id: Idc5e4ea8997810376d2f36bbdf628923b135b097 Member access within null pointer of type CpePersistentData original-Change-Id: Ib6c91cb0d37882768e5baf63324e429589de0d9d Member access within null pointer FDKaacEnc_psyMain() original-Change-Id: I7729b7f4479970531d9dc823abff63ca52e01997 Member access within null pointer FDKaacEnc_GetPnsParam() original-Change-Id: I9aa3b9f3456ae2e0f7483dbd5b3dde95fc62da39 Member access within null pointer FDKsbrEnc_EnvEncodeFrame() original-Change-Id: I67936f90ea714e90b3e81bc0dd1472cc713eb23a Add HCR sanity check original-Change-Id: I6c1d9732ebcf6af12f50b7641400752f74be39f7 Fix memory issue for HBE edge case with 8:3 SBR original-Change-Id: I11ea58a61e69fbe8bf75034b640baee3011e63e9 Additional SBR parametrization sanity check for ELD original-Change-Id: Ie26026fbfe174c2c7b3691f6218b5ce63e322140 Add MPEG-D DRC channel layout check original-Change-Id: Iea70a74f171b227cce636a9eac4ba662777a2f72 Additional out-of-bounds checks in MPEG-D DRC original-Change-Id: Ife4a8c3452c6fde8a0a09e941154a39a769777d4 Change-Id: Ic63cb2f628720f54fe9b572b0cb528e2599c624e
1397 lines
50 KiB
C++
1397 lines
50 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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 "mh_det.h"
|
|
|
|
#include "sbrenc_ram.h"
|
|
#include "sbr_misc.h"
|
|
|
|
#include "genericStds.h"
|
|
|
|
#define SFM_SHIFT 2 /* Attention: SFM_SCALE depends on SFM_SHIFT */
|
|
#define SFM_SCALE (MAXVAL_DBL >> SFM_SHIFT) /* 1.0 >> SFM_SHIFT */
|
|
|
|
/*!< Detector Parameters for AAC core codec. */
|
|
static const DETECTOR_PARAMETERS_MH paramsAac = {
|
|
9, /*!< deltaTime */
|
|
{
|
|
FL2FXCONST_DBL(20.0f * RELAXATION_FLOAT), /*!< thresHoldDiff */
|
|
FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< thresHoldDiffGuide */
|
|
FL2FXCONST_DBL(15.0f * RELAXATION_FLOAT), /*!< thresHoldTone */
|
|
FL2FXCONST_DBL((1.0f / 15.0f) *
|
|
RELAXATION_FLOAT), /*!< invThresHoldTone */
|
|
FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< thresHoldToneGuide */
|
|
FL2FXCONST_DBL(0.3f) >> SFM_SHIFT, /*!< sfmThresSbr */
|
|
FL2FXCONST_DBL(0.1f) >> SFM_SHIFT, /*!< sfmThresOrig */
|
|
FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */
|
|
FL2FXCONST_DBL(0.5f), /*!< decayGuideDiff */
|
|
FL2FXCONST_DBL(-0.000112993269),
|
|
/* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */
|
|
FL2FXCONST_DBL(-0.000112993269),
|
|
/* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */
|
|
FL2FXCONST_DBL(
|
|
-0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!<
|
|
derivThresAboveLD64
|
|
*/
|
|
},
|
|
50 /*!< maxComp */
|
|
};
|
|
|
|
/*!< Detector Parameters for AAC LD core codec. */
|
|
static const DETECTOR_PARAMETERS_MH paramsAacLd = {
|
|
16, /*!< Delta time. */
|
|
{
|
|
FL2FXCONST_DBL(25.0f * RELAXATION_FLOAT), /*!< thresHoldDiff */
|
|
FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< tresHoldDiffGuide */
|
|
FL2FXCONST_DBL(15.0f * RELAXATION_FLOAT), /*!< thresHoldTone */
|
|
FL2FXCONST_DBL((1.0f / 15.0f) *
|
|
RELAXATION_FLOAT), /*!< invThresHoldTone */
|
|
FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< thresHoldToneGuide */
|
|
FL2FXCONST_DBL(0.3f) >> SFM_SHIFT, /*!< sfmThresSbr */
|
|
FL2FXCONST_DBL(0.1f) >> SFM_SHIFT, /*!< sfmThresOrig */
|
|
FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */
|
|
FL2FXCONST_DBL(0.2f), /*!< decayGuideDiff */
|
|
FL2FXCONST_DBL(-0.000112993269),
|
|
/* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */
|
|
FL2FXCONST_DBL(-0.000112993269),
|
|
/* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */
|
|
FL2FXCONST_DBL(
|
|
-0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!<
|
|
derivThresAboveLD64
|
|
*/
|
|
},
|
|
50 /*!< maxComp */
|
|
};
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Calculates the difference in tonality between original and SBR
|
|
for a given time and frequency region.
|
|
|
|
The values for pDiffMapped2Scfb are scaled by RELAXATION
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static void diff(FIXP_DBL *RESTRICT pTonalityOrig, FIXP_DBL *pDiffMapped2Scfb,
|
|
const UCHAR *RESTRICT pFreqBandTable, INT nScfb,
|
|
SCHAR *indexVector) {
|
|
UCHAR i, ll, lu, k;
|
|
FIXP_DBL maxValOrig, maxValSbr, tmp;
|
|
INT scale;
|
|
|
|
for (i = 0; i < nScfb; i++) {
|
|
ll = pFreqBandTable[i];
|
|
lu = pFreqBandTable[i + 1];
|
|
|
|
maxValOrig = FL2FXCONST_DBL(0.0f);
|
|
maxValSbr = FL2FXCONST_DBL(0.0f);
|
|
|
|
for (k = ll; k < lu; k++) {
|
|
maxValOrig = fixMax(maxValOrig, pTonalityOrig[k]);
|
|
maxValSbr = fixMax(maxValSbr, pTonalityOrig[indexVector[k]]);
|
|
}
|
|
|
|
if ((maxValSbr >= RELAXATION)) {
|
|
tmp = fDivNorm(maxValOrig, maxValSbr, &scale);
|
|
pDiffMapped2Scfb[i] =
|
|
scaleValue(fMult(tmp, RELAXATION_FRACT),
|
|
fixMax(-(DFRACT_BITS - 1), (scale - RELAXATION_SHIFT)));
|
|
} else {
|
|
pDiffMapped2Scfb[i] = maxValOrig;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Calculates a flatness measure of the tonality measures.
|
|
|
|
Calculation of the power function and using scalefactor for basis:
|
|
Using log2:
|
|
z = (2^k * x)^y;
|
|
z' = CalcLd(z) = y*CalcLd(x) + y*k;
|
|
z = CalcInvLd(z');
|
|
|
|
Using ld64:
|
|
z = (2^k * x)^y;
|
|
z' = CalcLd64(z) = y*CalcLd64(x)/64 + y*k/64;
|
|
z = CalcInvLd64(z');
|
|
|
|
The values pSfmOrigVec and pSfmSbrVec are scaled by the factor 1/4.0
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static void calculateFlatnessMeasure(FIXP_DBL *pQuotaBuffer, SCHAR *indexVector,
|
|
FIXP_DBL *pSfmOrigVec,
|
|
FIXP_DBL *pSfmSbrVec,
|
|
const UCHAR *pFreqBandTable, INT nSfb) {
|
|
INT i, j;
|
|
FIXP_DBL invBands, tmp1, tmp2;
|
|
INT shiftFac0, shiftFacSum0;
|
|
INT shiftFac1, shiftFacSum1;
|
|
FIXP_DBL accu;
|
|
|
|
for (i = 0; i < nSfb; i++) {
|
|
INT ll = pFreqBandTable[i];
|
|
INT lu = pFreqBandTable[i + 1];
|
|
pSfmOrigVec[i] = (FIXP_DBL)(MAXVAL_DBL >> 2);
|
|
pSfmSbrVec[i] = (FIXP_DBL)(MAXVAL_DBL >> 2);
|
|
|
|
if (lu - ll > 1) {
|
|
FIXP_DBL amOrig, amTransp, gmOrig, gmTransp, sfmOrig, sfmTransp;
|
|
invBands = GetInvInt(lu - ll);
|
|
shiftFacSum0 = 0;
|
|
shiftFacSum1 = 0;
|
|
amOrig = amTransp = FL2FXCONST_DBL(0.0f);
|
|
gmOrig = gmTransp = (FIXP_DBL)MAXVAL_DBL;
|
|
|
|
for (j = ll; j < lu; j++) {
|
|
sfmOrig = pQuotaBuffer[j];
|
|
sfmTransp = pQuotaBuffer[indexVector[j]];
|
|
|
|
amOrig += fMult(sfmOrig, invBands);
|
|
amTransp += fMult(sfmTransp, invBands);
|
|
|
|
shiftFac0 = CountLeadingBits(sfmOrig);
|
|
shiftFac1 = CountLeadingBits(sfmTransp);
|
|
|
|
gmOrig = fMult(gmOrig, sfmOrig << shiftFac0);
|
|
gmTransp = fMult(gmTransp, sfmTransp << shiftFac1);
|
|
|
|
shiftFacSum0 += shiftFac0;
|
|
shiftFacSum1 += shiftFac1;
|
|
}
|
|
|
|
if (gmOrig > FL2FXCONST_DBL(0.0f)) {
|
|
tmp1 = CalcLdData(gmOrig); /* CalcLd64(x)/64 */
|
|
tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */
|
|
|
|
/* y*k/64 */
|
|
accu = (FIXP_DBL)-shiftFacSum0 << (DFRACT_BITS - 1 - 8);
|
|
tmp2 = fMultDiv2(invBands, accu) << (2 + 1);
|
|
|
|
tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */
|
|
gmOrig = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */
|
|
} else {
|
|
gmOrig = FL2FXCONST_DBL(0.0f);
|
|
}
|
|
|
|
if (gmTransp > FL2FXCONST_DBL(0.0f)) {
|
|
tmp1 = CalcLdData(gmTransp); /* CalcLd64(x)/64 */
|
|
tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */
|
|
|
|
/* y*k/64 */
|
|
accu = (FIXP_DBL)-shiftFacSum1 << (DFRACT_BITS - 1 - 8);
|
|
tmp2 = fMultDiv2(invBands, accu) << (2 + 1);
|
|
|
|
tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */
|
|
gmTransp = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */
|
|
} else {
|
|
gmTransp = FL2FXCONST_DBL(0.0f);
|
|
}
|
|
if (amOrig != FL2FXCONST_DBL(0.0f))
|
|
pSfmOrigVec[i] =
|
|
FDKsbrEnc_LSI_divide_scale_fract(gmOrig, amOrig, SFM_SCALE);
|
|
|
|
if (amTransp != FL2FXCONST_DBL(0.0f))
|
|
pSfmSbrVec[i] =
|
|
FDKsbrEnc_LSI_divide_scale_fract(gmTransp, amTransp, SFM_SCALE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Calculates the input to the missing harmonics detection.
|
|
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static void calculateDetectorInput(
|
|
FIXP_DBL **RESTRICT pQuotaBuffer, /*!< Pointer to tonality matrix. */
|
|
SCHAR *RESTRICT indexVector, FIXP_DBL **RESTRICT tonalityDiff,
|
|
FIXP_DBL **RESTRICT pSfmOrig, FIXP_DBL **RESTRICT pSfmSbr,
|
|
const UCHAR *freqBandTable, INT nSfb, INT noEstPerFrame, INT move) {
|
|
INT est;
|
|
|
|
/*
|
|
New estimate.
|
|
*/
|
|
for (est = 0; est < noEstPerFrame; est++) {
|
|
diff(pQuotaBuffer[est + move], tonalityDiff[est + move], freqBandTable,
|
|
nSfb, indexVector);
|
|
|
|
calculateFlatnessMeasure(pQuotaBuffer[est + move], indexVector,
|
|
pSfmOrig[est + move], pSfmSbr[est + move],
|
|
freqBandTable, nSfb);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Checks that the detection is not due to a LP filter
|
|
|
|
This function determines if a newly detected missing harmonics is not
|
|
in fact just a low-pass filtere input signal. If so, the detection is
|
|
removed.
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static void removeLowPassDetection(UCHAR *RESTRICT pAddHarmSfb,
|
|
UCHAR **RESTRICT pDetectionVectors,
|
|
INT start, INT stop, INT nSfb,
|
|
const UCHAR *RESTRICT pFreqBandTable,
|
|
FIXP_DBL *RESTRICT pNrgVector,
|
|
THRES_HOLDS mhThresh)
|
|
|
|
{
|
|
INT i, est;
|
|
INT maxDerivPos = pFreqBandTable[nSfb];
|
|
INT numBands = pFreqBandTable[nSfb];
|
|
FIXP_DBL nrgLow, nrgHigh;
|
|
FIXP_DBL nrgLD64, nrgLowLD64, nrgHighLD64, nrgDiffLD64;
|
|
FIXP_DBL valLD64, maxValLD64, maxValAboveLD64;
|
|
INT bLPsignal = 0;
|
|
|
|
maxValLD64 = FL2FXCONST_DBL(-1.0f);
|
|
for (i = numBands - 1 - 2; i > pFreqBandTable[0]; i--) {
|
|
nrgLow = pNrgVector[i];
|
|
nrgHigh = pNrgVector[i + 2];
|
|
|
|
if (nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh) {
|
|
nrgLowLD64 = CalcLdData(nrgLow >> 1);
|
|
nrgDiffLD64 = CalcLdData((nrgLow >> 1) - (nrgHigh >> 1));
|
|
valLD64 = nrgDiffLD64 - nrgLowLD64;
|
|
if (valLD64 > maxValLD64) {
|
|
maxDerivPos = i;
|
|
maxValLD64 = valLD64;
|
|
}
|
|
if (maxValLD64 > mhThresh.derivThresMaxLD64) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Find the largest "gradient" above. (should be relatively flat, hence we
|
|
expect a low value if the signal is LP.*/
|
|
maxValAboveLD64 = FL2FXCONST_DBL(-1.0f);
|
|
for (i = numBands - 1 - 2; i > maxDerivPos + 2; i--) {
|
|
nrgLow = pNrgVector[i];
|
|
nrgHigh = pNrgVector[i + 2];
|
|
|
|
if (nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh) {
|
|
nrgLowLD64 = CalcLdData(nrgLow >> 1);
|
|
nrgDiffLD64 = CalcLdData((nrgLow >> 1) - (nrgHigh >> 1));
|
|
valLD64 = nrgDiffLD64 - nrgLowLD64;
|
|
if (valLD64 > maxValAboveLD64) {
|
|
maxValAboveLD64 = valLD64;
|
|
}
|
|
} else {
|
|
if (nrgHigh != FL2FXCONST_DBL(0.0f) && nrgHigh > nrgLow) {
|
|
nrgHighLD64 = CalcLdData(nrgHigh >> 1);
|
|
nrgDiffLD64 = CalcLdData((nrgHigh >> 1) - (nrgLow >> 1));
|
|
valLD64 = nrgDiffLD64 - nrgHighLD64;
|
|
if (valLD64 > maxValAboveLD64) {
|
|
maxValAboveLD64 = valLD64;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (maxValLD64 > mhThresh.derivThresMaxLD64 &&
|
|
maxValAboveLD64 < mhThresh.derivThresAboveLD64) {
|
|
bLPsignal = 1;
|
|
|
|
for (i = maxDerivPos - 1; i > maxDerivPos - 5 && i >= 0; i--) {
|
|
if (pNrgVector[i] != FL2FXCONST_DBL(0.0f) &&
|
|
pNrgVector[i] > pNrgVector[maxDerivPos + 2]) {
|
|
nrgDiffLD64 = CalcLdData((pNrgVector[i] >> 1) -
|
|
(pNrgVector[maxDerivPos + 2] >> 1));
|
|
nrgLD64 = CalcLdData(pNrgVector[i] >> 1);
|
|
valLD64 = nrgDiffLD64 - nrgLD64;
|
|
if (valLD64 < mhThresh.derivThresBelowLD64) {
|
|
bLPsignal = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
bLPsignal = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bLPsignal) {
|
|
for (i = 0; i < nSfb; i++) {
|
|
if (maxDerivPos >= pFreqBandTable[i] &&
|
|
maxDerivPos < pFreqBandTable[i + 1])
|
|
break;
|
|
}
|
|
|
|
if (pAddHarmSfb[i]) {
|
|
pAddHarmSfb[i] = 0;
|
|
for (est = start; est < stop; est++) {
|
|
pDetectionVectors[est][i] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Checks if it is allowed to detect a missing tone, that wasn't
|
|
detected previously.
|
|
|
|
|
|
\return newDetectionAllowed flag.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static INT isDetectionOfNewToneAllowed(
|
|
const SBR_FRAME_INFO *pFrameInfo, INT *pDetectionStartPos,
|
|
INT noEstPerFrame, INT prevTransientFrame, INT prevTransientPos,
|
|
INT prevTransientFlag, INT transientPosOffset, INT transientFlag,
|
|
INT transientPos, INT deltaTime,
|
|
HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector) {
|
|
INT transientFrame, newDetectionAllowed;
|
|
|
|
/* Determine if this is a frame where a transient starts...
|
|
* If the transient flag was set the previous frame but not the
|
|
* transient frame flag, the transient frame flag is set in the current frame.
|
|
*****************************************************************************/
|
|
transientFrame = 0;
|
|
if (transientFlag) {
|
|
if (transientPos + transientPosOffset <
|
|
pFrameInfo->borders[pFrameInfo->nEnvelopes]) {
|
|
transientFrame = 1;
|
|
if (noEstPerFrame > 1) {
|
|
if (transientPos + transientPosOffset >
|
|
h_sbrMissingHarmonicsDetector->timeSlots >> 1) {
|
|
*pDetectionStartPos = noEstPerFrame;
|
|
} else {
|
|
*pDetectionStartPos = noEstPerFrame >> 1;
|
|
}
|
|
|
|
} else {
|
|
*pDetectionStartPos = noEstPerFrame;
|
|
}
|
|
}
|
|
} else {
|
|
if (prevTransientFlag && !prevTransientFrame) {
|
|
transientFrame = 1;
|
|
*pDetectionStartPos = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Determine if detection of new missing harmonics are allowed.
|
|
* If the frame contains a transient it's ok. If the previous
|
|
* frame contained a transient it needs to be sufficiently close
|
|
* to the start of the current frame.
|
|
****************************************************************/
|
|
newDetectionAllowed = 0;
|
|
if (transientFrame) {
|
|
newDetectionAllowed = 1;
|
|
} else {
|
|
if (prevTransientFrame &&
|
|
fixp_abs(pFrameInfo->borders[0] -
|
|
(prevTransientPos + transientPosOffset -
|
|
h_sbrMissingHarmonicsDetector->timeSlots)) < deltaTime) {
|
|
newDetectionAllowed = 1;
|
|
*pDetectionStartPos = 0;
|
|
}
|
|
}
|
|
|
|
h_sbrMissingHarmonicsDetector->previousTransientFlag = transientFlag;
|
|
h_sbrMissingHarmonicsDetector->previousTransientFrame = transientFrame;
|
|
h_sbrMissingHarmonicsDetector->previousTransientPos = transientPos;
|
|
|
|
return (newDetectionAllowed);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Cleans up the detection after a transient.
|
|
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static void transientCleanUp(FIXP_DBL **quotaBuffer, INT nSfb,
|
|
UCHAR **detectionVectors, UCHAR *pAddHarmSfb,
|
|
UCHAR *pPrevAddHarmSfb, INT **signBuffer,
|
|
const UCHAR *pFreqBandTable, INT start, INT stop,
|
|
INT newDetectionAllowed, FIXP_DBL *pNrgVector,
|
|
THRES_HOLDS mhThresh) {
|
|
INT i, j, est;
|
|
|
|
for (est = start; est < stop; est++) {
|
|
for (i = 0; i < nSfb; i++) {
|
|
pAddHarmSfb[i] = pAddHarmSfb[i] || detectionVectors[est][i];
|
|
}
|
|
}
|
|
|
|
if (newDetectionAllowed == 1) {
|
|
/*
|
|
* Check for duplication of sines located
|
|
* on the border of two scf-bands.
|
|
*************************************************/
|
|
for (i = 0; i < nSfb - 1; i++) {
|
|
/* detection in adjacent channels.*/
|
|
if (pAddHarmSfb[i] && pAddHarmSfb[i + 1]) {
|
|
FIXP_DBL maxVal1, maxVal2;
|
|
INT maxPos1, maxPos2, maxPosTime1, maxPosTime2;
|
|
|
|
INT li = pFreqBandTable[i];
|
|
INT ui = pFreqBandTable[i + 1];
|
|
|
|
/* Find maximum tonality in the the two scf bands.*/
|
|
maxPosTime1 = start;
|
|
maxPos1 = li;
|
|
maxVal1 = quotaBuffer[start][li];
|
|
for (est = start; est < stop; est++) {
|
|
for (j = li; j < ui; j++) {
|
|
if (quotaBuffer[est][j] > maxVal1) {
|
|
maxVal1 = quotaBuffer[est][j];
|
|
maxPos1 = j;
|
|
maxPosTime1 = est;
|
|
}
|
|
}
|
|
}
|
|
|
|
li = pFreqBandTable[i + 1];
|
|
ui = pFreqBandTable[i + 2];
|
|
|
|
/* Find maximum tonality in the the two scf bands.*/
|
|
maxPosTime2 = start;
|
|
maxPos2 = li;
|
|
maxVal2 = quotaBuffer[start][li];
|
|
for (est = start; est < stop; est++) {
|
|
for (j = li; j < ui; j++) {
|
|
if (quotaBuffer[est][j] > maxVal2) {
|
|
maxVal2 = quotaBuffer[est][j];
|
|
maxPos2 = j;
|
|
maxPosTime2 = est;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If the maximum values are in adjacent QMF-channels, we need to remove
|
|
the lowest of the two.*/
|
|
if (maxPos2 - maxPos1 < 2) {
|
|
if (pPrevAddHarmSfb[i] == 1 && pPrevAddHarmSfb[i + 1] == 0) {
|
|
/* Keep the lower, remove the upper.*/
|
|
pAddHarmSfb[i + 1] = 0;
|
|
for (est = start; est < stop; est++) {
|
|
detectionVectors[est][i + 1] = 0;
|
|
}
|
|
} else {
|
|
if (pPrevAddHarmSfb[i] == 0 && pPrevAddHarmSfb[i + 1] == 1) {
|
|
/* Keep the upper, remove the lower.*/
|
|
pAddHarmSfb[i] = 0;
|
|
for (est = start; est < stop; est++) {
|
|
detectionVectors[est][i] = 0;
|
|
}
|
|
} else {
|
|
/* If the maximum values are in adjacent QMF-channels, and if the
|
|
signs indicate that it is the same sine, we need to remove the
|
|
lowest of the two.*/
|
|
if (maxVal1 > maxVal2) {
|
|
if (signBuffer[maxPosTime1][maxPos2] < 0 &&
|
|
signBuffer[maxPosTime1][maxPos1] > 0) {
|
|
/* Keep the lower, remove the upper.*/
|
|
pAddHarmSfb[i + 1] = 0;
|
|
for (est = start; est < stop; est++) {
|
|
detectionVectors[est][i + 1] = 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (signBuffer[maxPosTime2][maxPos2] < 0 &&
|
|
signBuffer[maxPosTime2][maxPos1] > 0) {
|
|
/* Keep the upper, remove the lower.*/
|
|
pAddHarmSfb[i] = 0;
|
|
for (est = start; est < stop; est++) {
|
|
detectionVectors[est][i] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Make sure that the detection is not the cut-off of a low pass filter. */
|
|
removeLowPassDetection(pAddHarmSfb, detectionVectors, start, stop, nSfb,
|
|
pFreqBandTable, pNrgVector, mhThresh);
|
|
} else {
|
|
/*
|
|
* If a missing harmonic wasn't missing the previous frame
|
|
* the transient-flag needs to be set in order to be allowed to detect it.
|
|
*************************************************************************/
|
|
for (i = 0; i < nSfb; i++) {
|
|
if (pAddHarmSfb[i] - pPrevAddHarmSfb[i] > 0) pAddHarmSfb[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*!
|
|
\brief Detection for one tonality estimate.
|
|
|
|
This is the actual missing harmonics detection, using information from the
|
|
previous detection.
|
|
|
|
If a missing harmonic was detected (in a previous frame) due to too high
|
|
tonality differences, but there was not enough tonality difference in the
|
|
current frame, the detection algorithm still continues to trace the strongest
|
|
tone in the scalefactor band (assuming that this is the tone that is going to
|
|
be replaced in the decoder). This is done to avoid abrupt endings of sines
|
|
fading out (e.g. in the glockenspiel).
|
|
|
|
The function also tries to estimate where one sine is going to be replaced
|
|
with multiple sines (due to the patching). This is done by comparing the
|
|
tonality flatness measure of the original and the SBR signal.
|
|
|
|
The function also tries to estimate (for the scalefactor bands only
|
|
containing one qmf subband) when a strong tone in the original will be
|
|
replaced by a strong tone in the adjacent QMF subband.
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static void detection(FIXP_DBL *quotaBuffer, FIXP_DBL *pDiffVecScfb, INT nSfb,
|
|
UCHAR *pHarmVec, const UCHAR *pFreqBandTable,
|
|
FIXP_DBL *sfmOrig, FIXP_DBL *sfmSbr,
|
|
GUIDE_VECTORS guideVectors, GUIDE_VECTORS newGuideVectors,
|
|
THRES_HOLDS mhThresh) {
|
|
INT i, j, ll, lu;
|
|
FIXP_DBL thresTemp, thresOrig;
|
|
|
|
/*
|
|
* Do detection on the difference vector, i.e. the difference between
|
|
* the original and the transposed.
|
|
*********************************************************************/
|
|
for (i = 0; i < nSfb; i++) {
|
|
thresTemp = (guideVectors.guideVectorDiff[i] != FL2FXCONST_DBL(0.0f))
|
|
? fMax(fMult(mhThresh.decayGuideDiff,
|
|
guideVectors.guideVectorDiff[i]),
|
|
mhThresh.thresHoldDiffGuide)
|
|
: mhThresh.thresHoldDiff;
|
|
|
|
thresTemp = fMin(thresTemp, mhThresh.thresHoldDiff);
|
|
|
|
if (pDiffVecScfb[i] > thresTemp) {
|
|
pHarmVec[i] = 1;
|
|
newGuideVectors.guideVectorDiff[i] = pDiffVecScfb[i];
|
|
} else {
|
|
/* If the guide wasn't zero, but the current level is to low,
|
|
start tracking the decay on the tone in the original rather
|
|
than the difference.*/
|
|
if (guideVectors.guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)) {
|
|
guideVectors.guideVectorOrig[i] = mhThresh.thresHoldToneGuide;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Trace tones in the original signal that at one point
|
|
* have been detected because they will be replaced by
|
|
* multiple tones in the sbr signal.
|
|
****************************************************/
|
|
|
|
for (i = 0; i < nSfb; i++) {
|
|
ll = pFreqBandTable[i];
|
|
lu = pFreqBandTable[i + 1];
|
|
|
|
thresOrig =
|
|
fixMax(fMult(guideVectors.guideVectorOrig[i], mhThresh.decayGuideOrig),
|
|
mhThresh.thresHoldToneGuide);
|
|
thresOrig = fixMin(thresOrig, mhThresh.thresHoldTone);
|
|
|
|
if (guideVectors.guideVectorOrig[i] != FL2FXCONST_DBL(0.0f)) {
|
|
for (j = ll; j < lu; j++) {
|
|
if (quotaBuffer[j] > thresOrig) {
|
|
pHarmVec[i] = 1;
|
|
newGuideVectors.guideVectorOrig[i] = quotaBuffer[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check for multiple sines in the transposed signal,
|
|
* where there is only one in the original.
|
|
****************************************************/
|
|
thresOrig = mhThresh.thresHoldTone;
|
|
|
|
for (i = 0; i < nSfb; i++) {
|
|
ll = pFreqBandTable[i];
|
|
lu = pFreqBandTable[i + 1];
|
|
|
|
if (pHarmVec[i] == 0) {
|
|
if (lu - ll > 1) {
|
|
for (j = ll; j < lu; j++) {
|
|
if (quotaBuffer[j] > thresOrig &&
|
|
(sfmSbr[i] > mhThresh.sfmThresSbr &&
|
|
sfmOrig[i] < mhThresh.sfmThresOrig)) {
|
|
pHarmVec[i] = 1;
|
|
newGuideVectors.guideVectorOrig[i] = quotaBuffer[j];
|
|
}
|
|
}
|
|
} else {
|
|
if (i < nSfb - 1) {
|
|
ll = pFreqBandTable[i];
|
|
|
|
if (i > 0) {
|
|
if (quotaBuffer[ll] > mhThresh.thresHoldTone &&
|
|
(pDiffVecScfb[i + 1] < mhThresh.invThresHoldTone ||
|
|
pDiffVecScfb[i - 1] < mhThresh.invThresHoldTone)) {
|
|
pHarmVec[i] = 1;
|
|
newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll];
|
|
}
|
|
} else {
|
|
if (quotaBuffer[ll] > mhThresh.thresHoldTone &&
|
|
pDiffVecScfb[i + 1] < mhThresh.invThresHoldTone) {
|
|
pHarmVec[i] = 1;
|
|
newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Do detection for every tonality estimate, using forward prediction.
|
|
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static void detectionWithPrediction(
|
|
FIXP_DBL **quotaBuffer, FIXP_DBL **pDiffVecScfb, INT **signBuffer, INT nSfb,
|
|
const UCHAR *pFreqBandTable, FIXP_DBL **sfmOrig, FIXP_DBL **sfmSbr,
|
|
UCHAR **detectionVectors, UCHAR *pPrevAddHarmSfb,
|
|
GUIDE_VECTORS *guideVectors, INT noEstPerFrame, INT detectionStart,
|
|
INT totNoEst, INT newDetectionAllowed, INT *pAddHarmFlag,
|
|
UCHAR *pAddHarmSfb, FIXP_DBL *pNrgVector,
|
|
const DETECTOR_PARAMETERS_MH *mhParams) {
|
|
INT est = 0, i;
|
|
INT start;
|
|
|
|
FDKmemclear(pAddHarmSfb, nSfb * sizeof(UCHAR));
|
|
|
|
if (newDetectionAllowed) {
|
|
/* Since we don't want to use the transient region for detection (since the
|
|
tonality values tend to be a bit unreliable for this region) the
|
|
guide-values are copied to the current starting point. */
|
|
if (totNoEst > 1) {
|
|
start = detectionStart + 1;
|
|
|
|
if (start != 0) {
|
|
FDKmemcpy(guideVectors[start].guideVectorDiff,
|
|
guideVectors[0].guideVectorDiff, nSfb * sizeof(FIXP_DBL));
|
|
FDKmemcpy(guideVectors[start].guideVectorOrig,
|
|
guideVectors[0].guideVectorOrig, nSfb * sizeof(FIXP_DBL));
|
|
FDKmemclear(guideVectors[start - 1].guideVectorDetected,
|
|
nSfb * sizeof(UCHAR));
|
|
}
|
|
} else {
|
|
start = 0;
|
|
}
|
|
} else {
|
|
start = 0;
|
|
}
|
|
|
|
for (est = start; est < totNoEst; est++) {
|
|
/*
|
|
* Do detection on the current frame using
|
|
* guide-info from the previous.
|
|
*******************************************/
|
|
if (est > 0) {
|
|
FDKmemcpy(guideVectors[est].guideVectorDetected,
|
|
detectionVectors[est - 1], nSfb * sizeof(UCHAR));
|
|
}
|
|
|
|
FDKmemclear(detectionVectors[est], nSfb * sizeof(UCHAR));
|
|
|
|
if (est < totNoEst - 1) {
|
|
FDKmemclear(guideVectors[est + 1].guideVectorDiff,
|
|
nSfb * sizeof(FIXP_DBL));
|
|
FDKmemclear(guideVectors[est + 1].guideVectorOrig,
|
|
nSfb * sizeof(FIXP_DBL));
|
|
FDKmemclear(guideVectors[est + 1].guideVectorDetected,
|
|
nSfb * sizeof(UCHAR));
|
|
|
|
detection(quotaBuffer[est], pDiffVecScfb[est], nSfb,
|
|
detectionVectors[est], pFreqBandTable, sfmOrig[est],
|
|
sfmSbr[est], guideVectors[est], guideVectors[est + 1],
|
|
mhParams->thresHolds);
|
|
} else {
|
|
FDKmemclear(guideVectors[est].guideVectorDiff, nSfb * sizeof(FIXP_DBL));
|
|
FDKmemclear(guideVectors[est].guideVectorOrig, nSfb * sizeof(FIXP_DBL));
|
|
FDKmemclear(guideVectors[est].guideVectorDetected, nSfb * sizeof(UCHAR));
|
|
|
|
detection(quotaBuffer[est], pDiffVecScfb[est], nSfb,
|
|
detectionVectors[est], pFreqBandTable, sfmOrig[est],
|
|
sfmSbr[est], guideVectors[est], guideVectors[est],
|
|
mhParams->thresHolds);
|
|
}
|
|
}
|
|
|
|
/* Clean up the detection.*/
|
|
transientCleanUp(quotaBuffer, nSfb, detectionVectors, pAddHarmSfb,
|
|
pPrevAddHarmSfb, signBuffer, pFreqBandTable, start, totNoEst,
|
|
newDetectionAllowed, pNrgVector, mhParams->thresHolds);
|
|
|
|
/* Set flag... */
|
|
*pAddHarmFlag = 0;
|
|
for (i = 0; i < nSfb; i++) {
|
|
if (pAddHarmSfb[i]) {
|
|
*pAddHarmFlag = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
FDKmemcpy(pPrevAddHarmSfb, pAddHarmSfb, nSfb * sizeof(UCHAR));
|
|
FDKmemcpy(guideVectors[0].guideVectorDetected, pAddHarmSfb,
|
|
nSfb * sizeof(INT));
|
|
|
|
for (i = 0; i < nSfb; i++) {
|
|
guideVectors[0].guideVectorDiff[i] = FL2FXCONST_DBL(0.0f);
|
|
guideVectors[0].guideVectorOrig[i] = FL2FXCONST_DBL(0.0f);
|
|
|
|
if (pAddHarmSfb[i] == 1) {
|
|
/* If we had a detection use the guide-value in the next frame from the
|
|
last estimate were the detection was done.*/
|
|
for (est = start; est < totNoEst; est++) {
|
|
if (guideVectors[est].guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)) {
|
|
guideVectors[0].guideVectorDiff[i] =
|
|
guideVectors[est].guideVectorDiff[i];
|
|
}
|
|
if (guideVectors[est].guideVectorOrig[i] != FL2FXCONST_DBL(0.0f)) {
|
|
guideVectors[0].guideVectorOrig[i] =
|
|
guideVectors[est].guideVectorOrig[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Calculates a compensation vector for the energy data.
|
|
|
|
This function calculates a compensation vector for the energy data (i.e.
|
|
envelope data) that is calculated elsewhere. This is since, one sine on
|
|
the border of two scalefactor bands, will be replace by one sine in the
|
|
middle of either scalefactor band. However, since the sine that is replaced
|
|
will influence the energy estimate in both scalefactor bands (in the envelops
|
|
calculation function) a compensation value is required in order to avoid
|
|
noise substitution in the decoder next to the synthetic sine.
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static void calculateCompVector(UCHAR *pAddHarmSfb, FIXP_DBL **pTonalityMatrix,
|
|
INT **pSignMatrix, UCHAR *pEnvComp, INT nSfb,
|
|
const UCHAR *freqBandTable, INT totNoEst,
|
|
INT maxComp, UCHAR *pPrevEnvComp,
|
|
INT newDetectionAllowed) {
|
|
INT scfBand, est, l, ll, lu, maxPosF, maxPosT;
|
|
FIXP_DBL maxVal;
|
|
INT compValue;
|
|
FIXP_DBL tmp;
|
|
|
|
FDKmemclear(pEnvComp, nSfb * sizeof(UCHAR));
|
|
|
|
for (scfBand = 0; scfBand < nSfb; scfBand++) {
|
|
if (pAddHarmSfb[scfBand]) { /* A missing sine was detected */
|
|
ll = freqBandTable[scfBand];
|
|
lu = freqBandTable[scfBand + 1];
|
|
|
|
maxPosF = 0; /* First find the maximum*/
|
|
maxPosT = 0;
|
|
maxVal = FL2FXCONST_DBL(0.0f);
|
|
|
|
for (est = 0; est < totNoEst; est++) {
|
|
for (l = ll; l < lu; l++) {
|
|
if (pTonalityMatrix[est][l] > maxVal) {
|
|
maxVal = pTonalityMatrix[est][l];
|
|
maxPosF = l;
|
|
maxPosT = est;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the maximum tonality is at the lower border of the
|
|
* scalefactor band, we check the sign of the adjacent channels
|
|
* to see if this sine is shared by the lower channel. If so, the
|
|
* energy of the single sine will be present in two scalefactor bands
|
|
* in the SBR data, which will cause problems in the decoder, when we
|
|
* add a sine to just one of the channels.
|
|
*********************************************************************/
|
|
if (maxPosF == ll && scfBand) {
|
|
if (!pAddHarmSfb[scfBand - 1]) { /* No detection below*/
|
|
if (pSignMatrix[maxPosT][maxPosF - 1] > 0 &&
|
|
pSignMatrix[maxPosT][maxPosF] < 0) {
|
|
/* The comp value is calulated as the tonallity value, i.e we want
|
|
to reduce the envelope data for this channel with as much as the
|
|
tonality that is spread from the channel above. (ld64(RELAXATION)
|
|
= 0.31143075889) */
|
|
tmp = fixp_abs(
|
|
(FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF - 1]) +
|
|
RELAXATION_LD64);
|
|
tmp = (tmp >> (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1)) +
|
|
(FIXP_DBL)1; /* shift one bit less for rounding */
|
|
compValue = ((INT)(LONG)tmp) >> 1;
|
|
|
|
/* limit the comp-value*/
|
|
if (compValue > maxComp) compValue = maxComp;
|
|
|
|
pEnvComp[scfBand - 1] = compValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Same as above, but for the upper end of the scalefactor-band.
|
|
***************************************************************/
|
|
if (maxPosF == lu - 1 && scfBand + 1 < nSfb) { /* Upper border*/
|
|
if (!pAddHarmSfb[scfBand + 1]) {
|
|
if (pSignMatrix[maxPosT][maxPosF] > 0 &&
|
|
pSignMatrix[maxPosT][maxPosF + 1] < 0) {
|
|
tmp = fixp_abs(
|
|
(FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF + 1]) +
|
|
RELAXATION_LD64);
|
|
tmp = (tmp >> (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1)) +
|
|
(FIXP_DBL)1; /* shift one bit less for rounding */
|
|
compValue = ((INT)(LONG)tmp) >> 1;
|
|
|
|
if (compValue > maxComp) compValue = maxComp;
|
|
|
|
pEnvComp[scfBand + 1] = compValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (newDetectionAllowed == 0) {
|
|
for (scfBand = 0; scfBand < nSfb; scfBand++) {
|
|
if (pEnvComp[scfBand] != 0 && pPrevEnvComp[scfBand] == 0)
|
|
pEnvComp[scfBand] = 0;
|
|
}
|
|
}
|
|
|
|
/* remember the value for the next frame.*/
|
|
FDKmemcpy(pPrevEnvComp, pEnvComp, nSfb * sizeof(UCHAR));
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Detects where strong tonal components will be missing after
|
|
HFR in the decoder.
|
|
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
void FDKsbrEnc_SbrMissingHarmonicsDetectorQmf(
|
|
HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMHDet, FIXP_DBL **pQuotaBuffer,
|
|
INT **pSignBuffer, SCHAR *indexVector, const SBR_FRAME_INFO *pFrameInfo,
|
|
const UCHAR *pTranInfo, INT *pAddHarmonicsFlag,
|
|
UCHAR *pAddHarmonicsScaleFactorBands, const UCHAR *freqBandTable, INT nSfb,
|
|
UCHAR *envelopeCompensation, FIXP_DBL *pNrgVector) {
|
|
INT transientFlag = pTranInfo[1];
|
|
INT transientPos = pTranInfo[0];
|
|
INT newDetectionAllowed;
|
|
INT transientDetStart = 0;
|
|
|
|
UCHAR **detectionVectors = h_sbrMHDet->detectionVectors;
|
|
INT move = h_sbrMHDet->move;
|
|
INT noEstPerFrame = h_sbrMHDet->noEstPerFrame;
|
|
INT totNoEst = h_sbrMHDet->totNoEst;
|
|
INT prevTransientFlag = h_sbrMHDet->previousTransientFlag;
|
|
INT prevTransientFrame = h_sbrMHDet->previousTransientFrame;
|
|
INT transientPosOffset = h_sbrMHDet->transientPosOffset;
|
|
INT prevTransientPos = h_sbrMHDet->previousTransientPos;
|
|
GUIDE_VECTORS *guideVectors = h_sbrMHDet->guideVectors;
|
|
INT deltaTime = h_sbrMHDet->mhParams->deltaTime;
|
|
INT maxComp = h_sbrMHDet->mhParams->maxComp;
|
|
|
|
int est;
|
|
|
|
/*
|
|
Buffer values.
|
|
*/
|
|
FDK_ASSERT(move <= (MAX_NO_OF_ESTIMATES >> 1));
|
|
FDK_ASSERT(noEstPerFrame <= (MAX_NO_OF_ESTIMATES >> 1));
|
|
|
|
FIXP_DBL *sfmSbr[MAX_NO_OF_ESTIMATES];
|
|
FIXP_DBL *sfmOrig[MAX_NO_OF_ESTIMATES];
|
|
FIXP_DBL *tonalityDiff[MAX_NO_OF_ESTIMATES];
|
|
|
|
for (est = 0; est < MAX_NO_OF_ESTIMATES / 2; est++) {
|
|
sfmSbr[est] = h_sbrMHDet->sfmSbr[est];
|
|
sfmOrig[est] = h_sbrMHDet->sfmOrig[est];
|
|
tonalityDiff[est] = h_sbrMHDet->tonalityDiff[est];
|
|
}
|
|
|
|
C_ALLOC_SCRATCH_START(_scratch, FIXP_DBL,
|
|
3 * MAX_NO_OF_ESTIMATES / 2 * MAX_FREQ_COEFFS)
|
|
FIXP_DBL *scratch = _scratch;
|
|
for (; est < MAX_NO_OF_ESTIMATES; est++) {
|
|
sfmSbr[est] = scratch;
|
|
scratch += MAX_FREQ_COEFFS;
|
|
sfmOrig[est] = scratch;
|
|
scratch += MAX_FREQ_COEFFS;
|
|
tonalityDiff[est] = scratch;
|
|
scratch += MAX_FREQ_COEFFS;
|
|
}
|
|
|
|
/* Determine if we're allowed to detect "missing harmonics" that wasn't
|
|
detected before. In order to be allowed to do new detection, there must be
|
|
a transient in the current frame, or a transient in the previous frame
|
|
sufficiently close to the current frame. */
|
|
newDetectionAllowed = isDetectionOfNewToneAllowed(
|
|
pFrameInfo, &transientDetStart, noEstPerFrame, prevTransientFrame,
|
|
prevTransientPos, prevTransientFlag, transientPosOffset, transientFlag,
|
|
transientPos, deltaTime, h_sbrMHDet);
|
|
|
|
/* Calulate the variables that will be used subsequently for the actual
|
|
* detection */
|
|
calculateDetectorInput(pQuotaBuffer, indexVector, tonalityDiff, sfmOrig,
|
|
sfmSbr, freqBandTable, nSfb, noEstPerFrame, move);
|
|
|
|
/* Do the actual detection using information from previous detections */
|
|
detectionWithPrediction(pQuotaBuffer, tonalityDiff, pSignBuffer, nSfb,
|
|
freqBandTable, sfmOrig, sfmSbr, detectionVectors,
|
|
h_sbrMHDet->guideScfb, guideVectors, noEstPerFrame,
|
|
transientDetStart, totNoEst, newDetectionAllowed,
|
|
pAddHarmonicsFlag, pAddHarmonicsScaleFactorBands,
|
|
pNrgVector, h_sbrMHDet->mhParams);
|
|
|
|
/* Calculate the comp vector, so that the energy can be
|
|
compensated for a sine between two QMF-bands. */
|
|
calculateCompVector(pAddHarmonicsScaleFactorBands, pQuotaBuffer, pSignBuffer,
|
|
envelopeCompensation, nSfb, freqBandTable, totNoEst,
|
|
maxComp, h_sbrMHDet->prevEnvelopeCompensation,
|
|
newDetectionAllowed);
|
|
|
|
for (est = 0; est < move; est++) {
|
|
FDKmemcpy(tonalityDiff[est], tonalityDiff[est + noEstPerFrame],
|
|
sizeof(FIXP_DBL) * MAX_FREQ_COEFFS);
|
|
FDKmemcpy(sfmOrig[est], sfmOrig[est + noEstPerFrame],
|
|
sizeof(FIXP_DBL) * MAX_FREQ_COEFFS);
|
|
FDKmemcpy(sfmSbr[est], sfmSbr[est + noEstPerFrame],
|
|
sizeof(FIXP_DBL) * MAX_FREQ_COEFFS);
|
|
}
|
|
C_ALLOC_SCRATCH_END(_scratch, FIXP_DBL,
|
|
3 * MAX_NO_OF_ESTIMATES / 2 * MAX_FREQ_COEFFS)
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Initialize an instance of the missing harmonics detector.
|
|
|
|
|
|
\return errorCode, noError if OK.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
INT FDKsbrEnc_CreateSbrMissingHarmonicsDetector(
|
|
HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, INT chan) {
|
|
HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet;
|
|
INT i;
|
|
|
|
UCHAR *detectionVectors = GetRam_Sbr_detectionVectors(chan);
|
|
UCHAR *guideVectorDetected = GetRam_Sbr_guideVectorDetected(chan);
|
|
FIXP_DBL *guideVectorDiff = GetRam_Sbr_guideVectorDiff(chan);
|
|
FIXP_DBL *guideVectorOrig = GetRam_Sbr_guideVectorOrig(chan);
|
|
|
|
FDKmemclear(hs, sizeof(SBR_MISSING_HARMONICS_DETECTOR));
|
|
|
|
hs->prevEnvelopeCompensation = GetRam_Sbr_prevEnvelopeCompensation(chan);
|
|
hs->guideScfb = GetRam_Sbr_guideScfb(chan);
|
|
|
|
if ((NULL == detectionVectors) || (NULL == guideVectorDetected) ||
|
|
(NULL == guideVectorDiff) || (NULL == guideVectorOrig) ||
|
|
(NULL == hs->prevEnvelopeCompensation) || (NULL == hs->guideScfb)) {
|
|
goto bail;
|
|
}
|
|
|
|
for (i = 0; i < MAX_NO_OF_ESTIMATES; i++) {
|
|
hs->guideVectors[i].guideVectorDiff =
|
|
guideVectorDiff + (i * MAX_FREQ_COEFFS);
|
|
hs->guideVectors[i].guideVectorOrig =
|
|
guideVectorOrig + (i * MAX_FREQ_COEFFS);
|
|
hs->detectionVectors[i] = detectionVectors + (i * MAX_FREQ_COEFFS);
|
|
hs->guideVectors[i].guideVectorDetected =
|
|
guideVectorDetected + (i * MAX_FREQ_COEFFS);
|
|
}
|
|
|
|
return 0;
|
|
|
|
bail:
|
|
hs->guideVectors[0].guideVectorDiff = guideVectorDiff;
|
|
hs->guideVectors[0].guideVectorOrig = guideVectorOrig;
|
|
hs->detectionVectors[0] = detectionVectors;
|
|
hs->guideVectors[0].guideVectorDetected = guideVectorDetected;
|
|
|
|
FDKsbrEnc_DeleteSbrMissingHarmonicsDetector(hs);
|
|
return -1;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Initialize an instance of the missing harmonics detector.
|
|
|
|
|
|
\return errorCode, noError if OK.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
INT FDKsbrEnc_InitSbrMissingHarmonicsDetector(
|
|
HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, INT sampleFreq,
|
|
INT frameSize, INT nSfb, INT qmfNoChannels, INT totNoEst, INT move,
|
|
INT noEstPerFrame, UINT sbrSyntaxFlags) {
|
|
HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet;
|
|
int i;
|
|
|
|
FDK_ASSERT(totNoEst <= MAX_NO_OF_ESTIMATES);
|
|
|
|
if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
|
|
switch (frameSize) {
|
|
case 1024:
|
|
case 512:
|
|
hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD;
|
|
hs->timeSlots = 16;
|
|
break;
|
|
case 960:
|
|
case 480:
|
|
hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD;
|
|
hs->timeSlots = 15;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
} else {
|
|
switch (frameSize) {
|
|
case 2048:
|
|
case 1024:
|
|
hs->transientPosOffset = FRAME_MIDDLE_SLOT_2048;
|
|
hs->timeSlots = NUMBER_TIME_SLOTS_2048;
|
|
break;
|
|
case 1920:
|
|
case 960:
|
|
hs->transientPosOffset = FRAME_MIDDLE_SLOT_1920;
|
|
hs->timeSlots = NUMBER_TIME_SLOTS_1920;
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
|
|
hs->mhParams = ¶msAacLd;
|
|
} else
|
|
hs->mhParams = ¶msAac;
|
|
|
|
hs->qmfNoChannels = qmfNoChannels;
|
|
hs->sampleFreq = sampleFreq;
|
|
hs->nSfb = nSfb;
|
|
|
|
hs->totNoEst = totNoEst;
|
|
hs->move = move;
|
|
hs->noEstPerFrame = noEstPerFrame;
|
|
|
|
for (i = 0; i < totNoEst; i++) {
|
|
FDKmemclear(hs->guideVectors[i].guideVectorDiff,
|
|
sizeof(FIXP_DBL) * MAX_FREQ_COEFFS);
|
|
FDKmemclear(hs->guideVectors[i].guideVectorOrig,
|
|
sizeof(FIXP_DBL) * MAX_FREQ_COEFFS);
|
|
FDKmemclear(hs->detectionVectors[i], sizeof(UCHAR) * MAX_FREQ_COEFFS);
|
|
FDKmemclear(hs->guideVectors[i].guideVectorDetected,
|
|
sizeof(UCHAR) * MAX_FREQ_COEFFS);
|
|
}
|
|
|
|
// for(i=0; i<totNoEst/2; i++) {
|
|
for (i = 0; i < MAX_NO_OF_ESTIMATES / 2; i++) {
|
|
FDKmemclear(hs->tonalityDiff[i], sizeof(FIXP_DBL) * MAX_FREQ_COEFFS);
|
|
FDKmemclear(hs->sfmOrig[i], sizeof(FIXP_DBL) * MAX_FREQ_COEFFS);
|
|
FDKmemclear(hs->sfmSbr[i], sizeof(FIXP_DBL) * MAX_FREQ_COEFFS);
|
|
}
|
|
|
|
FDKmemclear(hs->prevEnvelopeCompensation, sizeof(UCHAR) * MAX_FREQ_COEFFS);
|
|
FDKmemclear(hs->guideScfb, sizeof(UCHAR) * MAX_FREQ_COEFFS);
|
|
|
|
hs->previousTransientFlag = 0;
|
|
hs->previousTransientFrame = 0;
|
|
hs->previousTransientPos = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Deletes an instance of the missing harmonics detector.
|
|
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
void FDKsbrEnc_DeleteSbrMissingHarmonicsDetector(
|
|
HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet) {
|
|
if (hSbrMHDet) {
|
|
HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet;
|
|
|
|
FreeRam_Sbr_detectionVectors(&hs->detectionVectors[0]);
|
|
FreeRam_Sbr_guideVectorDetected(&hs->guideVectors[0].guideVectorDetected);
|
|
FreeRam_Sbr_guideVectorDiff(&hs->guideVectors[0].guideVectorDiff);
|
|
FreeRam_Sbr_guideVectorOrig(&hs->guideVectors[0].guideVectorOrig);
|
|
FreeRam_Sbr_prevEnvelopeCompensation(&hs->prevEnvelopeCompensation);
|
|
FreeRam_Sbr_guideScfb(&hs->guideScfb);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Resets an instance of the missing harmonics detector.
|
|
|
|
|
|
\return error code, noError if OK.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
INT FDKsbrEnc_ResetSbrMissingHarmonicsDetector(
|
|
HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMissingHarmonicsDetector,
|
|
INT nSfb) {
|
|
int i;
|
|
FIXP_DBL tempGuide[MAX_FREQ_COEFFS];
|
|
UCHAR tempGuideInt[MAX_FREQ_COEFFS];
|
|
INT nSfbPrev;
|
|
|
|
nSfbPrev = hSbrMissingHarmonicsDetector->nSfb;
|
|
hSbrMissingHarmonicsDetector->nSfb = nSfb;
|
|
|
|
FDKmemcpy(tempGuideInt, hSbrMissingHarmonicsDetector->guideScfb,
|
|
nSfbPrev * sizeof(UCHAR));
|
|
|
|
if (nSfb > nSfbPrev) {
|
|
for (i = 0; i < (nSfb - nSfbPrev); i++) {
|
|
hSbrMissingHarmonicsDetector->guideScfb[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < nSfbPrev; i++) {
|
|
hSbrMissingHarmonicsDetector->guideScfb[i + (nSfb - nSfbPrev)] =
|
|
tempGuideInt[i];
|
|
}
|
|
} else {
|
|
for (i = 0; i < nSfb; i++) {
|
|
hSbrMissingHarmonicsDetector->guideScfb[i] =
|
|
tempGuideInt[i + (nSfbPrev - nSfb)];
|
|
}
|
|
}
|
|
|
|
FDKmemcpy(tempGuide,
|
|
hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff,
|
|
nSfbPrev * sizeof(FIXP_DBL));
|
|
|
|
if (nSfb > nSfbPrev) {
|
|
for (i = 0; i < (nSfb - nSfbPrev); i++) {
|
|
hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] =
|
|
FL2FXCONST_DBL(0.0f);
|
|
}
|
|
|
|
for (i = 0; i < nSfbPrev; i++) {
|
|
hSbrMissingHarmonicsDetector->guideVectors[0]
|
|
.guideVectorDiff[i + (nSfb - nSfbPrev)] = tempGuide[i];
|
|
}
|
|
} else {
|
|
for (i = 0; i < nSfb; i++) {
|
|
hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] =
|
|
tempGuide[i + (nSfbPrev - nSfb)];
|
|
}
|
|
}
|
|
|
|
FDKmemcpy(tempGuide,
|
|
hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig,
|
|
nSfbPrev * sizeof(FIXP_DBL));
|
|
|
|
if (nSfb > nSfbPrev) {
|
|
for (i = 0; i < (nSfb - nSfbPrev); i++) {
|
|
hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] =
|
|
FL2FXCONST_DBL(0.0f);
|
|
}
|
|
|
|
for (i = 0; i < nSfbPrev; i++) {
|
|
hSbrMissingHarmonicsDetector->guideVectors[0]
|
|
.guideVectorOrig[i + (nSfb - nSfbPrev)] = tempGuide[i];
|
|
}
|
|
} else {
|
|
for (i = 0; i < nSfb; i++) {
|
|
hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] =
|
|
tempGuide[i + (nSfbPrev - nSfb)];
|
|
}
|
|
}
|
|
|
|
FDKmemcpy(tempGuideInt,
|
|
hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected,
|
|
nSfbPrev * sizeof(UCHAR));
|
|
|
|
if (nSfb > nSfbPrev) {
|
|
for (i = 0; i < (nSfb - nSfbPrev); i++) {
|
|
hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < nSfbPrev; i++) {
|
|
hSbrMissingHarmonicsDetector->guideVectors[0]
|
|
.guideVectorDetected[i + (nSfb - nSfbPrev)] = tempGuideInt[i];
|
|
}
|
|
} else {
|
|
for (i = 0; i < nSfb; i++) {
|
|
hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] =
|
|
tempGuideInt[i + (nSfbPrev - nSfb)];
|
|
}
|
|
}
|
|
|
|
FDKmemcpy(tempGuideInt,
|
|
hSbrMissingHarmonicsDetector->prevEnvelopeCompensation,
|
|
nSfbPrev * sizeof(UCHAR));
|
|
|
|
if (nSfb > nSfbPrev) {
|
|
for (i = 0; i < (nSfb - nSfbPrev); i++) {
|
|
hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < nSfbPrev; i++) {
|
|
hSbrMissingHarmonicsDetector
|
|
->prevEnvelopeCompensation[i + (nSfb - nSfbPrev)] = tempGuideInt[i];
|
|
}
|
|
} else {
|
|
for (i = 0; i < nSfb; i++) {
|
|
hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] =
|
|
tempGuideInt[i + (nSfbPrev - nSfb)];
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|