mirror of https://github.com/mstorsjo/fdk-aac.git
611 lines
23 KiB
C++
611 lines
23 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 "invf_est.h"
|
|
#include "sbr_misc.h"
|
|
|
|
#include "genericStds.h"
|
|
|
|
#define MAX_NUM_REGIONS 10
|
|
#define SCALE_FAC_QUO 512.0f
|
|
#define SCALE_FAC_NRG 256.0f
|
|
|
|
#ifndef min
|
|
#define min(a, b) (a < b ? a : b)
|
|
#endif
|
|
|
|
#ifndef max
|
|
#define max(a, b) (a > b ? a : b)
|
|
#endif
|
|
|
|
static const FIXP_DBL quantStepsSbr[4] = {
|
|
0x00400000, 0x02800000, 0x03800000,
|
|
0x04c00000}; /* table scaled with SCALE_FAC_QUO */
|
|
static const FIXP_DBL quantStepsOrig[4] = {
|
|
0x00000000, 0x00c00000, 0x01c00000,
|
|
0x02800000}; /* table scaled with SCALE_FAC_QUO */
|
|
static const FIXP_DBL nrgBorders[4] = {
|
|
0x0c800000, 0x0f000000, 0x11800000,
|
|
0x14000000}; /* table scaled with SCALE_FAC_NRG */
|
|
|
|
static const DETECTOR_PARAMETERS detectorParamsAAC = {
|
|
quantStepsSbr,
|
|
quantStepsOrig,
|
|
nrgBorders,
|
|
4, /* Number of borders SBR. */
|
|
4, /* Number of borders orig. */
|
|
4, /* Number of borders Nrg. */
|
|
{
|
|
/* Region space. */
|
|
{INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* regionSbr */
|
|
{INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF} /* | */
|
|
}, /*------------------------ regionOrig ---------------------------------*/
|
|
{
|
|
/* Region space transient. */
|
|
{INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* regionSbr */
|
|
{INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF} /* | */
|
|
}, /*------------------------ regionOrig ---------------------------------*/
|
|
{-4, -3, -2, -1,
|
|
0} /* Reduction factor of the inverse filtering for low energies.*/
|
|
};
|
|
|
|
static const FIXP_DBL hysteresis =
|
|
0x00400000; /* Delta value for hysteresis. scaled with SCALE_FAC_QUO */
|
|
|
|
/*
|
|
* AAC+SBR PARAMETERS for Speech
|
|
*********************************/
|
|
static const DETECTOR_PARAMETERS detectorParamsAACSpeech = {
|
|
quantStepsSbr,
|
|
quantStepsOrig,
|
|
nrgBorders,
|
|
4, /* Number of borders SBR. */
|
|
4, /* Number of borders orig. */
|
|
4, /* Number of borders Nrg. */
|
|
{
|
|
/* Region space. */
|
|
{INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* regionSbr */
|
|
{INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF} /* | */
|
|
}, /*------------------------ regionOrig ---------------------------------*/
|
|
{
|
|
/* Region space transient. */
|
|
{INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* regionSbr */
|
|
{INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF}, /* | */
|
|
{INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF,
|
|
INVF_OFF} /* | */
|
|
}, /*------------------------ regionOrig ---------------------------------*/
|
|
{-4, -3, -2, -1,
|
|
0} /* Reduction factor of the inverse filtering for low energies.*/
|
|
};
|
|
|
|
/*
|
|
* Smoothing filters.
|
|
************************/
|
|
typedef const FIXP_DBL FIR_FILTER[5];
|
|
|
|
static const FIR_FILTER fir_0 = {0x7fffffff, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000};
|
|
static const FIR_FILTER fir_1 = {0x2aaaaa80, 0x555554ff, 0x00000000, 0x00000000,
|
|
0x00000000};
|
|
static const FIR_FILTER fir_2 = {0x10000000, 0x30000000, 0x40000000, 0x00000000,
|
|
0x00000000};
|
|
static const FIR_FILTER fir_3 = {0x077f80e8, 0x199999a0, 0x2bb3b240, 0x33333340,
|
|
0x00000000};
|
|
static const FIR_FILTER fir_4 = {0x04130598, 0x0ebdb000, 0x1becfa60, 0x2697a4c0,
|
|
0x2aaaaa80};
|
|
|
|
static const FIR_FILTER *const fir_table[5] = {&fir_0, &fir_1, &fir_2, &fir_3,
|
|
&fir_4};
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Calculates the values used for the detector.
|
|
|
|
|
|
\return none
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static void calculateDetectorValues(
|
|
FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the tonality values of the
|
|
original. */
|
|
SCHAR *indexVector, /*!< Index vector to obtain the patched data. */
|
|
FIXP_DBL *nrgVector, /*!< Energy vector. */
|
|
DETECTOR_VALUES *detectorValues, /*!< pointer to DETECTOR_VALUES struct. */
|
|
INT startChannel, /*!< Start channel. */
|
|
INT stopChannel, /*!< Stop channel. */
|
|
INT startIndex, /*!< Start index. */
|
|
INT stopIndex, /*!< Stop index. */
|
|
INT numberOfStrongest /*!< The number of sorted tonal components to be
|
|
considered. */
|
|
) {
|
|
INT i, temp, j;
|
|
|
|
const FIXP_DBL *filter = *fir_table[INVF_SMOOTHING_LENGTH];
|
|
FIXP_DBL origQuotaMeanStrongest, sbrQuotaMeanStrongest;
|
|
FIXP_DBL origQuota, sbrQuota;
|
|
FIXP_DBL invIndex, invChannel, invTemp;
|
|
FIXP_DBL quotaVecOrig[64], quotaVecSbr[64];
|
|
|
|
FDKmemclear(quotaVecOrig, 64 * sizeof(FIXP_DBL));
|
|
FDKmemclear(quotaVecSbr, 64 * sizeof(FIXP_DBL));
|
|
|
|
invIndex = GetInvInt(stopIndex - startIndex);
|
|
invChannel = GetInvInt(stopChannel - startChannel);
|
|
|
|
/*
|
|
Calculate the mean value, over the current time segment, for the original,
|
|
the HFR and the difference, over all channels in the current frequency range.
|
|
NOTE: the averaging is done on the values quota/(1 - quota + RELAXATION).
|
|
*/
|
|
|
|
/* The original, the sbr signal and the total energy */
|
|
detectorValues->avgNrg = FL2FXCONST_DBL(0.0f);
|
|
for (j = startIndex; j < stopIndex; j++) {
|
|
for (i = startChannel; i < stopChannel; i++) {
|
|
quotaVecOrig[i] += fMult(quotaMatrixOrig[j][i], invIndex);
|
|
|
|
if (indexVector[i] != -1)
|
|
quotaVecSbr[i] += fMult(quotaMatrixOrig[j][indexVector[i]], invIndex);
|
|
}
|
|
detectorValues->avgNrg += fMult(nrgVector[j], invIndex);
|
|
}
|
|
|
|
/*
|
|
Calculate the mean value, over the current frequency range, for the original,
|
|
the HFR and the difference. Also calculate the same mean values for the three
|
|
vectors, but only includeing the x strongest copmponents.
|
|
*/
|
|
|
|
origQuota = FL2FXCONST_DBL(0.0f);
|
|
sbrQuota = FL2FXCONST_DBL(0.0f);
|
|
for (i = startChannel; i < stopChannel; i++) {
|
|
origQuota += fMultDiv2(quotaVecOrig[i], invChannel);
|
|
sbrQuota += fMultDiv2(quotaVecSbr[i], invChannel);
|
|
}
|
|
|
|
/*
|
|
Calculate the mean value for the x strongest components
|
|
*/
|
|
FDKsbrEnc_Shellsort_fract(quotaVecOrig + startChannel,
|
|
stopChannel - startChannel);
|
|
FDKsbrEnc_Shellsort_fract(quotaVecSbr + startChannel,
|
|
stopChannel - startChannel);
|
|
|
|
origQuotaMeanStrongest = FL2FXCONST_DBL(0.0f);
|
|
sbrQuotaMeanStrongest = FL2FXCONST_DBL(0.0f);
|
|
|
|
temp = min(stopChannel - startChannel, numberOfStrongest);
|
|
invTemp = GetInvInt(temp);
|
|
|
|
for (i = 0; i < temp; i++) {
|
|
origQuotaMeanStrongest +=
|
|
fMultDiv2(quotaVecOrig[i + stopChannel - temp], invTemp);
|
|
sbrQuotaMeanStrongest +=
|
|
fMultDiv2(quotaVecSbr[i + stopChannel - temp], invTemp);
|
|
}
|
|
|
|
/*
|
|
The value for the strongest component
|
|
*/
|
|
detectorValues->origQuotaMax = quotaVecOrig[stopChannel - 1];
|
|
detectorValues->sbrQuotaMax = quotaVecSbr[stopChannel - 1];
|
|
|
|
/*
|
|
Buffer values
|
|
*/
|
|
FDKmemmove(detectorValues->origQuotaMean, detectorValues->origQuotaMean + 1,
|
|
INVF_SMOOTHING_LENGTH * sizeof(FIXP_DBL));
|
|
FDKmemmove(detectorValues->sbrQuotaMean, detectorValues->sbrQuotaMean + 1,
|
|
INVF_SMOOTHING_LENGTH * sizeof(FIXP_DBL));
|
|
FDKmemmove(detectorValues->origQuotaMeanStrongest,
|
|
detectorValues->origQuotaMeanStrongest + 1,
|
|
INVF_SMOOTHING_LENGTH * sizeof(FIXP_DBL));
|
|
FDKmemmove(detectorValues->sbrQuotaMeanStrongest,
|
|
detectorValues->sbrQuotaMeanStrongest + 1,
|
|
INVF_SMOOTHING_LENGTH * sizeof(FIXP_DBL));
|
|
|
|
detectorValues->origQuotaMean[INVF_SMOOTHING_LENGTH] = origQuota << 1;
|
|
detectorValues->sbrQuotaMean[INVF_SMOOTHING_LENGTH] = sbrQuota << 1;
|
|
detectorValues->origQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] =
|
|
origQuotaMeanStrongest << 1;
|
|
detectorValues->sbrQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] =
|
|
sbrQuotaMeanStrongest << 1;
|
|
|
|
/*
|
|
Filter values
|
|
*/
|
|
detectorValues->origQuotaMeanFilt = FL2FXCONST_DBL(0.0f);
|
|
detectorValues->sbrQuotaMeanFilt = FL2FXCONST_DBL(0.0f);
|
|
detectorValues->origQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f);
|
|
detectorValues->sbrQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f);
|
|
|
|
for (i = 0; i < INVF_SMOOTHING_LENGTH + 1; i++) {
|
|
detectorValues->origQuotaMeanFilt +=
|
|
fMult(detectorValues->origQuotaMean[i], filter[i]);
|
|
detectorValues->sbrQuotaMeanFilt +=
|
|
fMult(detectorValues->sbrQuotaMean[i], filter[i]);
|
|
detectorValues->origQuotaMeanStrongestFilt +=
|
|
fMult(detectorValues->origQuotaMeanStrongest[i], filter[i]);
|
|
detectorValues->sbrQuotaMeanStrongestFilt +=
|
|
fMult(detectorValues->sbrQuotaMeanStrongest[i], filter[i]);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Returns the region in which the input value belongs.
|
|
|
|
|
|
|
|
\return region.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static INT findRegion(
|
|
FIXP_DBL currVal, /*!< The current value. */
|
|
const FIXP_DBL *borders, /*!< The border of the regions. */
|
|
const INT numBorders /*!< The number of borders. */
|
|
) {
|
|
INT i;
|
|
|
|
if (currVal < borders[0]) {
|
|
return 0;
|
|
}
|
|
|
|
for (i = 1; i < numBorders; i++) {
|
|
if (currVal >= borders[i - 1] && currVal < borders[i]) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
if (currVal >= borders[numBorders - 1]) {
|
|
return numBorders;
|
|
}
|
|
|
|
return 0; /* We never get here, it's just to avoid compiler warnings.*/
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Makes a clever decision based on the quota vector.
|
|
|
|
|
|
\return decision on which invf mode to use
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
static INVF_MODE decisionAlgorithm(
|
|
const DETECTOR_PARAMETERS
|
|
*detectorParams, /*!< Struct with the detector parameters. */
|
|
DETECTOR_VALUES *detectorValues, /*!< Struct with the detector values. */
|
|
INT transientFlag, /*!< Flag indicating if there is a transient present.*/
|
|
INT *prevRegionSbr, /*!< The previous region in which the Sbr value was. */
|
|
INT *prevRegionOrig /*!< The previous region in which the Orig value was. */
|
|
) {
|
|
INT invFiltLevel, regionSbr, regionOrig, regionNrg;
|
|
|
|
/*
|
|
Current thresholds.
|
|
*/
|
|
const INT numRegionsSbr = detectorParams->numRegionsSbr;
|
|
const INT numRegionsOrig = detectorParams->numRegionsOrig;
|
|
const INT numRegionsNrg = detectorParams->numRegionsNrg;
|
|
|
|
FIXP_DBL quantStepsSbrTmp[MAX_NUM_REGIONS];
|
|
FIXP_DBL quantStepsOrigTmp[MAX_NUM_REGIONS];
|
|
|
|
/*
|
|
Current detector values.
|
|
*/
|
|
FIXP_DBL origQuotaMeanFilt;
|
|
FIXP_DBL sbrQuotaMeanFilt;
|
|
FIXP_DBL nrg;
|
|
|
|
/* 0.375 = 3.0 / 8.0; 0.31143075889 = log2(RELAXATION)/64.0; 0.625 =
|
|
* log(16)/64.0; 0.6875 = 44/64.0 */
|
|
origQuotaMeanFilt =
|
|
(fMultDiv2(FL2FXCONST_DBL(2.f * 0.375f),
|
|
(FIXP_DBL)(CalcLdData(max(detectorValues->origQuotaMeanFilt,
|
|
(FIXP_DBL)1)) +
|
|
FL2FXCONST_DBL(0.31143075889f))))
|
|
<< 0; /* scaled by 1/2^9 */
|
|
sbrQuotaMeanFilt =
|
|
(fMultDiv2(FL2FXCONST_DBL(2.f * 0.375f),
|
|
(FIXP_DBL)(CalcLdData(max(detectorValues->sbrQuotaMeanFilt,
|
|
(FIXP_DBL)1)) +
|
|
FL2FXCONST_DBL(0.31143075889f))))
|
|
<< 0; /* scaled by 1/2^9 */
|
|
/* If energy is zero then we will get different results for different word
|
|
* lengths. */
|
|
nrg =
|
|
(fMultDiv2(FL2FXCONST_DBL(2.f * 0.375f),
|
|
(FIXP_DBL)(CalcLdData(detectorValues->avgNrg + (FIXP_DBL)1) +
|
|
FL2FXCONST_DBL(0.0625f) + FL2FXCONST_DBL(0.6875f))))
|
|
<< 0; /* scaled by 1/2^8; 2^44 -> qmf energy scale */
|
|
|
|
FDKmemcpy(quantStepsSbrTmp, detectorParams->quantStepsSbr,
|
|
numRegionsSbr * sizeof(FIXP_DBL));
|
|
FDKmemcpy(quantStepsOrigTmp, detectorParams->quantStepsOrig,
|
|
numRegionsOrig * sizeof(FIXP_DBL));
|
|
|
|
if (*prevRegionSbr < numRegionsSbr)
|
|
quantStepsSbrTmp[*prevRegionSbr] =
|
|
detectorParams->quantStepsSbr[*prevRegionSbr] + hysteresis;
|
|
if (*prevRegionSbr > 0)
|
|
quantStepsSbrTmp[*prevRegionSbr - 1] =
|
|
detectorParams->quantStepsSbr[*prevRegionSbr - 1] - hysteresis;
|
|
|
|
if (*prevRegionOrig < numRegionsOrig)
|
|
quantStepsOrigTmp[*prevRegionOrig] =
|
|
detectorParams->quantStepsOrig[*prevRegionOrig] + hysteresis;
|
|
if (*prevRegionOrig > 0)
|
|
quantStepsOrigTmp[*prevRegionOrig - 1] =
|
|
detectorParams->quantStepsOrig[*prevRegionOrig - 1] - hysteresis;
|
|
|
|
regionSbr = findRegion(sbrQuotaMeanFilt, quantStepsSbrTmp, numRegionsSbr);
|
|
regionOrig = findRegion(origQuotaMeanFilt, quantStepsOrigTmp, numRegionsOrig);
|
|
regionNrg = findRegion(nrg, detectorParams->nrgBorders, numRegionsNrg);
|
|
|
|
*prevRegionSbr = regionSbr;
|
|
*prevRegionOrig = regionOrig;
|
|
|
|
/* Use different settings if a transient is present*/
|
|
invFiltLevel =
|
|
(transientFlag == 1)
|
|
? detectorParams->regionSpaceTransient[regionSbr][regionOrig]
|
|
: detectorParams->regionSpace[regionSbr][regionOrig];
|
|
|
|
/* Compensate for low energy.*/
|
|
invFiltLevel =
|
|
max(invFiltLevel + detectorParams->EnergyCompFactor[regionNrg], 0);
|
|
|
|
return (INVF_MODE)(invFiltLevel);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Estiamtion of the inverse filtering level required
|
|
in the decoder.
|
|
|
|
A second order LPC is calculated for every filterbank channel, using
|
|
the covariance method. THe ratio between the energy of the predicted
|
|
signal and the energy of the non-predictable signal is calcualted.
|
|
|
|
\return none.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
void FDKsbrEnc_qmfInverseFilteringDetector(
|
|
HANDLE_SBR_INV_FILT_EST
|
|
hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */
|
|
FIXP_DBL **quotaMatrix, /*!< The matrix holding the tonality values of the
|
|
original. */
|
|
FIXP_DBL *nrgVector, /*!< The energy vector. */
|
|
SCHAR *indexVector, /*!< Index vector to obtain the patched data. */
|
|
INT startIndex, /*!< Start index. */
|
|
INT stopIndex, /*!< Stop index. */
|
|
INT transientFlag, /*!< Flag indicating if a transient is present or not.*/
|
|
INVF_MODE *infVec /*!< Vector holding the inverse filtering levels. */
|
|
) {
|
|
INT band;
|
|
|
|
/*
|
|
* Do the inverse filtering level estimation.
|
|
*****************************************************/
|
|
for (band = 0; band < hInvFilt->noDetectorBands; band++) {
|
|
INT startChannel = hInvFilt->freqBandTableInvFilt[band];
|
|
INT stopChannel = hInvFilt->freqBandTableInvFilt[band + 1];
|
|
|
|
calculateDetectorValues(quotaMatrix, indexVector, nrgVector,
|
|
&hInvFilt->detectorValues[band], startChannel,
|
|
stopChannel, startIndex, stopIndex,
|
|
hInvFilt->numberOfStrongest);
|
|
|
|
infVec[band] = decisionAlgorithm(
|
|
hInvFilt->detectorParams, &hInvFilt->detectorValues[band],
|
|
transientFlag, &hInvFilt->prevRegionSbr[band],
|
|
&hInvFilt->prevRegionOrig[band]);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief Initialize an instance of the inverse filtering level estimator.
|
|
|
|
|
|
\return errorCode, noError if successful.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
INT FDKsbrEnc_initInvFiltDetector(
|
|
HANDLE_SBR_INV_FILT_EST
|
|
hInvFilt, /*!< Pointer to a handle to the SBR_INV_FILT_EST struct. */
|
|
INT *freqBandTableDetector, /*!< Frequency band table for the inverse
|
|
filtering. */
|
|
INT numDetectorBands, /*!< Number of inverse filtering bands. */
|
|
UINT
|
|
useSpeechConfig /*!< Flag: adapt tuning parameters according to speech*/
|
|
) {
|
|
INT i;
|
|
|
|
FDKmemclear(hInvFilt, sizeof(SBR_INV_FILT_EST));
|
|
|
|
hInvFilt->detectorParams =
|
|
(useSpeechConfig) ? &detectorParamsAACSpeech : &detectorParamsAAC;
|
|
|
|
hInvFilt->noDetectorBandsMax = numDetectorBands;
|
|
|
|
/*
|
|
Memory initialisation
|
|
*/
|
|
for (i = 0; i < hInvFilt->noDetectorBandsMax; i++) {
|
|
FDKmemclear(&hInvFilt->detectorValues[i], sizeof(DETECTOR_VALUES));
|
|
hInvFilt->prevInvfMode[i] = INVF_OFF;
|
|
hInvFilt->prevRegionOrig[i] = 0;
|
|
hInvFilt->prevRegionSbr[i] = 0;
|
|
}
|
|
|
|
/*
|
|
Reset the inverse fltering detector.
|
|
*/
|
|
FDKsbrEnc_resetInvFiltDetector(hInvFilt, freqBandTableDetector,
|
|
hInvFilt->noDetectorBandsMax);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
/*!
|
|
\brief resets sbr inverse filtering structure.
|
|
|
|
|
|
|
|
\return errorCode, noError if successful.
|
|
|
|
*/
|
|
/**************************************************************************/
|
|
INT FDKsbrEnc_resetInvFiltDetector(
|
|
HANDLE_SBR_INV_FILT_EST
|
|
hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */
|
|
INT *freqBandTableDetector, /*!< Frequency band table for the inverse
|
|
filtering. */
|
|
INT numDetectorBands) /*!< Number of inverse filtering bands. */
|
|
{
|
|
hInvFilt->numberOfStrongest = 1;
|
|
FDKmemcpy(hInvFilt->freqBandTableInvFilt, freqBandTableDetector,
|
|
(numDetectorBands + 1) * sizeof(INT));
|
|
hInvFilt->noDetectorBands = numDetectorBands;
|
|
|
|
return (0);
|
|
}
|