2018-02-26 20:17:00 +01:00
|
|
|
/* -----------------------------------------------------------------------------
|
2012-07-11 19:15:24 +02:00
|
|
|
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
|
|
|
|
Forschung e.V. All rights reserved.
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
1. INTRODUCTION
|
2018-02-26 20:17:00 +01:00
|
|
|
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.
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
2. COPYRIGHT LICENSE
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
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:
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
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.
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
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
|
2012-07-11 19:15:24 +02:00
|
|
|
modifications thereto to recipients of copies in binary form.
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
The name of Fraunhofer may not be used to endorse or promote products derived
|
|
|
|
from this library without prior written permission.
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
You may not charge copyright license fees for anyone to use, copy or distribute
|
|
|
|
the FDK AAC Codec software or your modifications thereto.
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
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."
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
3. NO PATENT LICENSE
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
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.
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
You may use this FDK AAC Codec software or modifications thereto only for
|
|
|
|
purposes that are authorized by appropriate patent licenses.
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
4. DISCLAIMER
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
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.
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
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
|
2018-02-26 20:17:00 +01:00
|
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**************************** SBR encoder library ******************************
|
|
|
|
|
|
|
|
Author(s): Tobias Chalupka
|
|
|
|
|
|
|
|
Description: SBR encoder transient detector
|
|
|
|
|
|
|
|
*******************************************************************************/
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
#include "tran_det.h"
|
|
|
|
|
|
|
|
#include "fram_gen.h"
|
2018-02-26 20:17:00 +01:00
|
|
|
#include "sbrenc_ram.h"
|
2012-07-11 19:15:24 +02:00
|
|
|
#include "sbr_misc.h"
|
|
|
|
|
|
|
|
#include "genericStds.h"
|
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
#define NORM_QMF_ENERGY 9.31322574615479E-10 /* 2^-30 */
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* static FIXP_DBL ABS_THRES = fixMax( FL2FXCONST_DBL(1.28e5 *
|
|
|
|
* NORM_QMF_ENERGY), (FIXP_DBL)1) Minimum threshold for detecting changes */
|
2012-07-11 19:15:24 +02:00
|
|
|
#define ABS_THRES ((FIXP_DBL)16)
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Functionname: spectralChange
|
|
|
|
*******************************************************************************
|
|
|
|
\brief Calculates a measure for the spectral change within the frame
|
|
|
|
|
|
|
|
The function says how good it would be to split the frame at the given border
|
|
|
|
position into 2 envelopes.
|
|
|
|
|
|
|
|
The return value delta_sum is scaled with the factor 1/64
|
|
|
|
|
|
|
|
\return calculated value
|
|
|
|
*******************************************************************************/
|
2018-02-26 20:17:00 +01:00
|
|
|
#define NRG_SHIFT 3 /* for energy summation */
|
|
|
|
|
|
|
|
static FIXP_DBL spectralChange(
|
|
|
|
FIXP_DBL Energies[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS],
|
|
|
|
INT *scaleEnergies, FIXP_DBL EnergyTotal, INT nSfb, INT start, INT border,
|
|
|
|
INT YBufferWriteOffset, INT stop, INT *result_e) {
|
|
|
|
INT i, j;
|
|
|
|
INT len1, len2;
|
|
|
|
SCHAR energies_e_diff[NUMBER_TIME_SLOTS_2304], energies_e, energyTotal_e = 19,
|
|
|
|
energies_e_add;
|
2016-04-08 19:52:42 +02:00
|
|
|
SCHAR prevEnergies_e_diff, newEnergies_e_diff;
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL tmp0, tmp1;
|
2016-04-08 19:52:42 +02:00
|
|
|
FIXP_DBL delta, delta_sum;
|
|
|
|
INT accu_e, tmp_e;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
delta_sum = FL2FXCONST_DBL(0.0f);
|
|
|
|
*result_e = 0;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
len1 = border - start;
|
|
|
|
len2 = stop - border;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
/* prefer borders near the middle of the frame */
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL pos_weight;
|
|
|
|
pos_weight = FL2FXCONST_DBL(0.5f) - (len1 * GetInvInt(len1 + len2));
|
|
|
|
pos_weight = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL -
|
|
|
|
(fMult(pos_weight, pos_weight) << 2);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
/*** Calc scaling for energies ***/
|
|
|
|
FDK_ASSERT(scaleEnergies[0] >= 0);
|
|
|
|
FDK_ASSERT(scaleEnergies[1] >= 0);
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
energies_e = 19 - fMin(scaleEnergies[0], scaleEnergies[1]);
|
2016-04-08 19:52:42 +02:00
|
|
|
|
|
|
|
/* limit shift for energy accumulation, energies_e can be -10 min. */
|
|
|
|
if (energies_e < -10) {
|
2018-02-26 20:17:00 +01:00
|
|
|
energies_e_add = -10 - energies_e;
|
|
|
|
energies_e = -10;
|
2016-04-08 19:52:42 +02:00
|
|
|
} else if (energies_e > 17) {
|
2018-02-26 20:17:00 +01:00
|
|
|
energies_e_add = energies_e - 17;
|
|
|
|
energies_e = 17;
|
2016-04-08 19:52:42 +02:00
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
energies_e_add = 0;
|
2016-04-08 19:52:42 +02:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* compensate scaling differences between scaleEnergies[0] and
|
|
|
|
* scaleEnergies[1] */
|
|
|
|
prevEnergies_e_diff = scaleEnergies[0] -
|
|
|
|
fMin(scaleEnergies[0], scaleEnergies[1]) +
|
|
|
|
energies_e_add + NRG_SHIFT;
|
|
|
|
newEnergies_e_diff = scaleEnergies[1] -
|
|
|
|
fMin(scaleEnergies[0], scaleEnergies[1]) +
|
|
|
|
energies_e_add + NRG_SHIFT;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
prevEnergies_e_diff = fMin(prevEnergies_e_diff, DFRACT_BITS - 1);
|
|
|
|
newEnergies_e_diff = fMin(newEnergies_e_diff, DFRACT_BITS - 1);
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (i = start; i < YBufferWriteOffset; i++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
energies_e_diff[i] = prevEnergies_e_diff;
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
for (i = YBufferWriteOffset; i < stop; i++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
energies_e_diff[i] = newEnergies_e_diff;
|
|
|
|
}
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
/* Sum up energies of all QMF-timeslots for both halfs */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_ASSERT(len1 <= 8); /* otherwise an overflow is possible */
|
|
|
|
FDK_ASSERT(len2 <= 8); /* otherwise an overflow is possible */
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (j = 0; j < nSfb; j++) {
|
|
|
|
FIXP_DBL accu1 = FL2FXCONST_DBL(0.f);
|
|
|
|
FIXP_DBL accu2 = FL2FXCONST_DBL(0.f);
|
|
|
|
accu_e = energies_e + 3;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
/* Sum up energies in first half */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (i = start; i < border; i++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
accu1 += scaleValue(Energies[i][j], -energies_e_diff[i]);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Sum up energies in second half */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (i = border; i < stop; i++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
accu2 += scaleValue(Energies[i][j], -energies_e_diff[i]);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Ensure certain energy to prevent division by zero and to prevent
|
|
|
|
* splitting for very low levels */
|
|
|
|
accu1 = fMax(accu1, (FIXP_DBL)len1);
|
|
|
|
accu2 = fMax(accu2, (FIXP_DBL)len2);
|
|
|
|
|
|
|
|
/* Energy change in current band */
|
|
|
|
#define LN2 FL2FXCONST_DBL(0.6931471806f) /* ln(2) */
|
2016-04-08 19:52:42 +02:00
|
|
|
tmp0 = fLog2(accu2, accu_e) - fLog2(accu1, accu_e);
|
|
|
|
tmp1 = fLog2((FIXP_DBL)len1, 31) - fLog2((FIXP_DBL)len2, 31);
|
|
|
|
delta = fMult(LN2, (tmp0 + tmp1));
|
2018-02-26 20:17:00 +01:00
|
|
|
delta = (FIXP_DBL)fAbs(delta);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
/* Weighting with amplitude ratio of this band */
|
2018-02-26 20:17:00 +01:00
|
|
|
accu_e++; /* scale at least one bit due to (accu1+accu2) */
|
|
|
|
accu1 >>= 1;
|
|
|
|
accu2 >>= 1;
|
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
if (accu_e & 1) {
|
2018-02-26 20:17:00 +01:00
|
|
|
accu_e++; /* for a defined square result exponent, the exponent has to be
|
|
|
|
even */
|
|
|
|
accu1 >>= 1;
|
|
|
|
accu2 >>= 1;
|
2016-04-08 19:52:42 +02:00
|
|
|
}
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
delta_sum += fMult(sqrtFixp(accu1 + accu2), delta);
|
|
|
|
*result_e = ((accu_e >> 1) + LD_DATA_SHIFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (energyTotal_e & 1) {
|
|
|
|
energyTotal_e += 1; /* for a defined square result exponent, the exponent
|
|
|
|
has to be even */
|
|
|
|
EnergyTotal >>= 1;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
delta_sum = fMult(delta_sum, invSqrtNorm2(EnergyTotal, &tmp_e));
|
2018-02-26 20:17:00 +01:00
|
|
|
*result_e = *result_e + (tmp_e - (energyTotal_e >> 1));
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2012-07-11 19:15:24 +02:00
|
|
|
return fMult(delta_sum, pos_weight);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Functionname: addLowbandEnergies
|
|
|
|
*******************************************************************************
|
|
|
|
\brief Calculates total lowband energy
|
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
The input values Energies[0] (low-band) are scaled by the factor
|
|
|
|
2^(14-*scaleEnergies[0])
|
|
|
|
The input values Energies[1] (high-band) are scaled by the factor
|
|
|
|
2^(14-*scaleEnergies[1])
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
\return total energy in the lowband, scaled by the factor 2^19
|
2012-07-11 19:15:24 +02:00
|
|
|
*******************************************************************************/
|
2018-02-26 20:17:00 +01:00
|
|
|
static FIXP_DBL addLowbandEnergies(FIXP_DBL **Energies, int *scaleEnergies,
|
|
|
|
int YBufferWriteOffset, int nrgSzShift,
|
|
|
|
int tran_off, UCHAR *freqBandTable,
|
|
|
|
int slots) {
|
|
|
|
INT nrgTotal_e;
|
|
|
|
FIXP_DBL nrgTotal_m;
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL accu1 = FL2FXCONST_DBL(0.0f);
|
|
|
|
FIXP_DBL accu2 = FL2FXCONST_DBL(0.0f);
|
2018-02-26 20:17:00 +01:00
|
|
|
int tran_offdiv2 = tran_off >> nrgSzShift;
|
|
|
|
int ts, k;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
/* Sum up lowband energy from one frame at offset tran_off */
|
2016-04-08 19:52:42 +02:00
|
|
|
/* freqBandTable[LORES] has MAX_FREQ_COEFFS/2 +1 coeefs max. */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (ts = tran_offdiv2; ts < YBufferWriteOffset; ts++) {
|
2012-07-11 19:15:24 +02:00
|
|
|
for (k = 0; k < freqBandTable[0]; k++) {
|
|
|
|
accu1 += Energies[ts][k] >> 6;
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
for (; ts < tran_offdiv2 + (slots >> nrgSzShift); ts++) {
|
2012-07-11 19:15:24 +02:00
|
|
|
for (k = 0; k < freqBandTable[0]; k++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
accu2 += Energies[ts][k] >> 9;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
nrgTotal_m = fAddNorm(accu1, 1 - scaleEnergies[0], accu2,
|
|
|
|
4 - scaleEnergies[1], &nrgTotal_e);
|
|
|
|
nrgTotal_m = scaleValueSaturate(nrgTotal_m, nrgTotal_e);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
return (nrgTotal_m);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Functionname: addHighbandEnergies
|
|
|
|
*******************************************************************************
|
|
|
|
\brief Add highband energies
|
|
|
|
|
|
|
|
Highband energies are mapped to an array with smaller dimension:
|
|
|
|
Its time resolution is only 1 SBR-timeslot and its frequency resolution
|
|
|
|
is 1 SBR-band. Therefore the data to be fed into the spectralChange
|
|
|
|
function is reduced.
|
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
The values EnergiesM are scaled by the factor (2^19-scaleEnergies[0]) for
|
|
|
|
slots<YBufferWriteOffset and by the factor (2^19-scaleEnergies[1]) for
|
|
|
|
slots>=YBufferWriteOffset.
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
\return total energy in the highband, scaled by factor 2^19
|
2012-07-11 19:15:24 +02:00
|
|
|
*******************************************************************************/
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
static FIXP_DBL addHighbandEnergies(
|
|
|
|
FIXP_DBL **RESTRICT Energies, /*!< input */
|
|
|
|
INT *scaleEnergies, INT YBufferWriteOffset,
|
|
|
|
FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304]
|
|
|
|
[MAX_FREQ_COEFFS], /*!< Combined output */
|
|
|
|
UCHAR *RESTRICT freqBandTable, INT nSfb, INT sbrSlots, INT timeStep) {
|
|
|
|
INT i, j, k, slotIn, slotOut, scale[2];
|
|
|
|
INT li, ui;
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL nrgTotal;
|
|
|
|
FIXP_DBL accu = FL2FXCONST_DBL(0.0f);
|
|
|
|
|
|
|
|
/* Combine QMF-timeslots to SBR-timeslots,
|
|
|
|
combine QMF-bands to SBR-bands,
|
|
|
|
combine Left and Right channel */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (slotOut = 0; slotOut < sbrSlots; slotOut++) {
|
|
|
|
/* Note: Below slotIn = slotOut and not slotIn = timeStep*slotOut
|
|
|
|
because the Energies[] time resolution is always the SBR slot resolution
|
|
|
|
regardless of the timeStep. */
|
|
|
|
slotIn = slotOut;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (j = 0; j < nSfb; j++) {
|
2012-07-11 19:15:24 +02:00
|
|
|
accu = FL2FXCONST_DBL(0.0f);
|
|
|
|
|
|
|
|
li = freqBandTable[j];
|
|
|
|
ui = freqBandTable[j + 1];
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = li; k < ui; k++) {
|
|
|
|
for (i = 0; i < timeStep; i++) {
|
|
|
|
accu += Energies[slotIn][k] >> 5;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
EnergiesM[slotOut][j] = accu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
/* scale energies down before add up */
|
2018-02-26 20:17:00 +01:00
|
|
|
scale[0] = fixMin(8, scaleEnergies[0]);
|
|
|
|
scale[1] = fixMin(8, scaleEnergies[1]);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if ((scaleEnergies[0] - scale[0]) > (DFRACT_BITS - 1) ||
|
|
|
|
(scaleEnergies[1] - scale[1]) > (DFRACT_BITS - 1))
|
2012-07-11 19:15:24 +02:00
|
|
|
nrgTotal = FL2FXCONST_DBL(0.0f);
|
|
|
|
else {
|
|
|
|
/* Now add all energies */
|
|
|
|
accu = FL2FXCONST_DBL(0.0f);
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (slotOut = 0; slotOut < YBufferWriteOffset; slotOut++) {
|
|
|
|
for (j = 0; j < nSfb; j++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
accu += (EnergiesM[slotOut][j] >> scale[0]);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
nrgTotal = accu >> (scaleEnergies[0] - scale[0]);
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (slotOut = YBufferWriteOffset; slotOut < sbrSlots; slotOut++) {
|
|
|
|
for (j = 0; j < nSfb; j++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
accu += (EnergiesM[slotOut][j] >> scale[0]);
|
|
|
|
}
|
|
|
|
}
|
2018-05-04 15:51:23 +02:00
|
|
|
nrgTotal = fAddSaturate(nrgTotal, accu >> (scaleEnergies[1] - scale[1]));
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
return (nrgTotal);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Functionname: FDKsbrEnc_frameSplitter
|
|
|
|
*******************************************************************************
|
|
|
|
\brief Decides if a FIXFIX-frame shall be splitted into 2 envelopes
|
|
|
|
|
|
|
|
If no transient has been detected before, the frame can still be splitted
|
|
|
|
into 2 envelopes.
|
|
|
|
*******************************************************************************/
|
2018-02-26 20:17:00 +01:00
|
|
|
void FDKsbrEnc_frameSplitter(
|
|
|
|
FIXP_DBL **Energies, INT *scaleEnergies,
|
|
|
|
HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, UCHAR *freqBandTable,
|
|
|
|
UCHAR *tran_vector, int YBufferWriteOffset, int YBufferSzShift, int nSfb,
|
|
|
|
int timeStep, int no_cols, FIXP_DBL *tonality) {
|
|
|
|
if (tran_vector[1] == 0) /* no transient was detected */
|
2012-07-11 19:15:24 +02:00
|
|
|
{
|
|
|
|
FIXP_DBL delta;
|
2016-04-08 19:52:42 +02:00
|
|
|
INT delta_e;
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL(*EnergiesM)[MAX_FREQ_COEFFS];
|
|
|
|
FIXP_DBL EnergyTotal, newLowbandEnergy, newHighbandEnergy;
|
2012-07-11 19:15:24 +02:00
|
|
|
INT border;
|
2018-02-26 20:17:00 +01:00
|
|
|
INT sbrSlots = fMultI(GetInvInt(timeStep), no_cols);
|
|
|
|
C_ALLOC_SCRATCH_START(_EnergiesM, FIXP_DBL,
|
|
|
|
NUMBER_TIME_SLOTS_2304 * MAX_FREQ_COEFFS)
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_ASSERT(sbrSlots * timeStep == no_cols);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
EnergiesM = (FIXP_DBL(*)[MAX_FREQ_COEFFS])_EnergiesM;
|
|
|
|
|
2012-07-11 19:15:24 +02:00
|
|
|
/*
|
2018-02-26 20:17:00 +01:00
|
|
|
Get Lowband-energy over a range of 2 frames (Look half a frame back and
|
|
|
|
ahead).
|
2012-07-11 19:15:24 +02:00
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
newLowbandEnergy = addLowbandEnergies(
|
|
|
|
Energies, scaleEnergies, YBufferWriteOffset, YBufferSzShift,
|
|
|
|
h_sbrTransientDetector->tran_off, freqBandTable, no_cols);
|
|
|
|
|
|
|
|
newHighbandEnergy =
|
|
|
|
addHighbandEnergies(Energies, scaleEnergies, YBufferWriteOffset,
|
|
|
|
EnergiesM, freqBandTable, nSfb, sbrSlots, timeStep);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
/* prevLowBandEnergy: Corresponds to 1 frame, starting with half a frame
|
|
|
|
look-behind newLowbandEnergy: Corresponds to 1 frame, starting in the
|
|
|
|
middle of the current frame */
|
|
|
|
EnergyTotal = (newLowbandEnergy >> 1) +
|
|
|
|
(h_sbrTransientDetector->prevLowBandEnergy >>
|
|
|
|
1); /* mean of new and prev LB NRG */
|
|
|
|
EnergyTotal =
|
|
|
|
fAddSaturate(EnergyTotal, newHighbandEnergy); /* Add HB NRG */
|
2012-07-11 19:15:24 +02:00
|
|
|
/* The below border should specify the same position as the middle border
|
|
|
|
of a FIXFIX-frame with 2 envelopes. */
|
2018-02-26 20:17:00 +01:00
|
|
|
border = (sbrSlots + 1) >> 1;
|
|
|
|
|
|
|
|
if ((INT)EnergyTotal & 0xffffffe0 &&
|
|
|
|
(scaleEnergies[0] < 32 || scaleEnergies[1] < 32)) /* i.e. > 31 */ {
|
|
|
|
delta = spectralChange(EnergiesM, scaleEnergies, EnergyTotal, nSfb, 0,
|
|
|
|
border, YBufferWriteOffset, sbrSlots, &delta_e);
|
2016-04-08 19:52:42 +02:00
|
|
|
} else {
|
|
|
|
delta = FL2FXCONST_DBL(0.0f);
|
|
|
|
delta_e = 0;
|
|
|
|
|
|
|
|
/* set tonality to 0 when energy is very low, since the amplitude
|
|
|
|
resolution should then be low as well */
|
|
|
|
*tonality = FL2FXCONST_DBL(0.0f);
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (fIsLessThan(h_sbrTransientDetector->split_thr_m,
|
|
|
|
h_sbrTransientDetector->split_thr_e, delta, delta_e)) {
|
2012-07-11 19:15:24 +02:00
|
|
|
tran_vector[0] = 1; /* Set flag for splitting */
|
2016-04-08 19:52:42 +02:00
|
|
|
} else {
|
2012-07-11 19:15:24 +02:00
|
|
|
tran_vector[0] = 0;
|
2016-04-08 19:52:42 +02:00
|
|
|
}
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Update prevLowBandEnergy */
|
|
|
|
h_sbrTransientDetector->prevLowBandEnergy = newLowbandEnergy;
|
|
|
|
h_sbrTransientDetector->prevHighBandEnergy = newHighbandEnergy;
|
2018-02-26 20:17:00 +01:00
|
|
|
C_ALLOC_SCRATCH_END(_EnergiesM, FIXP_DBL,
|
|
|
|
NUMBER_TIME_SLOTS_2304 * MAX_FREQ_COEFFS)
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate transient energy threshold for each QMF band
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
static void calculateThresholds(FIXP_DBL **RESTRICT Energies,
|
|
|
|
INT *RESTRICT scaleEnergies,
|
|
|
|
FIXP_DBL *RESTRICT thresholds,
|
|
|
|
int YBufferWriteOffset, int YBufferSzShift,
|
|
|
|
int noCols, int noRows, int tran_off) {
|
|
|
|
FIXP_DBL mean_val, std_val, temp;
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL i_noCols;
|
|
|
|
FIXP_DBL i_noCols1;
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL accu, accu0, accu1;
|
|
|
|
int scaleFactor0, scaleFactor1, commonScale;
|
|
|
|
int i, j;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
i_noCols = GetInvInt(noCols + tran_off) << YBufferSzShift;
|
2012-07-11 19:15:24 +02:00
|
|
|
i_noCols1 = GetInvInt(noCols + tran_off - 1) << YBufferSzShift;
|
|
|
|
|
|
|
|
/* calc minimum scale of energies of previous and current frame */
|
2018-02-26 20:17:00 +01:00
|
|
|
commonScale = fixMin(scaleEnergies[0], scaleEnergies[1]);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
/* calc scalefactors to adapt energies to common scale */
|
2018-02-26 20:17:00 +01:00
|
|
|
scaleFactor0 = fixMin((scaleEnergies[0] - commonScale), (DFRACT_BITS - 1));
|
|
|
|
scaleFactor1 = fixMin((scaleEnergies[1] - commonScale), (DFRACT_BITS - 1));
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
FDK_ASSERT((scaleFactor0 >= 0) && (scaleFactor1 >= 0));
|
|
|
|
|
|
|
|
/* calculate standard deviation in every subband */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (i = 0; i < noRows; i++) {
|
|
|
|
int startEnergy = (tran_off >> YBufferSzShift);
|
|
|
|
int endEnergy = ((noCols >> YBufferSzShift) + tran_off);
|
2012-07-11 19:15:24 +02:00
|
|
|
int shift;
|
|
|
|
|
|
|
|
/* calculate mean value over decimated energy values (downsampled by 2). */
|
|
|
|
accu0 = accu1 = FL2FXCONST_DBL(0.0f);
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (j = startEnergy; j < YBufferWriteOffset; j++)
|
|
|
|
accu0 = fMultAddDiv2(accu0, Energies[j][i], i_noCols);
|
|
|
|
for (; j < endEnergy; j++)
|
|
|
|
accu1 = fMultAddDiv2(accu1, Energies[j][i], i_noCols);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
mean_val = ((accu0 << 1) >> scaleFactor0) +
|
|
|
|
((accu1 << 1) >> scaleFactor1); /* average */
|
|
|
|
shift = fixMax(
|
|
|
|
0, CountLeadingBits(mean_val) -
|
|
|
|
6); /* -6 to keep room for accumulating upto N = 24 values */
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
/* calculate standard deviation */
|
|
|
|
accu = FL2FXCONST_DBL(0.0f);
|
|
|
|
|
|
|
|
/* summe { ((mean_val-nrg)^2) * i_noCols1 } */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (j = startEnergy; j < YBufferWriteOffset; j++) {
|
|
|
|
temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor0))
|
|
|
|
<< shift;
|
|
|
|
temp = fPow2Div2(temp);
|
|
|
|
accu = fMultAddDiv2(accu, temp, i_noCols1);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
for (; j < endEnergy; j++) {
|
|
|
|
temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor1))
|
|
|
|
<< shift;
|
|
|
|
temp = fPow2Div2(temp);
|
|
|
|
accu = fMultAddDiv2(accu, temp, i_noCols1);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
accu <<= 2;
|
|
|
|
std_val = sqrtFixp(accu) >> shift; /* standard deviation */
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Take new threshold as average of calculated standard deviation ratio
|
|
|
|
and old threshold if greater than absolute threshold
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
temp = (commonScale <= (DFRACT_BITS - 1))
|
|
|
|
? fMult(FL2FXCONST_DBL(0.66f), thresholds[i]) +
|
|
|
|
(fMult(FL2FXCONST_DBL(0.34f), std_val) >> commonScale)
|
|
|
|
: (FIXP_DBL)0;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
thresholds[i] = fixMax(ABS_THRES, temp);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
FDK_ASSERT(commonScale >= 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate transient levels for each QMF time slot.
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
static void extractTransientCandidates(
|
|
|
|
FIXP_DBL **RESTRICT Energies, INT *RESTRICT scaleEnergies,
|
|
|
|
FIXP_DBL *RESTRICT thresholds, FIXP_DBL *RESTRICT transients,
|
|
|
|
int YBufferWriteOffset, int YBufferSzShift, int noCols, int start_band,
|
|
|
|
int stop_band, int tran_off, int addPrevSamples) {
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL i_thres;
|
2018-02-26 20:17:00 +01:00
|
|
|
C_ALLOC_SCRATCH_START(EnergiesTemp, FIXP_DBL, 2 * 32)
|
2012-07-11 19:15:24 +02:00
|
|
|
int tmpScaleEnergies0, tmpScaleEnergies1;
|
|
|
|
int endCond;
|
2018-02-26 20:17:00 +01:00
|
|
|
int startEnerg, endEnerg;
|
|
|
|
int i, j, jIndex, jpBM;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
tmpScaleEnergies0 = scaleEnergies[0];
|
|
|
|
tmpScaleEnergies1 = scaleEnergies[1];
|
|
|
|
|
|
|
|
/* Scale value for first energies, upto YBufferWriteOffset */
|
|
|
|
tmpScaleEnergies0 = fixMin(tmpScaleEnergies0, MAX_SHIFT_DBL);
|
|
|
|
/* Scale value for first energies, from YBufferWriteOffset upwards */
|
|
|
|
tmpScaleEnergies1 = fixMin(tmpScaleEnergies1, MAX_SHIFT_DBL);
|
|
|
|
|
|
|
|
FDK_ASSERT((tmpScaleEnergies0 >= 0) && (tmpScaleEnergies1 >= 0));
|
|
|
|
|
|
|
|
/* Keep addPrevSamples extra previous transient candidates. */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDKmemmove(transients, transients + noCols - addPrevSamples,
|
|
|
|
(tran_off + addPrevSamples) * sizeof(FIXP_DBL));
|
|
|
|
FDKmemclear(transients + tran_off + addPrevSamples,
|
|
|
|
noCols * sizeof(FIXP_DBL));
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
endCond = noCols; /* Amount of new transient values to be calculated. */
|
2018-02-26 20:17:00 +01:00
|
|
|
startEnerg = (tran_off - 3) >> YBufferSzShift; /* >>YBufferSzShift because of
|
|
|
|
amount of energy values. -3
|
|
|
|
because of neighbors being
|
|
|
|
watched. */
|
|
|
|
endEnerg =
|
|
|
|
((noCols + (YBufferWriteOffset << YBufferSzShift)) - 1) >>
|
|
|
|
YBufferSzShift; /* YBufferSzShift shifts because of half energy values. */
|
|
|
|
|
|
|
|
/* Compute differential values with two different weightings in every subband
|
|
|
|
*/
|
|
|
|
for (i = start_band; i < stop_band; i++) {
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL thres = thresholds[i];
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if ((LONG)thresholds[i] >= 256)
|
|
|
|
i_thres = (LONG)((LONG)MAXVAL_DBL / ((((LONG)thresholds[i])) + 1))
|
|
|
|
<< (32 - 24);
|
2012-07-11 19:15:24 +02:00
|
|
|
else
|
|
|
|
i_thres = (LONG)MAXVAL_DBL;
|
|
|
|
|
|
|
|
/* Copy one timeslot and de-scale and de-squish */
|
|
|
|
if (YBufferSzShift == 1) {
|
2018-02-26 20:17:00 +01:00
|
|
|
for (j = startEnerg; j < YBufferWriteOffset; j++) {
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL tmp = Energies[j][i];
|
2018-02-26 20:17:00 +01:00
|
|
|
EnergiesTemp[(j << 1) + 1] = EnergiesTemp[j << 1] =
|
|
|
|
tmp >> tmpScaleEnergies0;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
for (; j <= endEnerg; j++) {
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL tmp = Energies[j][i];
|
2018-02-26 20:17:00 +01:00
|
|
|
EnergiesTemp[(j << 1) + 1] = EnergiesTemp[j << 1] =
|
|
|
|
tmp >> tmpScaleEnergies1;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
for (j = startEnerg; j < YBufferWriteOffset; j++) {
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL tmp = Energies[j][i];
|
2018-02-26 20:17:00 +01:00
|
|
|
EnergiesTemp[j] = tmp >> tmpScaleEnergies0;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
for (; j <= endEnerg; j++) {
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL tmp = Energies[j][i];
|
2018-02-26 20:17:00 +01:00
|
|
|
EnergiesTemp[j] = tmp >> tmpScaleEnergies1;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Detect peaks in energy values. */
|
|
|
|
|
|
|
|
jIndex = tran_off;
|
2018-02-26 20:17:00 +01:00
|
|
|
jpBM = jIndex + addPrevSamples;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (j = endCond; j--; jIndex++, jpBM++) {
|
2012-07-11 19:15:24 +02:00
|
|
|
FIXP_DBL delta, tran;
|
|
|
|
int d;
|
|
|
|
|
|
|
|
delta = (FIXP_DBL)0;
|
2018-02-26 20:17:00 +01:00
|
|
|
tran = (FIXP_DBL)0;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (d = 1; d < 4; d++) {
|
|
|
|
delta += EnergiesTemp[jIndex + d]; /* R */
|
|
|
|
delta -= EnergiesTemp[jIndex - d]; /* L */
|
2012-07-11 19:15:24 +02:00
|
|
|
delta -= thres;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (delta > (FIXP_DBL)0) {
|
|
|
|
tran = fMultAddDiv2(tran, i_thres, delta);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
transients[jpBM] += (tran << 1);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
C_ALLOC_SCRATCH_END(EnergiesTemp, FIXP_DBL, 2 * 32)
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
void FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTran,
|
|
|
|
FIXP_DBL **Energies, INT *scaleEnergies,
|
|
|
|
UCHAR *transient_info, int YBufferWriteOffset,
|
|
|
|
int YBufferSzShift, int timeStep,
|
|
|
|
int frameMiddleBorder) {
|
2012-07-11 19:15:24 +02:00
|
|
|
int no_cols = h_sbrTran->no_cols;
|
|
|
|
int qmfStartSample;
|
|
|
|
int addPrevSamples;
|
2018-02-26 20:17:00 +01:00
|
|
|
int timeStepShift = 0;
|
2012-07-11 19:15:24 +02:00
|
|
|
int i, cond;
|
|
|
|
|
|
|
|
/* Where to start looking for transients in the transient candidate buffer */
|
|
|
|
qmfStartSample = timeStep * frameMiddleBorder;
|
2018-02-26 20:17:00 +01:00
|
|
|
/* We need to look one value backwards in the transients, so we might need one
|
|
|
|
* more previous value. */
|
|
|
|
addPrevSamples = (qmfStartSample > 0) ? 0 : 1;
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
switch (timeStep) {
|
2018-02-26 20:17:00 +01:00
|
|
|
case 1:
|
|
|
|
timeStepShift = 0;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
timeStepShift = 1;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
timeStepShift = 2;
|
|
|
|
break;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
calculateThresholds(Energies, scaleEnergies, h_sbrTran->thresholds,
|
|
|
|
YBufferWriteOffset, YBufferSzShift, h_sbrTran->no_cols,
|
|
|
|
h_sbrTran->no_rows, h_sbrTran->tran_off);
|
|
|
|
|
|
|
|
extractTransientCandidates(
|
|
|
|
Energies, scaleEnergies, h_sbrTran->thresholds, h_sbrTran->transients,
|
|
|
|
YBufferWriteOffset, YBufferSzShift, h_sbrTran->no_cols, 0,
|
|
|
|
h_sbrTran->no_rows, h_sbrTran->tran_off, addPrevSamples);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
transient_info[0] = 0;
|
|
|
|
transient_info[1] = 0;
|
|
|
|
transient_info[2] = 0;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Offset by the amount of additional previous transient candidates being
|
|
|
|
* kept. */
|
2012-07-11 19:15:24 +02:00
|
|
|
qmfStartSample += addPrevSamples;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Check for transients in second granule (pick the last value of subsequent
|
|
|
|
* values) */
|
|
|
|
for (i = qmfStartSample; i < qmfStartSample + no_cols; i++) {
|
|
|
|
cond = (h_sbrTran->transients[i] <
|
|
|
|
fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1])) &&
|
|
|
|
(h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
|
|
|
if (cond) {
|
2018-02-26 20:17:00 +01:00
|
|
|
transient_info[0] = (i - qmfStartSample) >> timeStepShift;
|
2012-07-11 19:15:24 +02:00
|
|
|
transient_info[1] = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (h_sbrTran->frameShift != 0) {
|
|
|
|
/* transient prediction for LDSBR */
|
|
|
|
/* Check for transients in first <frameShift> qmf-slots of second frame */
|
|
|
|
for (i = qmfStartSample + no_cols;
|
|
|
|
i < qmfStartSample + no_cols + h_sbrTran->frameShift; i++) {
|
|
|
|
cond = (h_sbrTran->transients[i] <
|
|
|
|
fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1])) &&
|
|
|
|
(h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr);
|
|
|
|
|
|
|
|
if (cond) {
|
|
|
|
int pos = (int)((i - qmfStartSample - no_cols) >> timeStepShift);
|
|
|
|
if ((pos < 3) && (transient_info[1] == 0)) {
|
|
|
|
transient_info[2] = 1;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
break;
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
}
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
int FDKsbrEnc_InitSbrTransientDetector(
|
|
|
|
HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector,
|
|
|
|
UINT sbrSyntaxFlags, /* SBR syntax flags derived from AOT. */
|
|
|
|
INT frameSize, INT sampleFreq, sbrConfigurationPtr params, int tran_fc,
|
|
|
|
int no_cols, int no_rows, int YBufferWriteOffset, int YBufferSzShift,
|
|
|
|
int frameShift, int tran_off) {
|
|
|
|
INT totalBitrate =
|
|
|
|
params->codecSettings.standardBitrate * params->codecSettings.nChannels;
|
|
|
|
INT codecBitrate = params->codecSettings.bitRate;
|
|
|
|
FIXP_DBL bitrateFactor_m, framedur_fix;
|
|
|
|
INT bitrateFactor_e, tmp_e;
|
|
|
|
|
|
|
|
FDKmemclear(h_sbrTransientDetector, sizeof(SBR_TRANSIENT_DETECTOR));
|
|
|
|
|
|
|
|
h_sbrTransientDetector->frameShift = frameShift;
|
|
|
|
h_sbrTransientDetector->tran_off = tran_off;
|
|
|
|
|
|
|
|
if (codecBitrate) {
|
|
|
|
bitrateFactor_m = fDivNorm((FIXP_DBL)totalBitrate,
|
|
|
|
(FIXP_DBL)(codecBitrate << 2), &bitrateFactor_e);
|
|
|
|
bitrateFactor_e += 2;
|
|
|
|
} else {
|
|
|
|
bitrateFactor_m = FL2FXCONST_DBL(1.0 / 4.0);
|
|
|
|
bitrateFactor_e = 2;
|
|
|
|
}
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
framedur_fix = fDivNorm(frameSize, sampleFreq);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* The longer the frames, the more often should the FIXFIX-
|
|
|
|
case transmit 2 envelopes instead of 1.
|
|
|
|
Frame durations below 10 ms produce the highest threshold
|
|
|
|
so that practically always only 1 env is transmitted. */
|
|
|
|
FIXP_DBL tmp = framedur_fix - FL2FXCONST_DBL(0.010);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
tmp = fixMax(tmp, FL2FXCONST_DBL(0.0001));
|
|
|
|
tmp = fDivNorm(FL2FXCONST_DBL(0.000075), fPow2(tmp), &tmp_e);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
bitrateFactor_e = (tmp_e + bitrateFactor_e);
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
|
2016-04-08 19:52:42 +02:00
|
|
|
bitrateFactor_e--; /* divide by 2 */
|
|
|
|
}
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_ASSERT(no_cols <= 32);
|
|
|
|
FDK_ASSERT(no_rows <= 64);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
h_sbrTransientDetector->no_cols = no_cols;
|
|
|
|
h_sbrTransientDetector->tran_thr =
|
|
|
|
(FIXP_DBL)((params->tran_thr << (32 - 24 - 1)) / no_rows);
|
|
|
|
h_sbrTransientDetector->tran_fc = tran_fc;
|
|
|
|
h_sbrTransientDetector->split_thr_m = fMult(tmp, bitrateFactor_m);
|
|
|
|
h_sbrTransientDetector->split_thr_e = bitrateFactor_e;
|
|
|
|
h_sbrTransientDetector->no_rows = no_rows;
|
|
|
|
h_sbrTransientDetector->mode = params->tran_det_mode;
|
|
|
|
h_sbrTransientDetector->prevLowBandEnergy = FL2FXCONST_DBL(0.0f);
|
2012-07-11 19:15:24 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
return (0);
|
2012-07-11 19:15:24 +02:00
|
|
|
}
|
|
|
|
|
2016-04-08 19:52:42 +02:00
|
|
|
#define ENERGY_SCALING_SIZE 32
|
|
|
|
|
|
|
|
INT FDKsbrEnc_InitSbrFastTransientDetector(
|
2018-02-26 20:17:00 +01:00
|
|
|
HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector,
|
|
|
|
const INT time_slots_per_frame, const INT bandwidth_qmf_slot,
|
|
|
|
const INT no_qmf_channels, const INT sbr_qmf_1st_band) {
|
|
|
|
int i;
|
2016-04-08 19:52:42 +02:00
|
|
|
int buff_size;
|
|
|
|
FIXP_DBL myExp;
|
|
|
|
FIXP_DBL myExpSlot;
|
|
|
|
|
|
|
|
h_sbrFastTransientDetector->lookahead = TRAN_DET_LOOKAHEAD;
|
|
|
|
h_sbrFastTransientDetector->nTimeSlots = time_slots_per_frame;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
buff_size = h_sbrFastTransientDetector->nTimeSlots +
|
|
|
|
h_sbrFastTransientDetector->lookahead;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (i = 0; i < buff_size; i++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
h_sbrFastTransientDetector->delta_energy[i] = FL2FXCONST_DBL(0.0f);
|
|
|
|
h_sbrFastTransientDetector->energy_timeSlots[i] = FL2FXCONST_DBL(0.0f);
|
|
|
|
h_sbrFastTransientDetector->lowpass_energy[i] = FL2FXCONST_DBL(0.0f);
|
|
|
|
h_sbrFastTransientDetector->transientCandidates[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FDK_ASSERT(bandwidth_qmf_slot > 0.f);
|
2018-02-26 20:17:00 +01:00
|
|
|
h_sbrFastTransientDetector->stopBand =
|
|
|
|
fMin(TRAN_DET_STOP_FREQ / bandwidth_qmf_slot, no_qmf_channels);
|
|
|
|
h_sbrFastTransientDetector->startBand =
|
|
|
|
fMin(sbr_qmf_1st_band,
|
|
|
|
h_sbrFastTransientDetector->stopBand - TRAN_DET_MIN_QMFBANDS);
|
2016-04-08 19:52:42 +02:00
|
|
|
|
|
|
|
FDK_ASSERT(h_sbrFastTransientDetector->startBand < no_qmf_channels);
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_ASSERT(h_sbrFastTransientDetector->startBand <
|
|
|
|
h_sbrFastTransientDetector->stopBand);
|
2016-04-08 19:52:42 +02:00
|
|
|
FDK_ASSERT(h_sbrFastTransientDetector->startBand > 1);
|
|
|
|
FDK_ASSERT(h_sbrFastTransientDetector->stopBand > 1);
|
|
|
|
|
|
|
|
/* the energy weighting and adding up has a headroom of 6 Bits,
|
|
|
|
so up to 64 bands can be added without potential overflow. */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_ASSERT(h_sbrFastTransientDetector->stopBand -
|
|
|
|
h_sbrFastTransientDetector->startBand <=
|
|
|
|
64);
|
|
|
|
|
|
|
|
/* QMF_HP_dB_SLOPE_FIX says that we want a 20 dB per 16 kHz HP filter.
|
|
|
|
The following lines map this to the QMF bandwidth. */
|
|
|
|
#define EXP_E 7 /* 64 (=64) multiplications max, max. allowed sum is 0.5 */
|
|
|
|
myExp = fMultNorm(QMF_HP_dBd_SLOPE_FIX, 0, (FIXP_DBL)bandwidth_qmf_slot,
|
|
|
|
DFRACT_BITS - 1, EXP_E);
|
2016-04-08 19:52:42 +02:00
|
|
|
myExpSlot = myExp;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (i = 0; i < 64; i++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
/* Calculate dBf over all qmf bands:
|
|
|
|
dBf = (10^(0.002266f/10*bw(slot)))^(band) =
|
|
|
|
= 2^(log2(10)*0.002266f/10*bw(slot)*band) =
|
|
|
|
= 2^(0.00075275f*bw(slot)*band) */
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL dBf_m; /* dBf mantissa */
|
|
|
|
INT dBf_e; /* dBf exponent */
|
2016-04-08 19:52:42 +02:00
|
|
|
INT tmp;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
INT dBf_int; /* dBf integer part */
|
|
|
|
FIXP_DBL dBf_fract; /* dBf fractional part */
|
2016-04-08 19:52:42 +02:00
|
|
|
|
|
|
|
/* myExp*(i+1) = myExp_int - myExp_fract
|
|
|
|
myExp*(i+1) is split up here for better accuracy of CalcInvLdData(),
|
|
|
|
for its result can be split up into an integer and a fractional part */
|
|
|
|
|
|
|
|
/* Round up to next integer */
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL myExp_int =
|
|
|
|
(myExpSlot & (FIXP_DBL)0xfe000000) + (FIXP_DBL)0x02000000;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
|
|
|
/* This is the fractional part that needs to be substracted */
|
|
|
|
FIXP_DBL myExp_fract = myExp_int - myExpSlot;
|
|
|
|
|
|
|
|
/* Calc integer part */
|
2018-02-26 20:17:00 +01:00
|
|
|
dBf_int = CalcInvLdData(myExp_int);
|
|
|
|
/* The result needs to be re-scaled. The ld(myExp_int) had been scaled by
|
|
|
|
EXP_E, the CalcInvLdData expects the operand to be scaled by
|
|
|
|
LD_DATA_SHIFT. Therefore, the correctly scaled result is
|
|
|
|
dBf_int^(2^(EXP_E-LD_DATA_SHIFT)), which is dBf_int^2 */
|
|
|
|
|
|
|
|
if (dBf_int <=
|
|
|
|
46340) { /* compare with maximum allowed value for signed integer
|
|
|
|
multiplication, 46340 =
|
|
|
|
(INT)floor(sqrt((double)(((UINT)1<<(DFRACT_BITS-1))-1))) */
|
|
|
|
dBf_int *= dBf_int;
|
|
|
|
|
|
|
|
/* Calc fractional part */
|
|
|
|
dBf_fract = CalcInvLdData(-myExp_fract);
|
|
|
|
/* The result needs to be re-scaled. The ld(myExp_fract) had been scaled
|
|
|
|
by EXP_E, the CalcInvLdData expects the operand to be scaled by
|
|
|
|
LD_DATA_SHIFT. Therefore, the correctly scaled result is
|
|
|
|
dBf_fract^(2^(EXP_E-LD_DATA_SHIFT)), which is dBf_fract^2 */
|
|
|
|
dBf_fract = fMultNorm(dBf_fract, dBf_fract, &tmp);
|
|
|
|
|
|
|
|
/* Get worst case scaling of multiplication result */
|
|
|
|
dBf_e = (DFRACT_BITS - 1 - tmp) - CountLeadingBits(dBf_int);
|
|
|
|
|
|
|
|
/* Now multiply integer with fractional part of the result, thus resulting
|
|
|
|
in the overall accurate fractional result */
|
|
|
|
dBf_m = fMultNorm(dBf_int, DFRACT_BITS - 1, dBf_fract, tmp, dBf_e);
|
|
|
|
|
|
|
|
myExpSlot += myExp;
|
|
|
|
} else {
|
|
|
|
dBf_m = (FIXP_DBL)0;
|
|
|
|
dBf_e = 0;
|
|
|
|
}
|
2016-04-08 19:52:42 +02:00
|
|
|
|
|
|
|
/* Keep the results */
|
|
|
|
h_sbrFastTransientDetector->dBf_m[i] = dBf_m;
|
|
|
|
h_sbrFastTransientDetector->dBf_e[i] = dBf_e;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure that dBf is greater than 1.0 (because it should be a highpass) */
|
|
|
|
/* ... */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FDKsbrEnc_fastTransientDetect(
|
2018-02-26 20:17:00 +01:00
|
|
|
const HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector,
|
|
|
|
const FIXP_DBL *const *Energies, const int *const scaleEnergies,
|
|
|
|
const INT YBufferWriteOffset, UCHAR *const tran_vector) {
|
2016-04-08 19:52:42 +02:00
|
|
|
int timeSlot, band;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL max_delta_energy; /* helper to store maximum energy ratio */
|
|
|
|
int max_delta_energy_scale; /* helper to store scale of maximum energy ratio
|
|
|
|
*/
|
|
|
|
int ind_max = 0; /* helper to store index of maximum energy ratio */
|
|
|
|
int isTransientInFrame = 0;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
const int nTimeSlots = h_sbrFastTransientDetector->nTimeSlots;
|
|
|
|
const int lookahead = h_sbrFastTransientDetector->lookahead;
|
|
|
|
const int startBand = h_sbrFastTransientDetector->startBand;
|
|
|
|
const int stopBand = h_sbrFastTransientDetector->stopBand;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
int *transientCandidates = h_sbrFastTransientDetector->transientCandidates;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL *energy_timeSlots = h_sbrFastTransientDetector->energy_timeSlots;
|
|
|
|
int *energy_timeSlots_scale =
|
|
|
|
h_sbrFastTransientDetector->energy_timeSlots_scale;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL *delta_energy = h_sbrFastTransientDetector->delta_energy;
|
|
|
|
int *delta_energy_scale = h_sbrFastTransientDetector->delta_energy_scale;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
const FIXP_DBL thr = TRAN_DET_THRSHLD;
|
|
|
|
const INT thr_scale = TRAN_DET_THRSHLD_SCALE;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
|
|
|
/*reset transient info*/
|
|
|
|
tran_vector[2] = 0;
|
|
|
|
|
|
|
|
/* reset transient candidates */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDKmemclear(transientCandidates + lookahead, nTimeSlots * sizeof(int));
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
int i, norm;
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL tmpE = FL2FXCONST_DBL(0.0f);
|
|
|
|
int headroomEnSlot = DFRACT_BITS - 1;
|
2016-04-08 19:52:42 +02:00
|
|
|
|
|
|
|
FIXP_DBL smallNRG = FL2FXCONST_DBL(1e-2f);
|
|
|
|
FIXP_DBL denominator;
|
|
|
|
INT denominator_scale;
|
|
|
|
|
|
|
|
/* determine minimum headroom of energy values for this timeslot */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (band = startBand; band < stopBand; band++) {
|
|
|
|
int tmp_headroom = fNormz(Energies[timeSlot][band]) - 1;
|
|
|
|
if (tmp_headroom < headroomEnSlot) {
|
2016-04-08 19:52:42 +02:00
|
|
|
headroomEnSlot = tmp_headroom;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (i = 0, band = startBand; band < stopBand; band++, i++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
/* energy is weighted by weightingfactor stored in dBf_m array */
|
|
|
|
/* dBf_m index runs from 0 to stopBand-startband */
|
|
|
|
/* energy shifted by calculated headroom for maximum precision */
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL weightedEnergy =
|
|
|
|
fMult(Energies[timeSlot][band] << headroomEnSlot,
|
|
|
|
h_sbrFastTransientDetector->dBf_m[i]);
|
2016-04-08 19:52:42 +02:00
|
|
|
|
|
|
|
/* energy is added up */
|
|
|
|
/* shift by 6 to have a headroom for maximum 64 additions */
|
|
|
|
/* shift by dBf_e to handle weighting factor dependent scale factors */
|
2018-02-26 20:17:00 +01:00
|
|
|
tmpE +=
|
|
|
|
weightedEnergy >> (6 + (10 - h_sbrFastTransientDetector->dBf_e[i]));
|
2016-04-08 19:52:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* store calculated energy for timeslot */
|
|
|
|
energy_timeSlots[timeSlot] = tmpE;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* calculate overall scale factor for energy of this timeslot */
|
|
|
|
/* = original scale factor of energies
|
|
|
|
* (-scaleEnergies[0]+2*QMF_SCALE_OFFSET or
|
|
|
|
* -scaleEnergies[1]+2*QMF_SCALE_OFFSET */
|
|
|
|
/* depending on YBufferWriteOffset) */
|
|
|
|
/* + weighting factor scale (10) */
|
|
|
|
/* + adding up scale factor ( 6) */
|
|
|
|
/* - headroom of energy value (headroomEnSlot) */
|
|
|
|
if (timeSlot < YBufferWriteOffset) {
|
|
|
|
energy_timeSlots_scale[timeSlot] =
|
|
|
|
(-scaleEnergies[0] + 2 * QMF_SCALE_OFFSET) + (10 + 6) -
|
|
|
|
headroomEnSlot;
|
2016-04-08 19:52:42 +02:00
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
energy_timeSlots_scale[timeSlot] =
|
|
|
|
(-scaleEnergies[1] + 2 * QMF_SCALE_OFFSET) + (10 + 6) -
|
|
|
|
headroomEnSlot;
|
2016-04-08 19:52:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add a small energy to the denominator, thus making the transient
|
|
|
|
detection energy-dependent. Loud transients are being detected,
|
|
|
|
silent ones not. */
|
|
|
|
|
|
|
|
/* make sure that smallNRG does not overflow */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (-energy_timeSlots_scale[timeSlot - 1] + 1 > 5) {
|
2016-04-08 19:52:42 +02:00
|
|
|
denominator = smallNRG;
|
|
|
|
denominator_scale = 0;
|
|
|
|
} else {
|
|
|
|
/* Leave an additional headroom of 1 bit for this addition. */
|
2018-02-26 20:17:00 +01:00
|
|
|
smallNRG =
|
|
|
|
scaleValue(smallNRG, -(energy_timeSlots_scale[timeSlot - 1] + 1));
|
|
|
|
denominator = (energy_timeSlots[timeSlot - 1] >> 1) + smallNRG;
|
|
|
|
denominator_scale = energy_timeSlots_scale[timeSlot - 1] + 1;
|
2016-04-08 19:52:42 +02:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
delta_energy[timeSlot] =
|
|
|
|
fDivNorm(energy_timeSlots[timeSlot], denominator, &norm);
|
|
|
|
delta_energy_scale[timeSlot] =
|
|
|
|
energy_timeSlots_scale[timeSlot] - denominator_scale + norm;
|
2016-04-08 19:52:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*get transient candidates*/
|
|
|
|
/* For every timeslot, check if delta(E) exceeds the threshold. If it did,
|
|
|
|
it could potentially be marked as a transient candidate. However, the 2
|
|
|
|
slots before the current one must not be transients with an energy higher
|
|
|
|
than 1.4*E(current). If both aren't transients or if the energy of the
|
|
|
|
current timesolot is more than 1.4 times higher than the energy in the
|
|
|
|
last or the one before the last slot, it is marked as a transient.*/
|
|
|
|
|
|
|
|
FDK_ASSERT(lookahead >= 2);
|
2018-02-26 20:17:00 +01:00
|
|
|
for (timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) {
|
|
|
|
FIXP_DBL energy_cur_slot_weighted =
|
|
|
|
fMult(energy_timeSlots[timeSlot], FL2FXCONST_DBL(1.0f / 1.4f));
|
|
|
|
if (!fIsLessThan(delta_energy[timeSlot], delta_energy_scale[timeSlot], thr,
|
|
|
|
thr_scale) &&
|
|
|
|
(((transientCandidates[timeSlot - 2] == 0) &&
|
|
|
|
(transientCandidates[timeSlot - 1] == 0)) ||
|
|
|
|
!fIsLessThan(energy_cur_slot_weighted,
|
|
|
|
energy_timeSlots_scale[timeSlot],
|
|
|
|
energy_timeSlots[timeSlot - 1],
|
|
|
|
energy_timeSlots_scale[timeSlot - 1]) ||
|
|
|
|
!fIsLessThan(energy_cur_slot_weighted,
|
|
|
|
energy_timeSlots_scale[timeSlot],
|
|
|
|
energy_timeSlots[timeSlot - 2],
|
|
|
|
energy_timeSlots_scale[timeSlot - 2]))) {
|
2016-04-08 19:52:42 +02:00
|
|
|
/* in case of strong transients, subsequent
|
|
|
|
* qmf slots might be recognized as transients. */
|
|
|
|
transientCandidates[timeSlot] = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*get transient with max energy*/
|
2018-02-26 20:17:00 +01:00
|
|
|
max_delta_energy = FL2FXCONST_DBL(0.0f);
|
2016-04-08 19:52:42 +02:00
|
|
|
max_delta_energy_scale = 0;
|
|
|
|
ind_max = 0;
|
|
|
|
isTransientInFrame = 0;
|
2018-02-26 20:17:00 +01:00
|
|
|
for (timeSlot = 0; timeSlot < nTimeSlots; timeSlot++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
int scale = fMax(delta_energy_scale[timeSlot], max_delta_energy_scale);
|
2018-02-26 20:17:00 +01:00
|
|
|
if (transientCandidates[timeSlot] &&
|
|
|
|
((delta_energy[timeSlot] >> (scale - delta_energy_scale[timeSlot])) >
|
|
|
|
(max_delta_energy >> (scale - max_delta_energy_scale)))) {
|
|
|
|
max_delta_energy = delta_energy[timeSlot];
|
2016-04-08 19:52:42 +02:00
|
|
|
max_delta_energy_scale = scale;
|
2018-02-26 20:17:00 +01:00
|
|
|
ind_max = timeSlot;
|
2016-04-08 19:52:42 +02:00
|
|
|
isTransientInFrame = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*from all transient candidates take the one with the biggest energy*/
|
2018-02-26 20:17:00 +01:00
|
|
|
if (isTransientInFrame) {
|
2016-04-08 19:52:42 +02:00
|
|
|
tran_vector[0] = ind_max;
|
|
|
|
tran_vector[1] = 1;
|
|
|
|
} else {
|
|
|
|
/*reset transient info*/
|
|
|
|
tran_vector[0] = tran_vector[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*check for transients in lookahead*/
|
2018-02-26 20:17:00 +01:00
|
|
|
for (timeSlot = nTimeSlots; timeSlot < nTimeSlots + lookahead; timeSlot++) {
|
|
|
|
if (transientCandidates[timeSlot]) {
|
2016-04-08 19:52:42 +02:00
|
|
|
tran_vector[2] = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*update buffers*/
|
2018-02-26 20:17:00 +01:00
|
|
|
for (timeSlot = 0; timeSlot < lookahead; timeSlot++) {
|
2016-04-08 19:52:42 +02:00
|
|
|
transientCandidates[timeSlot] = transientCandidates[nTimeSlots + timeSlot];
|
|
|
|
|
|
|
|
/* fixpoint stuff */
|
2018-02-26 20:17:00 +01:00
|
|
|
energy_timeSlots[timeSlot] = energy_timeSlots[nTimeSlots + timeSlot];
|
|
|
|
energy_timeSlots_scale[timeSlot] =
|
|
|
|
energy_timeSlots_scale[nTimeSlots + timeSlot];
|
2016-04-08 19:52:42 +02:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
delta_energy[timeSlot] = delta_energy[nTimeSlots + timeSlot];
|
|
|
|
delta_energy_scale[timeSlot] = delta_energy_scale[nTimeSlots + timeSlot];
|
2016-04-08 19:52:42 +02:00
|
|
|
}
|
|
|
|
}
|