2018-02-26 20:17:00 +01:00
|
|
|
/* -----------------------------------------------------------------------------
|
2012-07-11 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 10:15:24 -07: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 decoder library ******************************
|
|
|
|
|
|
|
|
Author(s):
|
|
|
|
|
|
|
|
Description:
|
|
|
|
|
|
|
|
*******************************************************************************/
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\file
|
2018-02-26 20:17:00 +01:00
|
|
|
\brief Envelope calculation
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
The envelope adjustor compares the energies present in the transposed
|
|
|
|
highband to the reference energies conveyed with the bitstream.
|
|
|
|
The highband is amplified (sometimes) or attenuated (mostly) to the
|
|
|
|
desired level.
|
|
|
|
|
|
|
|
The spectral shape of the reference energies can be changed several times per
|
|
|
|
frame if necessary. Each set of energy values corresponding to a certain range
|
|
|
|
in time will be called an <em>envelope</em> here.
|
|
|
|
The bitstream supports several frequency scales and two resolutions. Normally,
|
|
|
|
one or more QMF-subbands are grouped to one SBR-band. An envelope contains
|
|
|
|
reference energies for each SBR-band.
|
|
|
|
In addition to the energy envelopes, noise envelopes are transmitted that
|
|
|
|
define the ratio of energy which is generated by adding noise instead of
|
|
|
|
transposing the lowband. The noise envelopes are given in a coarser time
|
|
|
|
and frequency resolution.
|
|
|
|
If a signal contains strong tonal components, synthetic sines can be
|
|
|
|
generated in individual SBR bands.
|
|
|
|
|
|
|
|
An overlap buffer of 6 QMF-timeslots is used to allow a more
|
|
|
|
flexible alignment of the envelopes in time that is not restricted to the
|
|
|
|
core codec's frame borders.
|
|
|
|
Therefore the envelope adjustor has access to the spectral data of the
|
|
|
|
current frame as well as the last 6 QMF-timeslots of the previous frame.
|
|
|
|
However, in average only the data of 1 frame is being processed as
|
|
|
|
the adjustor is called once per frame.
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
Depending on the frequency range set in the bitstream, only QMF-subbands
|
|
|
|
between <em>lowSubband</em> and <em>highSubband</em> are adjusted.
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
Scaling of spectral data to maximize SNR (see #QMF_SCALE_FACTOR) as well as a
|
|
|
|
special Mantissa-Exponent format ( see calculateSbrEnvelope() ) are being
|
|
|
|
used. The main entry point for this modules is calculateSbrEnvelope().
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
\sa sbr_scale.h, #QMF_SCALE_FACTOR, calculateSbrEnvelope(), \ref
|
|
|
|
documentationOverview
|
2012-07-11 10:15:24 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "env_calc.h"
|
|
|
|
|
|
|
|
#include "sbrdec_freq_sca.h"
|
|
|
|
#include "env_extr.h"
|
|
|
|
#include "transcendent.h"
|
|
|
|
#include "sbr_ram.h"
|
|
|
|
#include "sbr_rom.h"
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
#include "genericStds.h" /* need FDKpow() for debug outputs */
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
FIXP_DBL nrgRef[MAX_FREQ_COEFFS];
|
|
|
|
FIXP_DBL nrgEst[MAX_FREQ_COEFFS];
|
|
|
|
FIXP_DBL nrgGain[MAX_FREQ_COEFFS];
|
|
|
|
FIXP_DBL noiseLevel[MAX_FREQ_COEFFS];
|
|
|
|
FIXP_DBL nrgSine[MAX_FREQ_COEFFS];
|
|
|
|
|
|
|
|
SCHAR nrgRef_e[MAX_FREQ_COEFFS];
|
|
|
|
SCHAR nrgEst_e[MAX_FREQ_COEFFS];
|
|
|
|
SCHAR nrgGain_e[MAX_FREQ_COEFFS];
|
|
|
|
SCHAR noiseLevel_e[MAX_FREQ_COEFFS];
|
|
|
|
SCHAR nrgSine_e[MAX_FREQ_COEFFS];
|
|
|
|
/* yet another exponent [0]: for ts < no_cols; [1]: for ts >= no_cols */
|
|
|
|
SCHAR exponent[2];
|
|
|
|
} ENV_CALC_NRGS;
|
|
|
|
|
|
|
|
static void equalizeFiltBufferExp(FIXP_DBL *filtBuffer, SCHAR *filtBuffer_e,
|
|
|
|
FIXP_DBL *NrgGain, SCHAR *NrgGain_e,
|
|
|
|
int subbands);
|
|
|
|
|
|
|
|
static void calcNrgPerSubband(FIXP_DBL **analysBufferReal,
|
|
|
|
FIXP_DBL **analysBufferImag, int lowSubband,
|
|
|
|
int highSubband, int start_pos, int next_pos,
|
|
|
|
SCHAR frameExp, FIXP_DBL *nrgEst,
|
|
|
|
SCHAR *nrgEst_e);
|
|
|
|
|
|
|
|
static void calcNrgPerSfb(FIXP_DBL **analysBufferReal,
|
|
|
|
FIXP_DBL **analysBufferImag, int nSfb,
|
|
|
|
UCHAR *freqBandTable, int start_pos, int next_pos,
|
|
|
|
SCHAR input_e, FIXP_DBL *nrg_est, SCHAR *nrg_est_e);
|
|
|
|
|
|
|
|
static void calcSubbandGain(FIXP_DBL nrgRef, SCHAR nrgRef_e,
|
|
|
|
ENV_CALC_NRGS *nrgs, int c, FIXP_DBL tmpNoise,
|
|
|
|
SCHAR tmpNoise_e, UCHAR sinePresentFlag,
|
|
|
|
UCHAR sineMapped, int noNoiseFlag);
|
|
|
|
|
|
|
|
static void calcAvgGain(ENV_CALC_NRGS *nrgs, int lowSubband, int highSubband,
|
|
|
|
FIXP_DBL *sumRef_m, SCHAR *sumRef_e,
|
|
|
|
FIXP_DBL *ptrAvgGain_m, SCHAR *ptrAvgGain_e);
|
|
|
|
|
|
|
|
static void adjustTimeSlot_EldGrid(FIXP_DBL *ptrReal, ENV_CALC_NRGS *nrgs,
|
|
|
|
UCHAR *ptrHarmIndex, int lowSubbands,
|
|
|
|
int noSubbands, int scale_change,
|
|
|
|
int noNoiseFlag, int *ptrPhaseIndex,
|
|
|
|
int scale_diff_low);
|
|
|
|
|
|
|
|
static void adjustTimeSlotLC(FIXP_DBL *ptrReal, ENV_CALC_NRGS *nrgs,
|
|
|
|
UCHAR *ptrHarmIndex, int lowSubbands,
|
|
|
|
int noSubbands, int scale_change, int noNoiseFlag,
|
|
|
|
int *ptrPhaseIndex);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Variant of adjustTimeSlotHQ() which only regards gain and noise but no
|
|
|
|
* additional harmonics
|
|
|
|
*/
|
|
|
|
static void adjustTimeSlotHQ_GainAndNoise(
|
|
|
|
FIXP_DBL *ptrReal, FIXP_DBL *ptrImag,
|
|
|
|
HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
|
|
|
|
int lowSubbands, int noSubbands, int scale_change, FIXP_SGL smooth_ratio,
|
|
|
|
int noNoiseFlag, int filtBufferNoiseShift);
|
|
|
|
/**
|
|
|
|
* \brief Variant of adjustTimeSlotHQ() which only adds the additional harmonics
|
|
|
|
*/
|
|
|
|
static void adjustTimeSlotHQ_AddHarmonics(
|
|
|
|
FIXP_DBL *ptrReal, FIXP_DBL *ptrImag,
|
|
|
|
HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
|
|
|
|
int lowSubbands, int noSubbands, int scale_change);
|
|
|
|
|
|
|
|
static void adjustTimeSlotHQ(FIXP_DBL *ptrReal, FIXP_DBL *ptrImag,
|
|
|
|
HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env,
|
|
|
|
ENV_CALC_NRGS *nrgs, int lowSubbands,
|
|
|
|
int noSubbands, int scale_change,
|
|
|
|
FIXP_SGL smooth_ratio, int noNoiseFlag,
|
|
|
|
int filtBufferNoiseShift);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Map sine flags from bitstream to QMF bands
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
The bitstream carries only 1 sine flag per band (Sfb) and frame.
|
|
|
|
This function maps every sine flag from the bitstream to a specific QMF
|
|
|
|
subband and to a specific envelope where the sine shall start. The result is
|
|
|
|
stored in the vector sineMapped which contains one entry per QMF subband. The
|
|
|
|
value of an entry specifies the envelope where a sine shall start. A value of
|
|
|
|
32 indicates that no sine is present in the subband. The missing harmonics
|
|
|
|
flags from the previous frame (harmFlagsPrev) determine if a sine starts at
|
|
|
|
the beginning of the frame or at the transient position. Additionally, the
|
|
|
|
flags in harmFlagsPrev are being updated by this function for the next frame.
|
2012-07-11 10:15:24 -07:00
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
static void mapSineFlags(
|
|
|
|
UCHAR *freqBandTable, /*!< Band borders (there's only 1 flag per band) */
|
|
|
|
int nSfb, /*!< Number of bands in the table */
|
|
|
|
ULONG *addHarmonics, /*!< Packed addHarmonics of current frame (aligned to
|
|
|
|
the MSB) */
|
|
|
|
ULONG *harmFlagsPrev, /*!< Packed addHarmonics of previous frame (aligned to
|
|
|
|
the LSB) */
|
|
|
|
ULONG *harmFlagsPrevActive, /*!< Packed sineMapped of previous frame
|
|
|
|
(aligned to the LSB) */
|
|
|
|
int tranEnv, /*!< Transient position */
|
|
|
|
SCHAR *sineMapped) /*!< Resulting vector of sine start positions for each
|
|
|
|
QMF band */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
{
|
|
|
|
int i;
|
2018-02-26 20:17:00 +01:00
|
|
|
int bitcount = 31;
|
|
|
|
ULONG harmFlagsQmfBands[ADD_HARMONICS_FLAGS_SIZE] = {0};
|
|
|
|
ULONG *curFlags = addHarmonics;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*
|
2018-02-26 20:17:00 +01:00
|
|
|
Format of addHarmonics (aligned to MSB):
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
Up to MAX_FREQ_COEFFS sfb bands can be flagged for a sign.
|
|
|
|
first word = flags for lowest 32 sfb bands in use
|
|
|
|
second word = flags for higest 32 sfb bands (if present)
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
Format of harmFlagsPrev (aligned to LSB):
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
Index is absolute (not relative to lsb) so it is correct even if lsb
|
|
|
|
changes first word = flags for lowest 32 qmf bands (0...31) second word =
|
|
|
|
flags for next higher 32 qmf bands (32...63)
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
*/
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Reset the output vector first */
|
|
|
|
FDKmemset(sineMapped, 32,
|
|
|
|
MAX_FREQ_COEFFS * sizeof(SCHAR)); /* 32 means 'no sine' */
|
|
|
|
FDKmemclear(harmFlagsPrevActive, ADD_HARMONICS_FLAGS_SIZE * sizeof(ULONG));
|
|
|
|
for (i = 0; i < nSfb; i++) {
|
|
|
|
ULONG maskSfb =
|
|
|
|
1 << bitcount; /* mask to extract addHarmonics flag of current Sfb */
|
|
|
|
|
|
|
|
if (*curFlags & maskSfb) { /* There is a sine in this band */
|
|
|
|
const int lsb = freqBandTable[0]; /* start of sbr range */
|
|
|
|
/* qmf band to which sine should be added */
|
|
|
|
const int qmfBand = (freqBandTable[i] + freqBandTable[i + 1]) >> 1;
|
|
|
|
const int qmfBandDiv32 = qmfBand >> 5;
|
|
|
|
const int maskQmfBand =
|
|
|
|
1 << (qmfBand &
|
|
|
|
31); /* mask to extract harmonic flag from prevFlags */
|
|
|
|
|
|
|
|
/* mapping of sfb with sine to a certain qmf band -> for harmFlagsPrev */
|
|
|
|
harmFlagsQmfBands[qmfBandDiv32] |= maskQmfBand;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*
|
2018-02-26 20:17:00 +01:00
|
|
|
If there was a sine in the last frame, let it continue from the first
|
|
|
|
envelope on else start at the transient position. Indexing of sineMapped
|
|
|
|
starts relative to lsb.
|
2012-07-11 10:15:24 -07:00
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
sineMapped[qmfBand - lsb] =
|
|
|
|
(harmFlagsPrev[qmfBandDiv32] & maskQmfBand) ? 0 : tranEnv;
|
|
|
|
if (sineMapped[qmfBand - lsb] < PVC_NTIMESLOT) {
|
|
|
|
harmFlagsPrevActive[qmfBandDiv32] |= maskQmfBand;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (bitcount-- == 0) {
|
|
|
|
bitcount = 31;
|
|
|
|
curFlags++;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
FDKmemcpy(harmFlagsPrev, harmFlagsQmfBands,
|
|
|
|
sizeof(ULONG) * ADD_HARMONICS_FLAGS_SIZE);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/*!
|
|
|
|
\brief Restore sineMapped of previous frame
|
|
|
|
|
|
|
|
For PVC it might happen that the PVC framing (always 0) is out of sync with
|
|
|
|
the SBR framing. The adding of additional harmonics is done based on the SBR
|
|
|
|
framing. If the SBR framing is trailing the PVC framing the sine mapping of
|
|
|
|
the previous SBR frame needs to be used for the overlapping time slots.
|
|
|
|
*/
|
|
|
|
/*static*/ void mapSineFlagsPvc(
|
|
|
|
UCHAR *freqBandTable, /*!< Band borders (there's only 1 flag per
|
|
|
|
band) */
|
|
|
|
int nSfb, /*!< Number of bands in the table */
|
|
|
|
ULONG *harmFlagsPrev, /*!< Packed addHarmonics of previous frame
|
|
|
|
(aligned to the MSB) */
|
|
|
|
ULONG *harmFlagsPrevActive, /*!< Packed sineMapped of previous
|
|
|
|
frame (aligned to the LSB) */
|
|
|
|
SCHAR *sineMapped, /*!< Resulting vector of sine start positions
|
|
|
|
for each QMF band */
|
|
|
|
int sinusoidalPos, /*!< sinusoidal position */
|
|
|
|
SCHAR *sinusoidalPosPrev, /*!< sinusoidal position of previous
|
|
|
|
frame */
|
|
|
|
int trailingSbrFrame) /*!< indication if the SBR framing is
|
|
|
|
trailing the PVC framing */
|
|
|
|
{
|
|
|
|
/* Reset the output vector first */
|
|
|
|
FDKmemset(sineMapped, 32, MAX_FREQ_COEFFS); /* 32 means 'no sine' */
|
|
|
|
|
|
|
|
if (trailingSbrFrame) {
|
|
|
|
/* restore sineMapped[] of previous frame */
|
|
|
|
int i;
|
|
|
|
const int lsb = freqBandTable[0];
|
|
|
|
const int usb = freqBandTable[nSfb];
|
|
|
|
for (i = lsb; i < usb; i++) {
|
|
|
|
const int qmfBandDiv32 = i >> 5;
|
|
|
|
const int maskQmfBand =
|
|
|
|
1 << (i & 31); /* mask to extract harmonic flag from prevFlags */
|
|
|
|
|
|
|
|
/* Two cases need to be distinguished ... */
|
|
|
|
if (harmFlagsPrevActive[qmfBandDiv32] & maskQmfBand) {
|
|
|
|
/* the sine mapping already started last PVC frame -> seamlessly
|
|
|
|
* continue */
|
|
|
|
sineMapped[i - lsb] = 0;
|
|
|
|
} else if (harmFlagsPrev[qmfBandDiv32] & maskQmfBand) {
|
|
|
|
/* sinusoidalPos of prev PVC frame was >= PVC_NTIMESLOT -> sine starts
|
|
|
|
* in this frame */
|
|
|
|
sineMapped[i - lsb] =
|
|
|
|
*sinusoidalPosPrev - PVC_NTIMESLOT; /* we are 16 sbr time slots
|
|
|
|
ahead of last frame now */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*sinusoidalPosPrev = sinusoidalPos;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Reduce gain-adjustment induced aliasing for real valued filterbank.
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
/*static*/ void aliasingReduction(
|
|
|
|
FIXP_DBL *degreeAlias, /*!< estimated aliasing for each QMF
|
|
|
|
channel */
|
|
|
|
ENV_CALC_NRGS *nrgs,
|
|
|
|
UCHAR *useAliasReduction, /*!< synthetic sine energy for each
|
|
|
|
subband, used as flag */
|
|
|
|
int noSubbands) /*!< number of QMF channels to process */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL *nrgGain = nrgs->nrgGain; /*!< subband gains to be modified */
|
|
|
|
SCHAR *nrgGain_e =
|
|
|
|
nrgs->nrgGain_e; /*!< subband gains to be modified (exponents) */
|
|
|
|
FIXP_DBL *nrgEst = nrgs->nrgEst; /*!< subband energy before amplification */
|
|
|
|
SCHAR *nrgEst_e =
|
|
|
|
nrgs->nrgEst_e; /*!< subband energy before amplification (exponents) */
|
2012-07-11 10:15:24 -07:00
|
|
|
int grouping = 0, index = 0, noGroups, k;
|
|
|
|
int groupVector[MAX_FREQ_COEFFS];
|
|
|
|
|
|
|
|
/* Calculate grouping*/
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = 0; k < noSubbands - 1; k++) {
|
|
|
|
if ((degreeAlias[k + 1] != FL2FXCONST_DBL(0.0f)) && useAliasReduction[k]) {
|
|
|
|
if (grouping == 0) {
|
2012-07-11 10:15:24 -07:00
|
|
|
groupVector[index++] = k;
|
|
|
|
grouping = 1;
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
if (groupVector[index - 1] + 3 == k) {
|
2012-07-11 10:15:24 -07:00
|
|
|
groupVector[index++] = k + 1;
|
|
|
|
grouping = 0;
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
if (grouping) {
|
|
|
|
if (useAliasReduction[k])
|
2012-07-11 10:15:24 -07:00
|
|
|
groupVector[index++] = k + 1;
|
|
|
|
else
|
|
|
|
groupVector[index++] = k;
|
|
|
|
grouping = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (grouping) {
|
2012-07-11 10:15:24 -07:00
|
|
|
groupVector[index++] = noSubbands;
|
|
|
|
}
|
|
|
|
noGroups = index >> 1;
|
|
|
|
|
|
|
|
/*Calculate new gain*/
|
2018-02-26 20:17:00 +01:00
|
|
|
for (int group = 0; group < noGroups; group++) {
|
|
|
|
FIXP_DBL nrgOrig = FL2FXCONST_DBL(
|
|
|
|
0.0f); /* Original signal energy in current group of bands */
|
|
|
|
SCHAR nrgOrig_e = 0;
|
|
|
|
FIXP_DBL nrgAmp = FL2FXCONST_DBL(
|
|
|
|
0.0f); /* Amplified signal energy in group (using current gains) */
|
|
|
|
SCHAR nrgAmp_e = 0;
|
|
|
|
FIXP_DBL nrgMod = FL2FXCONST_DBL(
|
|
|
|
0.0f); /* Signal energy in group when applying modified gains */
|
|
|
|
SCHAR nrgMod_e = 0;
|
|
|
|
FIXP_DBL groupGain; /* Total energy gain in group */
|
|
|
|
SCHAR groupGain_e;
|
|
|
|
FIXP_DBL compensation; /* Compensation factor for the energy change when
|
|
|
|
applying modified gains */
|
|
|
|
SCHAR compensation_e;
|
|
|
|
|
|
|
|
int startGroup = groupVector[2 * group];
|
|
|
|
int stopGroup = groupVector[2 * group + 1];
|
|
|
|
|
|
|
|
/* Calculate total energy in group before and after amplification with
|
|
|
|
* current gains: */
|
|
|
|
for (k = startGroup; k < stopGroup; k++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* Get original band energy */
|
|
|
|
FIXP_DBL tmp = nrgEst[k];
|
2018-02-26 20:17:00 +01:00
|
|
|
SCHAR tmp_e = nrgEst_e[k];
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
FDK_add_MantExp(tmp, tmp_e, nrgOrig, nrgOrig_e, &nrgOrig, &nrgOrig_e);
|
|
|
|
|
|
|
|
/* Multiply band energy with current gain */
|
2018-02-26 20:17:00 +01:00
|
|
|
tmp = fMult(tmp, nrgGain[k]);
|
2012-07-11 10:15:24 -07:00
|
|
|
tmp_e = tmp_e + nrgGain_e[k];
|
|
|
|
|
|
|
|
FDK_add_MantExp(tmp, tmp_e, nrgAmp, nrgAmp_e, &nrgAmp, &nrgAmp_e);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate total energy gain in group */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_divide_MantExp(nrgAmp, nrgAmp_e, nrgOrig, nrgOrig_e, &groupGain,
|
|
|
|
&groupGain_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = startGroup; k < stopGroup; k++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL tmp;
|
2018-02-26 20:17:00 +01:00
|
|
|
SCHAR tmp_e;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
FIXP_DBL alpha = degreeAlias[k];
|
|
|
|
if (k < noSubbands - 1) {
|
2018-02-26 20:17:00 +01:00
|
|
|
if (degreeAlias[k + 1] > alpha) alpha = degreeAlias[k + 1];
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Modify gain depending on the degree of aliasing */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_add_MantExp(
|
|
|
|
fMult(alpha, groupGain), groupGain_e,
|
|
|
|
fMult(/*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL - alpha,
|
|
|
|
nrgGain[k]),
|
|
|
|
nrgGain_e[k], &nrgGain[k], &nrgGain_e[k]);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Apply modified gain to original energy */
|
2018-02-26 20:17:00 +01:00
|
|
|
tmp = fMult(nrgGain[k], nrgEst[k]);
|
2012-07-11 10:15:24 -07:00
|
|
|
tmp_e = nrgGain_e[k] + nrgEst_e[k];
|
|
|
|
|
|
|
|
/* Accumulate energy with modified gains applied */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_add_MantExp(tmp, tmp_e, nrgMod, nrgMod_e, &nrgMod, &nrgMod_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Calculate compensation factor to retain the energy of the amplified
|
|
|
|
* signal */
|
|
|
|
FDK_divide_MantExp(nrgAmp, nrgAmp_e, nrgMod, nrgMod_e, &compensation,
|
|
|
|
&compensation_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Apply compensation factor to all gains of the group */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = startGroup; k < stopGroup; k++) {
|
|
|
|
nrgGain[k] = fMult(nrgGain[k], compensation);
|
2012-07-11 10:15:24 -07:00
|
|
|
nrgGain_e[k] = nrgGain_e[k] + compensation_e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
#define INTER_TES_SF_CHANGE 3
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
FIXP_DBL subsample_power_low[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
FIXP_DBL subsample_power_high[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
FIXP_DBL gain[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
SCHAR subsample_power_low_sf[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
SCHAR subsample_power_high_sf[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
} ITES_TEMP;
|
|
|
|
|
|
|
|
static void apply_inter_tes(FIXP_DBL **qmfReal, FIXP_DBL **qmfImag,
|
|
|
|
const QMF_SCALE_FACTOR *sbrScaleFactor,
|
|
|
|
const SCHAR exp[2], const int RATE,
|
|
|
|
const int startPos, const int stopPos,
|
|
|
|
const int lowSubband, const int nbSubband,
|
|
|
|
const UCHAR gamma_idx) {
|
|
|
|
int highSubband = lowSubband + nbSubband;
|
|
|
|
FIXP_DBL *subsample_power_high, *subsample_power_low;
|
|
|
|
SCHAR *subsample_power_high_sf, *subsample_power_low_sf;
|
|
|
|
FIXP_DBL total_power_high = (FIXP_DBL)0;
|
|
|
|
FIXP_DBL total_power_low = (FIXP_DBL)0;
|
|
|
|
FIXP_DBL *gain;
|
|
|
|
int gain_sf[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
|
|
|
|
/* gamma[gamma_idx] = {0.0f, 1.0f, 2.0f, 4.0f} */
|
|
|
|
int gamma_sf =
|
|
|
|
(int)gamma_idx - 1; /* perhaps +1 to save one bit? (0.99999f vs 1.f) */
|
|
|
|
|
|
|
|
int nbSubsample = stopPos - startPos;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
C_ALLOC_SCRATCH_START(pTmp, ITES_TEMP, 1);
|
|
|
|
subsample_power_high = pTmp->subsample_power_high;
|
|
|
|
subsample_power_low = pTmp->subsample_power_low;
|
|
|
|
subsample_power_high_sf = pTmp->subsample_power_high_sf;
|
|
|
|
subsample_power_low_sf = pTmp->subsample_power_low_sf;
|
|
|
|
gain = pTmp->gain;
|
|
|
|
|
|
|
|
if (gamma_idx > 0) {
|
|
|
|
int preShift2 = 32 - fNormz((FIXP_DBL)nbSubsample);
|
|
|
|
int total_power_low_sf = 1 - DFRACT_BITS;
|
|
|
|
int total_power_high_sf = 1 - DFRACT_BITS;
|
|
|
|
|
|
|
|
for (i = 0; i < nbSubsample; ++i) {
|
|
|
|
FIXP_DBL bufferReal[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
FIXP_DBL bufferImag[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
FIXP_DBL maxVal = (FIXP_DBL)0;
|
|
|
|
|
|
|
|
int ts = startPos + i;
|
|
|
|
|
|
|
|
int low_sf = (ts < 3 * RATE) ? sbrScaleFactor->ov_lb_scale
|
|
|
|
: sbrScaleFactor->lb_scale;
|
|
|
|
low_sf = 15 - low_sf;
|
|
|
|
|
|
|
|
for (j = 0; j < lowSubband; ++j) {
|
|
|
|
bufferImag[j] = qmfImag[startPos + i][j];
|
|
|
|
maxVal |= (FIXP_DBL)((LONG)(bufferImag[j]) ^
|
|
|
|
((LONG)bufferImag[j] >> (DFRACT_BITS - 1)));
|
|
|
|
bufferReal[j] = qmfReal[startPos + i][j];
|
|
|
|
maxVal |= (FIXP_DBL)((LONG)(bufferReal[j]) ^
|
|
|
|
((LONG)bufferReal[j] >> (DFRACT_BITS - 1)));
|
|
|
|
}
|
|
|
|
|
|
|
|
subsample_power_low[i] = (FIXP_DBL)0;
|
|
|
|
subsample_power_low_sf[i] = 0;
|
|
|
|
|
|
|
|
if (maxVal != FL2FXCONST_DBL(0.f)) {
|
|
|
|
/* multiply first, then shift for safe summation */
|
|
|
|
int preShift = 1 - CntLeadingZeros(maxVal);
|
|
|
|
int postShift = 32 - fNormz((FIXP_DBL)lowSubband);
|
|
|
|
|
|
|
|
/* reduce preShift because otherwise we risk to square -1.f */
|
|
|
|
if (preShift != 0) preShift++;
|
|
|
|
|
|
|
|
subsample_power_low_sf[i] += (low_sf + preShift) * 2 + postShift + 1;
|
|
|
|
|
|
|
|
scaleValues(bufferReal, lowSubband, -preShift);
|
|
|
|
scaleValues(bufferImag, lowSubband, -preShift);
|
|
|
|
for (j = 0; j < lowSubband; ++j) {
|
|
|
|
FIXP_DBL addme;
|
|
|
|
addme = fPow2Div2(bufferReal[j]);
|
|
|
|
subsample_power_low[i] += addme >> postShift;
|
|
|
|
addme = fPow2Div2(bufferImag[j]);
|
|
|
|
subsample_power_low[i] += addme >> postShift;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now get high */
|
|
|
|
|
|
|
|
maxVal = (FIXP_DBL)0;
|
|
|
|
|
|
|
|
int high_sf = exp[(ts < 16 * RATE) ? 0 : 1];
|
|
|
|
|
|
|
|
for (j = lowSubband; j < highSubband; ++j) {
|
|
|
|
bufferImag[j] = qmfImag[startPos + i][j];
|
|
|
|
maxVal |= (FIXP_DBL)((LONG)(bufferImag[j]) ^
|
|
|
|
((LONG)bufferImag[j] >> (DFRACT_BITS - 1)));
|
|
|
|
bufferReal[j] = qmfReal[startPos + i][j];
|
|
|
|
maxVal |= (FIXP_DBL)((LONG)(bufferReal[j]) ^
|
|
|
|
((LONG)bufferReal[j] >> (DFRACT_BITS - 1)));
|
|
|
|
}
|
|
|
|
|
|
|
|
subsample_power_high[i] = (FIXP_DBL)0;
|
|
|
|
subsample_power_high_sf[i] = 0;
|
|
|
|
|
|
|
|
if (maxVal != FL2FXCONST_DBL(0.f)) {
|
|
|
|
int preShift = 1 - CntLeadingZeros(maxVal);
|
|
|
|
/* reduce preShift because otherwise we risk to square -1.f */
|
|
|
|
if (preShift != 0) preShift++;
|
|
|
|
|
|
|
|
int postShift = 32 - fNormz((FIXP_DBL)(highSubband - lowSubband));
|
|
|
|
subsample_power_high_sf[i] += (high_sf + preShift) * 2 + postShift + 1;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
scaleValues(&bufferReal[lowSubband], highSubband - lowSubband,
|
|
|
|
-preShift);
|
|
|
|
scaleValues(&bufferImag[lowSubband], highSubband - lowSubband,
|
|
|
|
-preShift);
|
|
|
|
for (j = lowSubband; j < highSubband; j++) {
|
|
|
|
subsample_power_high[i] += fPow2Div2(bufferReal[j]) >> postShift;
|
|
|
|
subsample_power_high[i] += fPow2Div2(bufferImag[j]) >> postShift;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sum all together */
|
|
|
|
FIXP_DBL new_summand = subsample_power_low[i];
|
|
|
|
int new_summand_sf = subsample_power_low_sf[i];
|
|
|
|
|
|
|
|
/* make sure the current sum, and the new summand have the same SF */
|
|
|
|
if (new_summand_sf > total_power_low_sf) {
|
|
|
|
int diff = fMin(DFRACT_BITS - 1, new_summand_sf - total_power_low_sf);
|
|
|
|
total_power_low >>= diff;
|
|
|
|
total_power_low_sf = new_summand_sf;
|
|
|
|
} else if (new_summand_sf < total_power_low_sf) {
|
|
|
|
new_summand >>= total_power_low_sf - new_summand_sf;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_power_low += (new_summand >> preShift2);
|
|
|
|
|
|
|
|
new_summand = subsample_power_high[i];
|
|
|
|
new_summand_sf = subsample_power_high_sf[i];
|
|
|
|
if (new_summand_sf > total_power_high_sf) {
|
|
|
|
total_power_high >>=
|
|
|
|
fMin(DFRACT_BITS - 1, new_summand_sf - total_power_high_sf);
|
|
|
|
total_power_high_sf = new_summand_sf;
|
|
|
|
} else if (new_summand_sf < total_power_high_sf) {
|
|
|
|
new_summand >>= total_power_high_sf - new_summand_sf;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_power_high += (new_summand >> preShift2);
|
|
|
|
}
|
|
|
|
|
|
|
|
total_power_low_sf += preShift2;
|
|
|
|
total_power_high_sf += preShift2;
|
|
|
|
|
|
|
|
/* gain[i] = e_LOW[i] */
|
|
|
|
for (i = 0; i < nbSubsample; ++i) {
|
|
|
|
int sf2;
|
|
|
|
FIXP_DBL mult =
|
|
|
|
fMultNorm(subsample_power_low[i], (FIXP_DBL)nbSubsample, &sf2);
|
|
|
|
int mult_sf = subsample_power_low_sf[i] + DFRACT_BITS - 1 + sf2;
|
|
|
|
|
|
|
|
if (total_power_low != FIXP_DBL(0)) {
|
|
|
|
gain[i] = fDivNorm(mult, total_power_low, &sf2);
|
|
|
|
gain_sf[i] = mult_sf - total_power_low_sf + sf2;
|
|
|
|
gain[i] = sqrtFixp_lookup(gain[i], &gain_sf[i]);
|
|
|
|
if (gain_sf[i] < 0) {
|
|
|
|
gain[i] >>= -gain_sf[i];
|
|
|
|
gain_sf[i] = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (mult == FIXP_DBL(0)) {
|
|
|
|
gain[i] = FIXP_DBL(0);
|
|
|
|
gain_sf[i] = 0;
|
|
|
|
} else {
|
|
|
|
gain[i] = (FIXP_DBL)MAXVAL_DBL;
|
|
|
|
gain_sf[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FIXP_DBL total_power_high_after = (FIXP_DBL)0;
|
|
|
|
int total_power_high_after_sf = 1 - DFRACT_BITS;
|
|
|
|
|
|
|
|
/* gain[i] = g_inter[i] */
|
|
|
|
for (i = 0; i < nbSubsample; ++i) {
|
|
|
|
if (gain_sf[i] < 0) {
|
|
|
|
gain[i] >>= -gain_sf[i];
|
|
|
|
gain_sf[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate: gain[i] = 1.0f + gamma * (gain[i] - 1.0f); */
|
|
|
|
FIXP_DBL one = (FIXP_DBL)MAXVAL_DBL >>
|
|
|
|
gain_sf[i]; /* to substract this from gain[i] */
|
|
|
|
|
|
|
|
/* gamma is actually always 1 according to the table, so skip the
|
|
|
|
* fMultDiv2 */
|
|
|
|
FIXP_DBL mult = (gain[i] - one) >> 1;
|
|
|
|
int mult_sf = gain_sf[i] + gamma_sf;
|
|
|
|
|
|
|
|
one = FL2FXCONST_DBL(0.5f) >> mult_sf;
|
|
|
|
gain[i] = one + mult;
|
|
|
|
gain_sf[i] += gamma_sf + 1; /* +1 because of fMultDiv2() */
|
|
|
|
|
|
|
|
/* set gain to at least 0.2f */
|
|
|
|
FIXP_DBL point_two = FL2FXCONST_DBL(0.8f); /* scaled up by 2 */
|
|
|
|
int point_two_sf = -2;
|
|
|
|
|
|
|
|
FIXP_DBL tmp = gain[i];
|
|
|
|
if (point_two_sf < gain_sf[i]) {
|
|
|
|
point_two >>= gain_sf[i] - point_two_sf;
|
|
|
|
} else {
|
|
|
|
tmp >>= point_two_sf - gain_sf[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* limit and calculate gain[i]^2 too */
|
|
|
|
FIXP_DBL gain_pow2;
|
|
|
|
int gain_pow2_sf;
|
|
|
|
if (tmp < point_two) {
|
|
|
|
gain[i] = FL2FXCONST_DBL(0.8f);
|
|
|
|
gain_sf[i] = -2;
|
|
|
|
gain_pow2 = FL2FXCONST_DBL(0.64f);
|
|
|
|
gain_pow2_sf = -4;
|
|
|
|
} else {
|
|
|
|
/* this upscaling seems quite important */
|
|
|
|
int r = CountLeadingBits(gain[i]);
|
|
|
|
gain[i] <<= r;
|
|
|
|
gain_sf[i] -= r;
|
|
|
|
|
|
|
|
gain_pow2 = fPow2(gain[i]);
|
|
|
|
gain_pow2_sf = gain_sf[i] << 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int room;
|
|
|
|
subsample_power_high[i] =
|
|
|
|
fMultNorm(subsample_power_high[i], gain_pow2, &room);
|
|
|
|
subsample_power_high_sf[i] =
|
|
|
|
subsample_power_high_sf[i] + gain_pow2_sf + room;
|
|
|
|
|
|
|
|
int new_summand_sf = subsample_power_high_sf[i]; /* + gain_pow2_sf; */
|
|
|
|
if (new_summand_sf > total_power_high_after_sf) {
|
|
|
|
total_power_high_after >>=
|
|
|
|
fMin(DFRACT_BITS - 1, new_summand_sf - total_power_high_after_sf);
|
|
|
|
total_power_high_after_sf = new_summand_sf;
|
|
|
|
} else if (new_summand_sf < total_power_high_after_sf) {
|
|
|
|
subsample_power_high[i] >>= total_power_high_after_sf - new_summand_sf;
|
|
|
|
}
|
|
|
|
total_power_high_after += subsample_power_high[i] >> preShift2;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_power_high_after_sf += preShift2;
|
|
|
|
|
|
|
|
int sf2 = 0;
|
|
|
|
FIXP_DBL gain_adj_2 = FL2FX_DBL(0.5f);
|
|
|
|
int gain_adj_2_sf = 1;
|
|
|
|
|
|
|
|
if ((total_power_high != (FIXP_DBL)0) &&
|
|
|
|
(total_power_high_after != (FIXP_DBL)0)) {
|
|
|
|
gain_adj_2 = fDivNorm(total_power_high, total_power_high_after, &sf2);
|
|
|
|
gain_adj_2_sf = total_power_high_sf - total_power_high_after_sf + sf2;
|
|
|
|
}
|
|
|
|
|
|
|
|
FIXP_DBL gain_adj = sqrtFixp_lookup(gain_adj_2, &gain_adj_2_sf);
|
|
|
|
int gain_adj_sf = gain_adj_2_sf;
|
|
|
|
|
|
|
|
for (i = 0; i < nbSubsample; ++i) {
|
|
|
|
gain[i] = fMult(gain[i], gain_adj);
|
|
|
|
gain_sf[i] += gain_adj_sf;
|
|
|
|
|
|
|
|
/* limit gain */
|
|
|
|
if (gain_sf[i] > INTER_TES_SF_CHANGE) {
|
|
|
|
gain[i] = (FIXP_DBL)MAXVAL_DBL;
|
|
|
|
gain_sf[i] = INTER_TES_SF_CHANGE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nbSubsample; ++i) {
|
|
|
|
/* equalize gain[]'s scale factors */
|
|
|
|
gain[i] >>= INTER_TES_SF_CHANGE - gain_sf[i];
|
|
|
|
|
|
|
|
for (j = lowSubband; j < highSubband; j++) {
|
|
|
|
qmfReal[startPos + i][j] = fMult(qmfReal[startPos + i][j], gain[i]);
|
|
|
|
qmfImag[startPos + i][j] = fMult(qmfImag[startPos + i][j], gain[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { /* gamma_idx == 0 */
|
|
|
|
/* Inter-TES is not active. Still perform the scale change to have a
|
|
|
|
* consistent scaling for all envelopes of this frame. */
|
|
|
|
for (i = 0; i < nbSubsample; ++i) {
|
|
|
|
for (j = lowSubband; j < highSubband; j++) {
|
|
|
|
qmfReal[startPos + i][j] >>= INTER_TES_SF_CHANGE;
|
|
|
|
qmfImag[startPos + i][j] >>= INTER_TES_SF_CHANGE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
C_ALLOC_SCRATCH_END(pTmp, ITES_TEMP, 1);
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Apply spectral envelope to subband samples
|
|
|
|
|
|
|
|
This function is called from sbr_dec.cpp in each frame.
|
|
|
|
|
|
|
|
To enhance accuracy and due to the usage of tables for squareroots and
|
|
|
|
inverse, some calculations are performed with the operands being split
|
|
|
|
into mantissa and exponent. The variable names in the source code carry
|
|
|
|
the suffixes <em>_m</em> and <em>_e</em> respectively. The control data
|
|
|
|
in #hFrameData containts envelope data which is represented by this format but
|
|
|
|
stored in single words. (See requantizeEnvelopeData() for details). This data
|
2018-02-26 20:17:00 +01:00
|
|
|
is unpacked within calculateSbrEnvelope() to follow the described suffix
|
|
|
|
convention.
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
The actual value (comparable to the corresponding float-variable in the
|
|
|
|
research-implementation) of a mantissa/exponent-pair can be calculated as
|
|
|
|
|
|
|
|
\f$ value = value\_m * 2^{value\_e} \f$
|
|
|
|
|
|
|
|
All energies and noise levels decoded from the bitstream suit for an
|
2018-02-26 20:17:00 +01:00
|
|
|
original signal magnitude of \f$\pm 32768 \f$ rather than \f$ \pm 1\f$.
|
|
|
|
Therefore, the scale factor <em>hb_scale</em> passed into this function will
|
|
|
|
be converted to an 'input exponent' (#input_e), which fits the internal
|
|
|
|
representation.
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
Before the actual processing, an exponent #adj_e for resulting adjusted
|
|
|
|
samples is derived from the maximum reference energy.
|
|
|
|
|
|
|
|
Then, for each envelope, the following steps are performed:
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
\li Calculate energy in the signal to be adjusted. Depending on the the value
|
|
|
|
of #interpolFreq (interpolation mode), this is either done seperately for each
|
|
|
|
QMF-subband or for each SBR-band. The resulting energies are stored in
|
|
|
|
#nrgEst_m[#MAX_FREQ_COEFFS] (mantissas) and #nrgEst_e[#MAX_FREQ_COEFFS]
|
|
|
|
(exponents). \li Calculate gain and noise level for each subband:<br> \f$ gain
|
|
|
|
= \sqrt{ \frac{nrgRef}{nrgEst} \cdot (1 - noiseRatio) } \hspace{2cm} noise =
|
|
|
|
\sqrt{ nrgRef \cdot noiseRatio } \f$<br> where <em>noiseRatio</em> and
|
|
|
|
<em>nrgRef</em> are extracted from the bitstream and <em>nrgEst</em> is the
|
|
|
|
subband energy before adjustment. The resulting gains are stored in
|
|
|
|
#nrgGain_m[#MAX_FREQ_COEFFS] (mantissas) and #nrgGain_e[#MAX_FREQ_COEFFS]
|
|
|
|
(exponents), the noise levels are stored in #noiseLevel_m[#MAX_FREQ_COEFFS]
|
|
|
|
and #noiseLevel_e[#MAX_FREQ_COEFFS] (exponents). The sine levels are stored in
|
|
|
|
#nrgSine_m[#MAX_FREQ_COEFFS] and #nrgSine_e[#MAX_FREQ_COEFFS]. \li Noise
|
|
|
|
limiting: The gain for each subband is limited both absolutely and relatively
|
|
|
|
compared to the total gain over all subbands. \li Boost gain: Calculate and
|
|
|
|
apply boost factor for each limiter band in order to compensate for the energy
|
|
|
|
loss imposed by the limiting. \li Apply gains and add noise: The gains and
|
|
|
|
noise levels are applied to all timeslots of the current envelope. A short
|
|
|
|
FIR-filter (length 4 QMF-timeslots) can be used to smooth the sudden change at
|
|
|
|
the envelope borders. Each complex subband sample of the current timeslot is
|
|
|
|
multiplied by the smoothed gain, then random noise with the calculated level
|
|
|
|
is added.
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
\note
|
|
|
|
To reduce the stack size, some of the local arrays could be located within
|
|
|
|
the time output buffer. Of the 512 samples temporarily available there,
|
|
|
|
about half the size is already used by #SBR_FRAME_DATA. A pointer to the
|
2018-02-26 20:17:00 +01:00
|
|
|
remaining free memory could be supplied by an additional argument to
|
|
|
|
calculateSbrEnvelope() in sbr_dec:
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
\par
|
|
|
|
\code
|
|
|
|
calculateSbrEnvelope (&hSbrDec->sbrScaleFactor,
|
|
|
|
&hSbrDec->SbrCalculateEnvelope,
|
|
|
|
hHeaderData,
|
|
|
|
hFrameData,
|
|
|
|
QmfBufferReal,
|
|
|
|
QmfBufferImag,
|
2018-02-26 20:17:00 +01:00
|
|
|
timeOutPtr + sizeof(SBR_FRAME_DATA)/sizeof(Float) +
|
|
|
|
1); \endcode
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
\par
|
2018-02-26 20:17:00 +01:00
|
|
|
Within calculateSbrEnvelope(), some pointers could be defined instead of the
|
|
|
|
arrays #nrgRef_m, #nrgRef_e, #nrgEst_m, #nrgEst_e, #noiseLevel_m:
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
\par
|
|
|
|
\code
|
|
|
|
fract* nrgRef_m = timeOutPtr;
|
|
|
|
SCHAR* nrgRef_e = nrgRef_m + MAX_FREQ_COEFFS;
|
|
|
|
fract* nrgEst_m = nrgRef_e + MAX_FREQ_COEFFS;
|
|
|
|
SCHAR* nrgEst_e = nrgEst_m + MAX_FREQ_COEFFS;
|
|
|
|
fract* noiseLevel_m = nrgEst_e + MAX_FREQ_COEFFS;
|
|
|
|
\endcode
|
|
|
|
|
|
|
|
<br>
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
void calculateSbrEnvelope(
|
|
|
|
QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */
|
|
|
|
HANDLE_SBR_CALCULATE_ENVELOPE
|
|
|
|
h_sbr_cal_env, /*!< Handle to struct filled by the create-function */
|
|
|
|
HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
|
|
|
|
HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */
|
|
|
|
PVC_DYNAMIC_DATA *pPvcDynamicData,
|
|
|
|
FIXP_DBL *
|
|
|
|
*analysBufferReal, /*!< Real part of subband samples to be processed */
|
|
|
|
FIXP_DBL *
|
|
|
|
*analysBufferImag, /*!< Imag part of subband samples to be processed */
|
|
|
|
const int useLP,
|
|
|
|
FIXP_DBL *degreeAlias, /*!< Estimated aliasing for each QMF channel */
|
|
|
|
const UINT flags, const int frameErrorFlag) {
|
|
|
|
int c, i, i_stop, j, envNoise = 0;
|
|
|
|
UCHAR *borders = hFrameData->frameInfo.borders;
|
|
|
|
UCHAR *bordersPvc = hFrameData->frameInfo.pvcBorders;
|
|
|
|
int pvc_mode = pPvcDynamicData->pvc_mode;
|
|
|
|
int first_start =
|
|
|
|
((pvc_mode > 0) ? bordersPvc[0] : borders[0]) * hHeaderData->timeStep;
|
|
|
|
FIXP_SGL *noiseLevels = hFrameData->sbrNoiseFloorLevel;
|
2012-07-11 10:15:24 -07:00
|
|
|
HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData;
|
2018-02-26 20:17:00 +01:00
|
|
|
UCHAR **pFreqBandTable = hFreq->freqBandTable;
|
|
|
|
UCHAR *pFreqBandTableNoise = hFreq->freqBandTableNoise;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
int lowSubband = hFreq->lowSubband;
|
2012-07-11 10:15:24 -07:00
|
|
|
int highSubband = hFreq->highSubband;
|
2018-02-26 20:17:00 +01:00
|
|
|
int noSubbands = highSubband - lowSubband;
|
|
|
|
|
|
|
|
/* old high subband before headerchange
|
|
|
|
we asume no headerchange here */
|
|
|
|
int ov_highSubband = hFreq->highSubband;
|
|
|
|
|
|
|
|
int noNoiseBands = hFreq->nNfb;
|
|
|
|
UCHAR *noSubFrameBands = hFreq->nSfb;
|
|
|
|
int no_cols = hHeaderData->numberTimeSlots * hHeaderData->timeStep;
|
|
|
|
|
|
|
|
SCHAR sineMapped[MAX_FREQ_COEFFS];
|
|
|
|
SCHAR ov_adj_e = SCALE2EXP(sbrScaleFactor->ov_hb_scale);
|
|
|
|
SCHAR adj_e = 0;
|
|
|
|
SCHAR output_e;
|
|
|
|
SCHAR final_e = 0;
|
|
|
|
/* inter-TES is active in one or more envelopes of the current SBR frame */
|
|
|
|
const int iTES_enable = hFrameData->iTESactive;
|
|
|
|
const int iTES_scale_change = (iTES_enable) ? INTER_TES_SF_CHANGE : 0;
|
|
|
|
SCHAR maxGainLimit_e = (frameErrorFlag) ? MAX_GAIN_CONCEAL_EXP : MAX_GAIN_EXP;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
UCHAR smooth_length = 0;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_SGL *pIenv = hFrameData->iEnvelope;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
C_ALLOC_SCRATCH_START(useAliasReduction, UCHAR, 64)
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* if values differ we had a headerchange; if old highband is bigger then new
|
|
|
|
one we need to patch overlap-highband-scaling for this frame (see use of
|
|
|
|
ov_highSubband) as overlap contains higher frequency components which would
|
|
|
|
get lost */
|
|
|
|
if (hFreq->highSubband < hFreq->ov_highSubband) {
|
|
|
|
ov_highSubband = hFreq->ov_highSubband;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (pvc_mode > 0) {
|
|
|
|
if (hFrameData->frameInfo.bordersNoise[0] > bordersPvc[0]) {
|
|
|
|
/* noise envelope of previous frame is trailing into current PVC frame */
|
|
|
|
envNoise = -1;
|
|
|
|
noiseLevels = h_sbr_cal_env->prevSbrNoiseFloorLevel;
|
|
|
|
noNoiseBands = h_sbr_cal_env->prevNNfb;
|
|
|
|
noSubFrameBands = h_sbr_cal_env->prevNSfb;
|
|
|
|
lowSubband = h_sbr_cal_env->prevLoSubband;
|
|
|
|
highSubband = h_sbr_cal_env->prevHiSubband;
|
|
|
|
|
|
|
|
noSubbands = highSubband - lowSubband;
|
|
|
|
ov_highSubband = highSubband;
|
|
|
|
if (highSubband < h_sbr_cal_env->prev_ov_highSubband) {
|
|
|
|
ov_highSubband = h_sbr_cal_env->prev_ov_highSubband;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
pFreqBandTable[0] = h_sbr_cal_env->prevFreqBandTableLo;
|
|
|
|
pFreqBandTable[1] = h_sbr_cal_env->prevFreqBandTableHi;
|
|
|
|
pFreqBandTableNoise = h_sbr_cal_env->prevFreqBandTableNoise;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
mapSineFlagsPvc(pFreqBandTable[1], noSubFrameBands[1],
|
|
|
|
h_sbr_cal_env->harmFlagsPrev,
|
|
|
|
h_sbr_cal_env->harmFlagsPrevActive, sineMapped,
|
|
|
|
hFrameData->sinusoidal_position,
|
|
|
|
&h_sbr_cal_env->sinusoidal_positionPrev,
|
|
|
|
(borders[0] > bordersPvc[0]) ? 1 : 0);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
Extract sine flags for all QMF bands
|
|
|
|
*/
|
|
|
|
mapSineFlags(pFreqBandTable[1], noSubFrameBands[1],
|
|
|
|
hFrameData->addHarmonics, h_sbr_cal_env->harmFlagsPrev,
|
|
|
|
h_sbr_cal_env->harmFlagsPrevActive,
|
|
|
|
hFrameData->frameInfo.tranEnv, sineMapped);
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
Scan for maximum in bufferd noise levels.
|
|
|
|
This is needed in case that we had strong noise in the previous frame
|
|
|
|
which is smoothed into the current frame.
|
|
|
|
The resulting exponent is used as start value for the maximum search
|
|
|
|
in reference energies
|
|
|
|
*/
|
|
|
|
if (!useLP)
|
2018-02-26 20:17:00 +01:00
|
|
|
adj_e = h_sbr_cal_env->filtBufferNoise_e -
|
|
|
|
getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
Scan for maximum reference energy to be able
|
|
|
|
to select appropriate values for adj_e and final_e.
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
if (pvc_mode > 0) {
|
|
|
|
INT maxSfbNrg_e = pPvcDynamicData->predEsg_expMax;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Energy -> magnitude (sqrt halfens exponent) */
|
2018-02-26 20:17:00 +01:00
|
|
|
maxSfbNrg_e =
|
|
|
|
(maxSfbNrg_e + 1) >> 1; /* +1 to go safe (round to next higher int) */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Some safety margin is needed for 2 reasons:
|
|
|
|
- The signal energy is not equally spread over all subband samples in
|
|
|
|
a specific sfb of an envelope (Nrg could be too high by a factor of
|
|
|
|
envWidth * sfbWidth)
|
2018-02-26 20:17:00 +01:00
|
|
|
- Smoothing can smear high gains of the previous envelope into the
|
|
|
|
current
|
2012-07-11 10:15:24 -07:00
|
|
|
*/
|
|
|
|
maxSfbNrg_e += 6;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
adj_e = maxSfbNrg_e;
|
|
|
|
// final_e should not exist for PVC fixfix framing
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < hFrameData->frameInfo.nEnvelopes; i++) {
|
|
|
|
INT maxSfbNrg_e =
|
|
|
|
-FRACT_BITS + NRG_EXP_OFFSET; /* start value for maximum search */
|
|
|
|
|
|
|
|
/* Fetch frequency resolution for current envelope: */
|
|
|
|
for (j = noSubFrameBands[hFrameData->frameInfo.freqRes[i]]; j != 0; j--) {
|
|
|
|
maxSfbNrg_e = fixMax(maxSfbNrg_e, (INT)((LONG)(*pIenv++) & MASK_E));
|
|
|
|
}
|
|
|
|
maxSfbNrg_e -= NRG_EXP_OFFSET;
|
|
|
|
|
|
|
|
/* Energy -> magnitude (sqrt halfens exponent) */
|
|
|
|
maxSfbNrg_e =
|
|
|
|
(maxSfbNrg_e + 1) >> 1; /* +1 to go safe (round to next higher int) */
|
|
|
|
|
|
|
|
/* Some safety margin is needed for 2 reasons:
|
|
|
|
- The signal energy is not equally spread over all subband samples in
|
|
|
|
a specific sfb of an envelope (Nrg could be too high by a factor of
|
|
|
|
envWidth * sfbWidth)
|
|
|
|
- Smoothing can smear high gains of the previous envelope into the
|
|
|
|
current
|
|
|
|
*/
|
|
|
|
maxSfbNrg_e += 6;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (borders[i] < hHeaderData->numberTimeSlots)
|
|
|
|
/* This envelope affects timeslots that belong to the output frame */
|
|
|
|
adj_e = fMax(maxSfbNrg_e, adj_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (borders[i + 1] > hHeaderData->numberTimeSlots)
|
|
|
|
/* This envelope affects timeslots after the output frame */
|
|
|
|
final_e = fMax(maxSfbNrg_e, final_e);
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
Calculate adjustment factors and apply them for every envelope.
|
|
|
|
*/
|
|
|
|
pIenv = hFrameData->iEnvelope;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (pvc_mode > 0) {
|
|
|
|
/* iterate over SBR time slots starting with bordersPvc[i] */
|
|
|
|
i = bordersPvc[0]; /* usually 0; can be >0 if switching from legacy SBR to
|
|
|
|
PVC */
|
|
|
|
i_stop = PVC_NTIMESLOT;
|
|
|
|
FDK_ASSERT(bordersPvc[hFrameData->frameInfo.nEnvelopes] == PVC_NTIMESLOT);
|
|
|
|
} else {
|
|
|
|
/* iterate over SBR envelopes starting with 0 */
|
|
|
|
i = 0;
|
|
|
|
i_stop = hFrameData->frameInfo.nEnvelopes;
|
|
|
|
}
|
|
|
|
for (; i < i_stop; i++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
int k, noNoiseFlag;
|
2018-02-26 20:17:00 +01:00
|
|
|
SCHAR noise_e, input_e = SCALE2EXP(sbrScaleFactor->hb_scale);
|
2012-07-11 10:15:24 -07:00
|
|
|
C_ALLOC_SCRATCH_START(pNrgs, ENV_CALC_NRGS, 1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Helper variables.
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
int start_pos, stop_pos, freq_res;
|
|
|
|
if (pvc_mode > 0) {
|
|
|
|
start_pos =
|
|
|
|
hHeaderData->timeStep *
|
|
|
|
i; /* Start-position in time (subband sample) for current envelope. */
|
|
|
|
stop_pos = hHeaderData->timeStep * (i + 1); /* Stop-position in time
|
|
|
|
(subband sample) for
|
|
|
|
current envelope. */
|
|
|
|
freq_res =
|
|
|
|
hFrameData->frameInfo
|
|
|
|
.freqRes[0]; /* Frequency resolution for current envelope. */
|
|
|
|
FDK_ASSERT(
|
|
|
|
freq_res ==
|
|
|
|
hFrameData->frameInfo.freqRes[hFrameData->frameInfo.nEnvelopes - 1]);
|
|
|
|
} else {
|
|
|
|
start_pos = hHeaderData->timeStep *
|
|
|
|
borders[i]; /* Start-position in time (subband sample) for
|
|
|
|
current envelope. */
|
|
|
|
stop_pos = hHeaderData->timeStep *
|
|
|
|
borders[i + 1]; /* Stop-position in time (subband sample) for
|
|
|
|
current envelope. */
|
|
|
|
freq_res =
|
|
|
|
hFrameData->frameInfo
|
|
|
|
.freqRes[i]; /* Frequency resolution for current envelope. */
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Always fully initialize the temporary energy table. This prevents
|
|
|
|
negative energies and extreme gain factors in cases where the number of
|
|
|
|
limiter bands exceeds the number of subbands. The latter can be caused by
|
|
|
|
undetected bit errors and is tested by some streams from the
|
|
|
|
certification set. */
|
2012-07-11 10:15:24 -07:00
|
|
|
FDKmemclear(pNrgs, sizeof(ENV_CALC_NRGS));
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (pvc_mode > 0) {
|
|
|
|
/* get predicted energy values from PVC module */
|
|
|
|
expandPredEsg(pPvcDynamicData, i, (int)MAX_FREQ_COEFFS, pNrgs->nrgRef,
|
|
|
|
pNrgs->nrgRef_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (i == borders[0]) {
|
|
|
|
mapSineFlags(pFreqBandTable[1], noSubFrameBands[1],
|
|
|
|
hFrameData->addHarmonics, h_sbr_cal_env->harmFlagsPrev,
|
|
|
|
h_sbr_cal_env->harmFlagsPrevActive,
|
|
|
|
hFrameData->sinusoidal_position, sineMapped);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= hFrameData->frameInfo.bordersNoise[envNoise + 1]) {
|
|
|
|
if (envNoise >= 0) {
|
|
|
|
noiseLevels += noNoiseBands; /* The noise floor data is stored in a
|
|
|
|
row [noiseFloor1 noiseFloor2...].*/
|
|
|
|
} else {
|
|
|
|
/* leave trailing noise envelope of past frame */
|
|
|
|
noNoiseBands = hFreq->nNfb;
|
|
|
|
noSubFrameBands = hFreq->nSfb;
|
|
|
|
noiseLevels = hFrameData->sbrNoiseFloorLevel;
|
|
|
|
|
|
|
|
lowSubband = hFreq->lowSubband;
|
|
|
|
highSubband = hFreq->highSubband;
|
|
|
|
|
|
|
|
noSubbands = highSubband - lowSubband;
|
|
|
|
ov_highSubband = highSubband;
|
|
|
|
if (highSubband < hFreq->ov_highSubband) {
|
|
|
|
ov_highSubband = hFreq->ov_highSubband;
|
|
|
|
}
|
|
|
|
|
|
|
|
pFreqBandTable[0] = hFreq->freqBandTableLo;
|
|
|
|
pFreqBandTable[1] = hFreq->freqBandTableHi;
|
|
|
|
pFreqBandTableNoise = hFreq->freqBandTableNoise;
|
|
|
|
}
|
|
|
|
envNoise++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* If the start-pos of the current envelope equals the stop pos of the
|
|
|
|
current noise envelope, increase the pointer (i.e. choose the next
|
|
|
|
noise-floor).*/
|
|
|
|
if (borders[i] == hFrameData->frameInfo.bordersNoise[envNoise + 1]) {
|
|
|
|
noiseLevels += noNoiseBands; /* The noise floor data is stored in a row
|
|
|
|
[noiseFloor1 noiseFloor2...].*/
|
|
|
|
envNoise++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == hFrameData->frameInfo.tranEnv ||
|
|
|
|
i == h_sbr_cal_env->prevTranEnv) /* attack */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
|
|
|
noNoiseFlag = 1;
|
2018-02-26 20:17:00 +01:00
|
|
|
if (!useLP) smooth_length = 0; /* No smoothing on attacks! */
|
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
noNoiseFlag = 0;
|
|
|
|
if (!useLP)
|
2018-02-26 20:17:00 +01:00
|
|
|
smooth_length = (1 - hHeaderData->bs_data.smoothingLength)
|
|
|
|
<< 2; /* can become either 0 or 4 */
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Energy estimation in transposed highband.
|
|
|
|
*/
|
|
|
|
if (hHeaderData->bs_data.interpolFreq)
|
2018-02-26 20:17:00 +01:00
|
|
|
calcNrgPerSubband(analysBufferReal, (useLP) ? NULL : analysBufferImag,
|
|
|
|
lowSubband, highSubband, start_pos, stop_pos, input_e,
|
|
|
|
pNrgs->nrgEst, pNrgs->nrgEst_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
else
|
2018-02-26 20:17:00 +01:00
|
|
|
calcNrgPerSfb(analysBufferReal, (useLP) ? NULL : analysBufferImag,
|
|
|
|
noSubFrameBands[freq_res], pFreqBandTable[freq_res],
|
|
|
|
start_pos, stop_pos, input_e, pNrgs->nrgEst,
|
2012-07-11 10:15:24 -07:00
|
|
|
pNrgs->nrgEst_e);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Calculate subband gains
|
|
|
|
*/
|
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
UCHAR *table = pFreqBandTable[freq_res];
|
|
|
|
UCHAR *pUiNoise =
|
|
|
|
&pFreqBandTableNoise[1]; /*! Upper limit of the current noise floor
|
|
|
|
band. */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_SGL *pNoiseLevels = noiseLevels;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL tmpNoise =
|
|
|
|
FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M));
|
|
|
|
SCHAR tmpNoise_e =
|
|
|
|
(UCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
int cc = 0;
|
|
|
|
c = 0;
|
2018-02-26 20:17:00 +01:00
|
|
|
if (pvc_mode > 0) {
|
|
|
|
for (j = 0; j < noSubFrameBands[freq_res]; j++) {
|
|
|
|
UCHAR sinePresentFlag = 0;
|
|
|
|
int li = table[j];
|
|
|
|
int ui = table[j + 1];
|
|
|
|
|
|
|
|
for (k = li; k < ui; k++) {
|
|
|
|
sinePresentFlag |= (i >= sineMapped[cc]);
|
|
|
|
cc++;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = li; k < ui; k++) {
|
|
|
|
FIXP_DBL refNrg = pNrgs->nrgRef[k - lowSubband];
|
|
|
|
SCHAR refNrg_e = pNrgs->nrgRef_e[k - lowSubband];
|
|
|
|
|
|
|
|
if (k >= *pUiNoise) {
|
|
|
|
tmpNoise =
|
|
|
|
FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M));
|
|
|
|
tmpNoise_e =
|
|
|
|
(SCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET;
|
|
|
|
|
|
|
|
pUiNoise++;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_ASSERT(k >= lowSubband);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (useLP) useAliasReduction[k - lowSubband] = !sinePresentFlag;
|
|
|
|
|
|
|
|
pNrgs->nrgSine[c] = FL2FXCONST_DBL(0.0f);
|
|
|
|
pNrgs->nrgSine_e[c] = 0;
|
|
|
|
|
|
|
|
calcSubbandGain(refNrg, refNrg_e, pNrgs, c, tmpNoise, tmpNoise_e,
|
|
|
|
sinePresentFlag, i >= sineMapped[c], noNoiseFlag);
|
|
|
|
|
|
|
|
c++;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
for (j = 0; j < noSubFrameBands[freq_res]; j++) {
|
|
|
|
FIXP_DBL refNrg = FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pIenv) & MASK_M));
|
|
|
|
SCHAR refNrg_e = (SCHAR)((LONG)(*pIenv) & MASK_E) - NRG_EXP_OFFSET;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
UCHAR sinePresentFlag = 0;
|
|
|
|
int li = table[j];
|
|
|
|
int ui = table[j + 1];
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = li; k < ui; k++) {
|
|
|
|
sinePresentFlag |= (i >= sineMapped[cc]);
|
|
|
|
cc++;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = li; k < ui; k++) {
|
|
|
|
if (k >= *pUiNoise) {
|
|
|
|
tmpNoise =
|
|
|
|
FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M));
|
|
|
|
tmpNoise_e =
|
|
|
|
(SCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET;
|
|
|
|
|
|
|
|
pUiNoise++;
|
|
|
|
}
|
|
|
|
|
|
|
|
FDK_ASSERT(k >= lowSubband);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (useLP) useAliasReduction[k - lowSubband] = !sinePresentFlag;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
pNrgs->nrgSine[c] = FL2FXCONST_DBL(0.0f);
|
|
|
|
pNrgs->nrgSine_e[c] = 0;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
calcSubbandGain(refNrg, refNrg_e, pNrgs, c, tmpNoise, tmpNoise_e,
|
|
|
|
sinePresentFlag, i >= sineMapped[c], noNoiseFlag);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
pNrgs->nrgRef[c] = refNrg;
|
|
|
|
pNrgs->nrgRef_e[c] = refNrg_e;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
c++;
|
|
|
|
}
|
|
|
|
pIenv++;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Noise limiting
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (c = 0; c < hFreq->noLimiterBands; c++) {
|
|
|
|
FIXP_DBL sumRef, boostGain, maxGain;
|
|
|
|
FIXP_DBL accu = FL2FXCONST_DBL(0.0f);
|
2018-02-26 20:17:00 +01:00
|
|
|
SCHAR sumRef_e, boostGain_e, maxGain_e, accu_e = 0;
|
|
|
|
int maxGainLimGainSum_e = 0;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
calcAvgGain(pNrgs, hFreq->limiterBandTable[c],
|
|
|
|
hFreq->limiterBandTable[c + 1], &sumRef, &sumRef_e, &maxGain,
|
|
|
|
&maxGain_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Multiply maxGain with limiterGain: */
|
2018-02-26 20:17:00 +01:00
|
|
|
maxGain = fMult(
|
|
|
|
maxGain,
|
|
|
|
FDK_sbrDecoder_sbr_limGains_m[hHeaderData->bs_data.limiterGains]);
|
|
|
|
/* maxGain_e +=
|
|
|
|
* FDK_sbrDecoder_sbr_limGains_e[hHeaderData->bs_data.limiterGains]; */
|
|
|
|
/* The addition of maxGain_e and FDK_sbrDecoder_sbr_limGains_e[3] might
|
|
|
|
yield values greater than 127 which doesn't fit into an SCHAR! In these
|
|
|
|
rare situations limit maxGain_e to 127.
|
|
|
|
*/
|
|
|
|
maxGainLimGainSum_e =
|
|
|
|
maxGain_e +
|
|
|
|
FDK_sbrDecoder_sbr_limGains_e[hHeaderData->bs_data.limiterGains];
|
|
|
|
maxGain_e =
|
|
|
|
(maxGainLimGainSum_e > 127) ? (SCHAR)127 : (SCHAR)maxGainLimGainSum_e;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Scale mantissa of MaxGain into range between 0.5 and 1: */
|
|
|
|
if (maxGain == FL2FXCONST_DBL(0.0f))
|
|
|
|
maxGain_e = -FRACT_BITS;
|
|
|
|
else {
|
|
|
|
SCHAR charTemp = CountLeadingBits(maxGain);
|
|
|
|
maxGain_e -= charTemp;
|
2018-02-26 20:17:00 +01:00
|
|
|
maxGain <<= (int)charTemp;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (maxGain_e >= maxGainLimit_e) { /* upper limit (e.g. 96 dB) */
|
|
|
|
maxGain = FL2FXCONST_DBL(0.5f);
|
|
|
|
maxGain_e = maxGainLimit_e;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Every subband gain is compared to the scaled "average gain"
|
|
|
|
and limited if necessary: */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1];
|
|
|
|
k++) {
|
|
|
|
if ((pNrgs->nrgGain_e[k] > maxGain_e) ||
|
|
|
|
(pNrgs->nrgGain_e[k] == maxGain_e && pNrgs->nrgGain[k] > maxGain)) {
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL noiseAmp;
|
2018-02-26 20:17:00 +01:00
|
|
|
SCHAR noiseAmp_e;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_divide_MantExp(maxGain, maxGain_e, pNrgs->nrgGain[k],
|
|
|
|
pNrgs->nrgGain_e[k], &noiseAmp, &noiseAmp_e);
|
|
|
|
pNrgs->noiseLevel[k] = fMult(pNrgs->noiseLevel[k], noiseAmp);
|
2012-07-11 10:15:24 -07:00
|
|
|
pNrgs->noiseLevel_e[k] += noiseAmp_e;
|
2018-02-26 20:17:00 +01:00
|
|
|
pNrgs->nrgGain[k] = maxGain;
|
|
|
|
pNrgs->nrgGain_e[k] = maxGain_e;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -- Boost gain
|
|
|
|
Calculate and apply boost factor for each limiter band:
|
|
|
|
1. Check how much energy would be present when using the limited gain
|
|
|
|
2. Calculate boost factor by comparison with reference energy
|
|
|
|
3. Apply boost factor to compensate for the energy loss due to limiting
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1];
|
|
|
|
k++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* 1.a Add energy of adjusted signal (using preliminary gain) */
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL tmp = fMult(pNrgs->nrgGain[k], pNrgs->nrgEst[k]);
|
|
|
|
SCHAR tmp_e = pNrgs->nrgGain_e[k] + pNrgs->nrgEst_e[k];
|
2012-07-11 10:15:24 -07:00
|
|
|
FDK_add_MantExp(tmp, tmp_e, accu, accu_e, &accu, &accu_e);
|
|
|
|
|
|
|
|
/* 1.b Add sine energy (if present) */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (pNrgs->nrgSine[k] != FL2FXCONST_DBL(0.0f)) {
|
|
|
|
FDK_add_MantExp(pNrgs->nrgSine[k], pNrgs->nrgSine_e[k], accu, accu_e,
|
|
|
|
&accu, &accu_e);
|
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* 1.c Add noise energy (if present) */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (noNoiseFlag == 0) {
|
|
|
|
FDK_add_MantExp(pNrgs->noiseLevel[k], pNrgs->noiseLevel_e[k], accu,
|
|
|
|
accu_e, &accu, &accu_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 2.a Calculate ratio of wanted energy and accumulated energy */
|
|
|
|
if (accu == (FIXP_DBL)0) { /* If divisor is 0, limit quotient to +4 dB */
|
|
|
|
boostGain = FL2FXCONST_DBL(0.6279716f);
|
|
|
|
boostGain_e = 2;
|
|
|
|
} else {
|
|
|
|
INT div_e;
|
|
|
|
boostGain = fDivNorm(sumRef, accu, &div_e);
|
|
|
|
boostGain_e = sumRef_e - accu_e + div_e;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 2.b Result too high? --> Limit the boost factor to +4 dB */
|
2018-02-26 20:17:00 +01:00
|
|
|
if ((boostGain_e > 3) ||
|
|
|
|
(boostGain_e == 2 && boostGain > FL2FXCONST_DBL(0.6279716f)) ||
|
|
|
|
(boostGain_e == 3 && boostGain > FL2FXCONST_DBL(0.3139858f))) {
|
2012-07-11 10:15:24 -07:00
|
|
|
boostGain = FL2FXCONST_DBL(0.6279716f);
|
|
|
|
boostGain_e = 2;
|
|
|
|
}
|
|
|
|
/* 3. Multiply all signal components with the boost factor */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1];
|
|
|
|
k++) {
|
|
|
|
pNrgs->nrgGain[k] = fMultDiv2(pNrgs->nrgGain[k], boostGain);
|
2012-07-11 10:15:24 -07:00
|
|
|
pNrgs->nrgGain_e[k] = pNrgs->nrgGain_e[k] + boostGain_e + 1;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
pNrgs->nrgSine[k] = fMultDiv2(pNrgs->nrgSine[k], boostGain);
|
2012-07-11 10:15:24 -07:00
|
|
|
pNrgs->nrgSine_e[k] = pNrgs->nrgSine_e[k] + boostGain_e + 1;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
pNrgs->noiseLevel[k] = fMultDiv2(pNrgs->noiseLevel[k], boostGain);
|
2012-07-11 10:15:24 -07:00
|
|
|
pNrgs->noiseLevel_e[k] = pNrgs->noiseLevel_e[k] + boostGain_e + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* End of noise limiting */
|
|
|
|
|
|
|
|
if (useLP)
|
2018-02-26 20:17:00 +01:00
|
|
|
aliasingReduction(degreeAlias + lowSubband, pNrgs, useAliasReduction,
|
2012-07-11 10:15:24 -07:00
|
|
|
noSubbands);
|
|
|
|
|
|
|
|
/* For the timeslots within the range for the output frame,
|
|
|
|
use the same scale for the noise levels.
|
|
|
|
Drawback: If the envelope exceeds the frame border, the noise levels
|
|
|
|
will have to be rescaled later to fit final_e of
|
|
|
|
the gain-values.
|
|
|
|
*/
|
|
|
|
noise_e = (start_pos < no_cols) ? adj_e : final_e;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Convert energies to amplitude levels
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
FDK_sqrt_MantExp(&pNrgs->nrgSine[k], &pNrgs->nrgSine_e[k], &noise_e);
|
|
|
|
FDK_sqrt_MantExp(&pNrgs->nrgGain[k], &pNrgs->nrgGain_e[k],
|
|
|
|
&pNrgs->nrgGain_e[k]);
|
|
|
|
FDK_sqrt_MantExp(&pNrgs->noiseLevel[k], &pNrgs->noiseLevel_e[k],
|
|
|
|
&noise_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Apply calculated gains and adaptive noise
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* assembleHfSignals() */
|
|
|
|
{
|
|
|
|
int scale_change, sc_change;
|
|
|
|
FIXP_SGL smooth_ratio;
|
2018-02-26 20:17:00 +01:00
|
|
|
int filtBufferNoiseShift = 0;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Initialize smoothing buffers with the first valid values */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (h_sbr_cal_env->startUp) {
|
2012-07-11 10:15:24 -07:00
|
|
|
if (!useLP) {
|
|
|
|
h_sbr_cal_env->filtBufferNoise_e = noise_e;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e,
|
|
|
|
noSubbands * sizeof(SCHAR));
|
|
|
|
FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel,
|
|
|
|
noSubbands * sizeof(FIXP_DBL));
|
|
|
|
FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain,
|
|
|
|
noSubbands * sizeof(FIXP_DBL));
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
h_sbr_cal_env->startUp = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!useLP) {
|
2018-02-26 20:17:00 +01:00
|
|
|
equalizeFiltBufferExp(h_sbr_cal_env->filtBuffer, /* buffered */
|
|
|
|
h_sbr_cal_env->filtBuffer_e, /* buffered */
|
|
|
|
pNrgs->nrgGain, /* current */
|
|
|
|
pNrgs->nrgGain_e, /* current */
|
2012-07-11 10:15:24 -07:00
|
|
|
noSubbands);
|
|
|
|
|
|
|
|
/* Adapt exponent of buffered noise levels to the current exponent
|
|
|
|
so they can easily be smoothed */
|
2018-02-26 20:17:00 +01:00
|
|
|
if ((h_sbr_cal_env->filtBufferNoise_e - noise_e) >= 0) {
|
|
|
|
int shift = fixMin(DFRACT_BITS - 1,
|
|
|
|
(int)(h_sbr_cal_env->filtBufferNoise_e - noise_e));
|
|
|
|
for (k = 0; k < noSubbands; k++)
|
2012-07-11 10:15:24 -07:00
|
|
|
h_sbr_cal_env->filtBufferNoise[k] <<= shift;
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
int shift =
|
|
|
|
fixMin(DFRACT_BITS - 1,
|
|
|
|
-(int)(h_sbr_cal_env->filtBufferNoise_e - noise_e));
|
|
|
|
for (k = 0; k < noSubbands; k++)
|
2012-07-11 10:15:24 -07:00
|
|
|
h_sbr_cal_env->filtBufferNoise[k] >>= shift;
|
|
|
|
}
|
|
|
|
|
|
|
|
h_sbr_cal_env->filtBufferNoise_e = noise_e;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find best scaling! */
|
2018-02-26 20:17:00 +01:00
|
|
|
scale_change = -(DFRACT_BITS - 1);
|
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
scale_change = fixMax(scale_change, (int)pNrgs->nrgGain_e[k]);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
sc_change = (start_pos < no_cols) ? adj_e - input_e : final_e - input_e;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if ((scale_change - sc_change + 1) < 0)
|
|
|
|
scale_change -= (scale_change - sc_change + 1);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
scale_change = (scale_change - sc_change) + 1;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
int sc = scale_change - pNrgs->nrgGain_e[k] + (sc_change - 1);
|
|
|
|
pNrgs->nrgGain[k] >>= sc;
|
|
|
|
pNrgs->nrgGain_e[k] += sc;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!useLP) {
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
int sc =
|
|
|
|
scale_change - h_sbr_cal_env->filtBuffer_e[k] + (sc_change - 1);
|
2012-07-11 10:15:24 -07:00
|
|
|
h_sbr_cal_env->filtBuffer[k] >>= sc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (j = start_pos; j < stop_pos; j++) {
|
|
|
|
/* This timeslot is located within the first part of the processing
|
|
|
|
buffer and will be fed into the QMF-synthesis for the current frame.
|
2012-07-11 10:15:24 -07:00
|
|
|
adj_e - input_e
|
|
|
|
This timeslot will not yet be fed into the QMF so we do not care
|
|
|
|
about the adj_e.
|
|
|
|
sc_change = final_e - input_e
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
if ((j == no_cols) && (start_pos < no_cols)) {
|
|
|
|
int shift = (int)(noise_e - final_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
if (!useLP)
|
2018-02-26 20:17:00 +01:00
|
|
|
filtBufferNoiseShift = shift; /* shifting of
|
|
|
|
h_sbr_cal_env->filtBufferNoise[k]
|
|
|
|
will be applied in function
|
|
|
|
adjustTimeSlotHQ() */
|
|
|
|
if (shift >= 0) {
|
|
|
|
shift = fixMin(DFRACT_BITS - 1, shift);
|
|
|
|
for (k = 0; k < noSubbands; k++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
pNrgs->nrgSine[k] <<= shift;
|
2018-02-26 20:17:00 +01:00
|
|
|
pNrgs->noiseLevel[k] <<= shift;
|
2012-07-11 10:15:24 -07:00
|
|
|
/*
|
|
|
|
if (!useLP)
|
|
|
|
h_sbr_cal_env->filtBufferNoise[k] <<= shift;
|
|
|
|
*/
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
shift = fixMin(DFRACT_BITS - 1, -shift);
|
|
|
|
for (k = 0; k < noSubbands; k++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
pNrgs->nrgSine[k] >>= shift;
|
2018-02-26 20:17:00 +01:00
|
|
|
pNrgs->noiseLevel[k] >>= shift;
|
2012-07-11 10:15:24 -07:00
|
|
|
/*
|
|
|
|
if (!useLP)
|
|
|
|
h_sbr_cal_env->filtBufferNoise[k] >>= shift;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update noise scaling */
|
|
|
|
noise_e = final_e;
|
|
|
|
if (!useLP)
|
2018-02-26 20:17:00 +01:00
|
|
|
h_sbr_cal_env->filtBufferNoise_e =
|
|
|
|
noise_e; /* scaling value unused! */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* update gain buffer*/
|
|
|
|
sc_change -= (final_e - input_e);
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (sc_change < 0) {
|
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
pNrgs->nrgGain[k] >>= -sc_change;
|
|
|
|
pNrgs->nrgGain_e[k] += -sc_change;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
if (!useLP) {
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
h_sbr_cal_env->filtBuffer[k] >>= -sc_change;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
scale_change += sc_change;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
} /* if */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
if (!useLP) {
|
|
|
|
/* Prevent the smoothing filter from running on constant levels */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (j - start_pos < smooth_length)
|
|
|
|
smooth_ratio = FDK_sbrDecoder_sbr_smoothFilter[j - start_pos];
|
2012-07-11 10:15:24 -07:00
|
|
|
else
|
|
|
|
smooth_ratio = FL2FXCONST_SGL(0.0f);
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (iTES_enable) {
|
|
|
|
/* adjustTimeSlotHQ() without adding of additional harmonics */
|
|
|
|
adjustTimeSlotHQ_GainAndNoise(
|
|
|
|
&analysBufferReal[j][lowSubband],
|
|
|
|
&analysBufferImag[j][lowSubband], h_sbr_cal_env, pNrgs,
|
|
|
|
lowSubband, noSubbands, scale_change, smooth_ratio, noNoiseFlag,
|
|
|
|
filtBufferNoiseShift);
|
|
|
|
} else {
|
|
|
|
adjustTimeSlotHQ(&analysBufferReal[j][lowSubband],
|
|
|
|
&analysBufferImag[j][lowSubband], h_sbr_cal_env,
|
|
|
|
pNrgs, lowSubband, noSubbands, scale_change,
|
|
|
|
smooth_ratio, noNoiseFlag, filtBufferNoiseShift);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
FDK_ASSERT(!iTES_enable); /* not supported */
|
2016-04-08 12:05:12 -07:00
|
|
|
if (flags & SBRDEC_ELD_GRID) {
|
2018-02-26 20:17:00 +01:00
|
|
|
/* FDKmemset(analysBufferReal[j], 0, 64 * sizeof(FIXP_DBL)); */
|
|
|
|
adjustTimeSlot_EldGrid(&analysBufferReal[j][lowSubband], pNrgs,
|
|
|
|
&h_sbr_cal_env->harmIndex, lowSubband,
|
|
|
|
noSubbands, scale_change, noNoiseFlag,
|
|
|
|
&h_sbr_cal_env->phaseIndex,
|
|
|
|
EXP2SCALE(adj_e) - sbrScaleFactor->lb_scale);
|
|
|
|
} else {
|
|
|
|
adjustTimeSlotLC(&analysBufferReal[j][lowSubband], pNrgs,
|
|
|
|
&h_sbr_cal_env->harmIndex, lowSubband, noSubbands,
|
|
|
|
scale_change, noNoiseFlag,
|
|
|
|
&h_sbr_cal_env->phaseIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* In case the envelope spans accross the no_cols border both exponents
|
|
|
|
* are needed. */
|
|
|
|
/* nrgGain_e[0...(noSubbands-1)] are equalized by
|
|
|
|
* equalizeFiltBufferExp() */
|
|
|
|
pNrgs->exponent[(j < no_cols) ? 0 : 1] =
|
|
|
|
(SCHAR)((15 - sbrScaleFactor->hb_scale) + pNrgs->nrgGain_e[0] + 1 -
|
|
|
|
scale_change);
|
|
|
|
} /* for */
|
|
|
|
|
|
|
|
if (iTES_enable) {
|
|
|
|
apply_inter_tes(
|
|
|
|
analysBufferReal, /* pABufR, */
|
|
|
|
analysBufferImag, /* pABufI, */
|
|
|
|
sbrScaleFactor, pNrgs->exponent, hHeaderData->timeStep, start_pos,
|
|
|
|
stop_pos, lowSubband, noSubbands,
|
|
|
|
hFrameData
|
|
|
|
->interTempShapeMode[i] /* frameData->interTempShapeMode[env] */
|
|
|
|
);
|
|
|
|
|
|
|
|
/* add additional harmonics */
|
|
|
|
for (j = start_pos; j < stop_pos; j++) {
|
|
|
|
/* match exponent of additional harmonics to scale change of QMF data
|
|
|
|
* caused by apply_inter_tes() */
|
|
|
|
scale_change = 0;
|
|
|
|
|
|
|
|
if ((start_pos <= no_cols) && (stop_pos > no_cols)) {
|
|
|
|
/* Scaling of analysBuffers was potentially changed within this
|
|
|
|
envelope. The pNrgs->nrgSine_e match the second part of the
|
|
|
|
envelope. For (j<=no_cols) the exponent of the sine energies has
|
|
|
|
to be adapted. */
|
|
|
|
scale_change = pNrgs->exponent[1] - pNrgs->exponent[0];
|
2016-04-08 12:05:12 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
|
|
|
|
adjustTimeSlotHQ_AddHarmonics(
|
|
|
|
&analysBufferReal[j][lowSubband],
|
|
|
|
&analysBufferImag[j][lowSubband], h_sbr_cal_env, pNrgs,
|
|
|
|
lowSubband, noSubbands,
|
|
|
|
-iTES_scale_change + ((j < no_cols) ? scale_change : 0));
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
if (!useLP) {
|
|
|
|
/* Update time-smoothing-buffers for gains and noise levels
|
2018-02-26 20:17:00 +01:00
|
|
|
The gains and the noise values of the current envelope are copied
|
|
|
|
into the buffer. This has to be done at the end of each envelope as
|
|
|
|
the values are required for a smooth transition to the next envelope.
|
|
|
|
*/
|
|
|
|
FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain,
|
|
|
|
noSubbands * sizeof(FIXP_DBL));
|
|
|
|
FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e,
|
|
|
|
noSubbands * sizeof(SCHAR));
|
|
|
|
FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel,
|
|
|
|
noSubbands * sizeof(FIXP_DBL));
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
C_ALLOC_SCRATCH_END(pNrgs, ENV_CALC_NRGS, 1);
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* adapt adj_e to the scale change caused by apply_inter_tes() */
|
|
|
|
adj_e += iTES_scale_change;
|
|
|
|
|
2012-07-11 10:15:24 -07:00
|
|
|
/* Rescale output samples */
|
|
|
|
{
|
|
|
|
FIXP_DBL maxVal;
|
|
|
|
int ov_reserve, reserve;
|
|
|
|
|
|
|
|
/* Determine headroom in old adjusted samples */
|
2018-02-26 20:17:00 +01:00
|
|
|
maxVal =
|
|
|
|
maxSubbandSample(analysBufferReal, (useLP) ? NULL : analysBufferImag,
|
|
|
|
lowSubband, ov_highSubband, 0, first_start);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
ov_reserve = fNorm(maxVal);
|
|
|
|
|
|
|
|
/* Determine headroom in new adjusted samples */
|
2018-02-26 20:17:00 +01:00
|
|
|
maxVal =
|
|
|
|
maxSubbandSample(analysBufferReal, (useLP) ? NULL : analysBufferImag,
|
|
|
|
lowSubband, highSubband, first_start, no_cols);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
reserve = fNorm(maxVal);
|
|
|
|
|
|
|
|
/* Determine common output exponent */
|
2018-02-26 20:17:00 +01:00
|
|
|
output_e = fMax(ov_adj_e - ov_reserve, adj_e - reserve);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Rescale old samples */
|
2018-02-26 20:17:00 +01:00
|
|
|
rescaleSubbandSamples(analysBufferReal, (useLP) ? NULL : analysBufferImag,
|
|
|
|
lowSubband, ov_highSubband, 0, first_start,
|
|
|
|
ov_adj_e - output_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Rescale new samples */
|
2018-02-26 20:17:00 +01:00
|
|
|
rescaleSubbandSamples(analysBufferReal, (useLP) ? NULL : analysBufferImag,
|
|
|
|
lowSubband, highSubband, first_start, no_cols,
|
|
|
|
adj_e - output_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Update hb_scale */
|
|
|
|
sbrScaleFactor->hb_scale = EXP2SCALE(output_e);
|
|
|
|
|
|
|
|
/* Save the current final exponent for the next frame: */
|
2018-02-26 20:17:00 +01:00
|
|
|
/* adapt final_e to the scale change caused by apply_inter_tes() */
|
|
|
|
sbrScaleFactor->ov_hb_scale = EXP2SCALE(final_e + iTES_scale_change);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* We need to remember to the next frame that the transient
|
2012-07-11 10:15:24 -07:00
|
|
|
will occur in the first envelope (if tranEnv == nEnvelopes). */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (hFrameData->frameInfo.tranEnv == hFrameData->frameInfo.nEnvelopes)
|
2012-07-11 10:15:24 -07:00
|
|
|
h_sbr_cal_env->prevTranEnv = 0;
|
|
|
|
else
|
|
|
|
h_sbr_cal_env->prevTranEnv = -1;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (pvc_mode > 0) {
|
|
|
|
/* Not more than just the last noise envelope reaches into the next PVC
|
|
|
|
frame! This should be true because bs_noise_position is <= 15 */
|
|
|
|
FDK_ASSERT(hFrameData->frameInfo
|
|
|
|
.bordersNoise[hFrameData->frameInfo.nNoiseEnvelopes - 1] <
|
|
|
|
PVC_NTIMESLOT);
|
|
|
|
if (hFrameData->frameInfo
|
|
|
|
.bordersNoise[hFrameData->frameInfo.nNoiseEnvelopes] >
|
|
|
|
PVC_NTIMESLOT) {
|
|
|
|
FDK_ASSERT(noiseLevels ==
|
|
|
|
(hFrameData->sbrNoiseFloorLevel +
|
|
|
|
(hFrameData->frameInfo.nNoiseEnvelopes - 1) * noNoiseBands));
|
|
|
|
h_sbr_cal_env->prevNNfb = noNoiseBands;
|
|
|
|
|
|
|
|
h_sbr_cal_env->prevNSfb[0] = noSubFrameBands[0];
|
|
|
|
h_sbr_cal_env->prevNSfb[1] = noSubFrameBands[1];
|
|
|
|
|
|
|
|
h_sbr_cal_env->prevLoSubband = lowSubband;
|
|
|
|
h_sbr_cal_env->prevHiSubband = highSubband;
|
|
|
|
h_sbr_cal_env->prev_ov_highSubband = ov_highSubband;
|
|
|
|
|
|
|
|
FDKmemcpy(h_sbr_cal_env->prevFreqBandTableLo, pFreqBandTable[0],
|
|
|
|
noSubFrameBands[0] + 1);
|
|
|
|
FDKmemcpy(h_sbr_cal_env->prevFreqBandTableHi, pFreqBandTable[1],
|
|
|
|
noSubFrameBands[1] + 1);
|
|
|
|
FDKmemcpy(h_sbr_cal_env->prevFreqBandTableNoise,
|
|
|
|
hFreq->freqBandTableNoise, sizeof(hFreq->freqBandTableNoise));
|
|
|
|
|
|
|
|
FDKmemcpy(h_sbr_cal_env->prevSbrNoiseFloorLevel, noiseLevels,
|
|
|
|
MAX_NOISE_COEFFS * sizeof(FIXP_SGL));
|
|
|
|
}
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
C_ALLOC_SCRATCH_END(useAliasReduction, UCHAR, 64)
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Create envelope instance
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
Must be called once for each channel before calculateSbrEnvelope() can be
|
|
|
|
used.
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
\return errorCode, 0 if successful
|
|
|
|
*/
|
|
|
|
SBR_ERROR
|
2018-02-26 20:17:00 +01:00
|
|
|
createSbrEnvelopeCalc(
|
|
|
|
HANDLE_SBR_CALCULATE_ENVELOPE hs, /*!< pointer to envelope instance */
|
|
|
|
HANDLE_SBR_HEADER_DATA
|
|
|
|
hHeaderData, /*!< static SBR control data, initialized with defaults */
|
|
|
|
const int chan, /*!< Channel for which to assign buffers */
|
|
|
|
const UINT flags) {
|
2012-07-11 10:15:24 -07:00
|
|
|
SBR_ERROR err = SBRDEC_OK;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Clear previous missing harmonics flags */
|
2018-02-26 20:17:00 +01:00
|
|
|
for (i = 0; i < ADD_HARMONICS_FLAGS_SIZE; i++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
hs->harmFlagsPrev[i] = 0;
|
2018-02-26 20:17:00 +01:00
|
|
|
hs->harmFlagsPrevActive[i] = 0;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
hs->harmIndex = 0;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FDKmemclear(hs->prevSbrNoiseFloorLevel, sizeof(hs->prevSbrNoiseFloorLevel));
|
|
|
|
hs->prevNNfb = 0;
|
|
|
|
FDKmemclear(hs->prevFreqBandTableNoise, sizeof(hs->prevFreqBandTableNoise));
|
|
|
|
hs->sinusoidal_positionPrev = 0;
|
|
|
|
|
2012-07-11 10:15:24 -07:00
|
|
|
/*
|
|
|
|
Setup pointers for time smoothing.
|
|
|
|
The buffer itself will be initialized later triggered by the startUp-flag.
|
|
|
|
*/
|
|
|
|
hs->prevTranEnv = -1;
|
|
|
|
|
|
|
|
/* initialization */
|
|
|
|
resetSbrEnvelopeCalc(hs);
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (chan == 0) { /* do this only once */
|
2012-07-11 10:15:24 -07:00
|
|
|
err = resetFreqBandTables(hHeaderData, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Create envelope instance
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
Must be called once for each channel before calculateSbrEnvelope() can be
|
|
|
|
used.
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
\return errorCode, 0 if successful
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
int deleteSbrEnvelopeCalc(HANDLE_SBR_CALCULATE_ENVELOPE hs) { return 0; }
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Reset envelope instance
|
|
|
|
|
|
|
|
This function must be called for each channel on a change of configuration.
|
|
|
|
Note that resetFreqBandTables should also be called in this case.
|
|
|
|
|
|
|
|
\return errorCode, 0 if successful
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
void resetSbrEnvelopeCalc(
|
|
|
|
HANDLE_SBR_CALCULATE_ENVELOPE hCalEnv) /*!< pointer to envelope instance */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
|
|
|
hCalEnv->phaseIndex = 0;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Noise exponent needs to be reset because the output exponent for the next
|
|
|
|
* frame depends on it */
|
2012-07-11 10:15:24 -07:00
|
|
|
hCalEnv->filtBufferNoise_e = 0;
|
|
|
|
|
|
|
|
hCalEnv->startUp = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Equalize exponents of the buffered gain values and the new ones
|
|
|
|
|
|
|
|
After equalization of exponents, the FIR-filter addition for smoothing
|
|
|
|
can be performed.
|
|
|
|
This function is called once for each envelope before adjusting.
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
static void equalizeFiltBufferExp(
|
|
|
|
FIXP_DBL *filtBuffer, /*!< bufferd gains */
|
|
|
|
SCHAR *filtBuffer_e, /*!< exponents of bufferd gains */
|
|
|
|
FIXP_DBL *nrgGain, /*!< gains for current envelope */
|
|
|
|
SCHAR *nrgGain_e, /*!< exponents of gains for current envelope */
|
|
|
|
int subbands) /*!< Number of QMF subbands */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
int band;
|
|
|
|
int diff;
|
|
|
|
|
|
|
|
for (band = 0; band < subbands; band++) {
|
|
|
|
diff = (int)(nrgGain_e[band] - filtBuffer_e[band]);
|
|
|
|
if (diff > 0) {
|
|
|
|
filtBuffer[band] >>=
|
|
|
|
diff; /* Compensate for the scale change by shifting the mantissa. */
|
|
|
|
filtBuffer_e[band] += diff; /* New gain is bigger, use its exponent */
|
|
|
|
} else if (diff < 0) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* The buffered gains seem to be larger, but maybe there
|
|
|
|
are some unused bits left in the mantissa */
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
int reserve = CntLeadingZeros(fixp_abs(filtBuffer[band])) - 1;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
if ((-diff) <= reserve) {
|
|
|
|
/* There is enough space in the buffered mantissa so
|
|
|
|
that we can take the new exponent as common.
|
|
|
|
*/
|
|
|
|
filtBuffer[band] <<= (-diff);
|
2018-02-26 20:17:00 +01:00
|
|
|
filtBuffer_e[band] += diff; /* becomes equal to *ptrNewExp */
|
|
|
|
} else {
|
|
|
|
filtBuffer[band] <<=
|
|
|
|
reserve; /* Shift the mantissa as far as possible: */
|
|
|
|
filtBuffer_e[band] -= reserve; /* Compensate in the exponent: */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* For the remaining difference, change the new gain value */
|
2018-02-26 20:17:00 +01:00
|
|
|
diff = fixMin(-(reserve + diff), DFRACT_BITS - 1);
|
2012-07-11 10:15:24 -07:00
|
|
|
nrgGain[band] >>= diff;
|
|
|
|
nrgGain_e[band] += diff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Shift left the mantissas of all subband samples
|
|
|
|
in the giventime and frequency range by the specified number of bits.
|
|
|
|
|
|
|
|
This function is used to rescale the audio data in the overlap buffer
|
|
|
|
which has already been envelope adjusted with the last frame.
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
void rescaleSubbandSamples(
|
|
|
|
FIXP_DBL **re, /*!< Real part of input and output subband samples */
|
|
|
|
FIXP_DBL **im, /*!< Imaginary part of input and output subband samples */
|
|
|
|
int lowSubband, /*!< Begin of frequency range to process */
|
|
|
|
int highSubband, /*!< End of frequency range to process */
|
|
|
|
int start_pos, /*!< Begin of time rage (QMF-timeslot) */
|
|
|
|
int next_pos, /*!< End of time rage (QMF-timeslot) */
|
|
|
|
int shift) /*!< number of bits to shift */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
int width = highSubband - lowSubband;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if ((width > 0) && (shift != 0)) {
|
|
|
|
if (im != NULL) {
|
|
|
|
for (int l = start_pos; l < next_pos; l++) {
|
|
|
|
scaleValues(&re[l][lowSubband], width, shift);
|
|
|
|
scaleValues(&im[l][lowSubband], width, shift);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
for (int l = start_pos; l < next_pos; l++) {
|
|
|
|
scaleValues(&re[l][lowSubband], width, shift);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
static inline FIXP_DBL FDK_get_maxval_real(FIXP_DBL maxVal, FIXP_DBL *reTmp,
|
|
|
|
INT width) {
|
|
|
|
maxVal = (FIXP_DBL)0;
|
|
|
|
while (width-- != 0) {
|
|
|
|
FIXP_DBL tmp = *(reTmp++);
|
|
|
|
maxVal |= (FIXP_DBL)((LONG)(tmp) ^ ((LONG)tmp >> (DFRACT_BITS - 1)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return maxVal;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Determine headroom for shifting
|
|
|
|
|
|
|
|
Determine by how much the spectrum can be shifted left
|
|
|
|
for better accuracy in later processing.
|
|
|
|
|
|
|
|
\return Number of free bits in the biggest spectral value
|
|
|
|
*/
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL maxSubbandSample(
|
|
|
|
FIXP_DBL **re, /*!< Real part of input and output subband samples */
|
|
|
|
FIXP_DBL **im, /*!< Real part of input and output subband samples */
|
|
|
|
int lowSubband, /*!< Begin of frequency range to process */
|
|
|
|
int highSubband, /*!< Number of QMF bands to process */
|
|
|
|
int start_pos, /*!< Begin of time rage (QMF-timeslot) */
|
|
|
|
int next_pos /*!< End of time rage (QMF-timeslot) */
|
|
|
|
) {
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL maxVal = FL2FX_DBL(0.0f);
|
|
|
|
unsigned int width = highSubband - lowSubband;
|
|
|
|
|
|
|
|
FDK_ASSERT(width <= (64));
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (width > 0) {
|
|
|
|
if (im != NULL) {
|
|
|
|
for (int l = start_pos; l < next_pos; l++) {
|
|
|
|
int k = width;
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL *reTmp = &re[l][lowSubband];
|
|
|
|
FIXP_DBL *imTmp = &im[l][lowSubband];
|
2018-02-26 20:17:00 +01:00
|
|
|
do {
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL tmp1 = *(reTmp++);
|
|
|
|
FIXP_DBL tmp2 = *(imTmp++);
|
2018-02-26 20:17:00 +01:00
|
|
|
maxVal |=
|
|
|
|
(FIXP_DBL)((LONG)(tmp1) ^ ((LONG)tmp1 >> (DFRACT_BITS - 1)));
|
|
|
|
maxVal |=
|
|
|
|
(FIXP_DBL)((LONG)(tmp2) ^ ((LONG)tmp2 >> (DFRACT_BITS - 1)));
|
|
|
|
} while (--k != 0);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
for (int l = start_pos; l < next_pos; l++) {
|
|
|
|
maxVal |= FDK_get_maxval_real(maxVal, &re[l][lowSubband], width);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (maxVal > (FIXP_DBL)0) {
|
|
|
|
/* For negative input values, maxVal is too small by 1. Add 1 only when
|
|
|
|
* necessary: if maxVal is a power of 2 */
|
|
|
|
FIXP_DBL lowerPow2 =
|
|
|
|
(FIXP_DBL)(1 << (DFRACT_BITS - 1 - CntLeadingZeros(maxVal)));
|
|
|
|
if (maxVal == lowerPow2) maxVal += (FIXP_DBL)1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (maxVal);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* #define SHIFT_BEFORE_SQUARE (3) */ /* (7/2) */
|
|
|
|
/* Avoid assertion failures triggerd by overflows which occured in robustness
|
|
|
|
tests. Setting the SHIFT_BEFORE_SQUARE to 4 has negligible effect on (USAC)
|
|
|
|
conformance results. */
|
|
|
|
#define SHIFT_BEFORE_SQUARE (4) /* ((8 - 0) / 2) */
|
|
|
|
|
2012-07-11 10:15:24 -07:00
|
|
|
/*!<
|
|
|
|
If the accumulator does not provide enough overflow bits or
|
|
|
|
does not provide a high dynamic range, the below energy calculation
|
|
|
|
requires an additional shift operation for each sample.
|
|
|
|
On the other hand, doing the shift allows using a single-precision
|
|
|
|
multiplication for the square (at least 16bit x 16bit).
|
|
|
|
For even values of OVRFLW_BITS (0, 2, 4, 6), saturated arithmetic
|
|
|
|
is required for the energy accumulation.
|
|
|
|
Theoretically, the sample-squares can sum up to a value of 76,
|
|
|
|
requiring 7 overflow bits. However since such situations are *very*
|
|
|
|
rare, accu can be limited to 64.
|
|
|
|
In case native saturated arithmetic is not available, overflows
|
|
|
|
can be prevented by replacing the above #define by
|
|
|
|
#define SHIFT_BEFORE_SQUARE ((8 - OVRFLW_BITS) / 2)
|
|
|
|
which will result in slightly reduced accuracy.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Estimates the mean energy of each filter-bank channel for the
|
|
|
|
duration of the current envelope
|
|
|
|
|
|
|
|
This function is used when interpolFreq is true.
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
static void calcNrgPerSubband(
|
|
|
|
FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */
|
|
|
|
FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */
|
|
|
|
int lowSubband, /*!< Begin of the SBR frequency range */
|
|
|
|
int highSubband, /*!< High end of the SBR frequency range */
|
|
|
|
int start_pos, /*!< First QMF-slot of current envelope */
|
|
|
|
int next_pos, /*!< Last QMF-slot of current envelope + 1 */
|
|
|
|
SCHAR frameExp, /*!< Common exponent for all input samples */
|
|
|
|
FIXP_DBL *nrgEst, /*!< resulting Energy (0..1) */
|
|
|
|
SCHAR *nrgEst_e) /*!< Exponent of resulting Energy */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
|
|
|
FIXP_SGL invWidth;
|
2018-02-26 20:17:00 +01:00
|
|
|
SCHAR preShift;
|
|
|
|
SCHAR shift;
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL sum;
|
2018-02-26 20:17:00 +01:00
|
|
|
int k;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Divide by width of envelope later: */
|
|
|
|
invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos));
|
2018-02-26 20:17:00 +01:00
|
|
|
/* The common exponent needs to be doubled because all mantissas are squared:
|
|
|
|
*/
|
2012-07-11 10:15:24 -07:00
|
|
|
frameExp = frameExp << 1;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = lowSubband; k < highSubband; k++) {
|
|
|
|
FIXP_DBL bufferReal[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
FIXP_DBL bufferImag[(((1024) / (32) * (4) / 2) + (3 * (4)))];
|
|
|
|
FIXP_DBL maxVal;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (analysBufferImag != NULL) {
|
|
|
|
int l;
|
|
|
|
maxVal = FL2FX_DBL(0.0f);
|
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
bufferImag[l] = analysBufferImag[l][k];
|
2018-02-26 20:17:00 +01:00
|
|
|
maxVal |= (FIXP_DBL)((LONG)(bufferImag[l]) ^
|
|
|
|
((LONG)bufferImag[l] >> (DFRACT_BITS - 1)));
|
2012-07-11 10:15:24 -07:00
|
|
|
bufferReal[l] = analysBufferReal[l][k];
|
2018-02-26 20:17:00 +01:00
|
|
|
maxVal |= (FIXP_DBL)((LONG)(bufferReal[l]) ^
|
|
|
|
((LONG)bufferReal[l] >> (DFRACT_BITS - 1)));
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
int l;
|
|
|
|
maxVal = FL2FX_DBL(0.0f);
|
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
bufferReal[l] = analysBufferReal[l][k];
|
2018-02-26 20:17:00 +01:00
|
|
|
maxVal |= (FIXP_DBL)((LONG)(bufferReal[l]) ^
|
|
|
|
((LONG)bufferReal[l] >> (DFRACT_BITS - 1)));
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (maxVal != FL2FXCONST_DBL(0.f)) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* If the accu does not provide enough overflow bits, we cannot
|
|
|
|
shift the samples up to the limit.
|
|
|
|
Instead, keep up to 3 free bits in each sample, i.e. up to
|
|
|
|
6 bits after calculation of square.
|
|
|
|
Please note the comment on saturated arithmetic above!
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL accu;
|
|
|
|
preShift = CntLeadingZeros(maxVal) - 1;
|
2012-07-11 10:15:24 -07:00
|
|
|
preShift -= SHIFT_BEFORE_SQUARE;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Limit preShift to a maximum value to prevent accumulator overflow in
|
|
|
|
exceptional situations where the signal in the analysis-buffer is very
|
|
|
|
small (small maxVal).
|
|
|
|
*/
|
|
|
|
preShift = fMin(preShift, (SCHAR)25);
|
|
|
|
|
|
|
|
accu = FL2FXCONST_DBL(0.0f);
|
|
|
|
if (preShift >= 0) {
|
|
|
|
int l;
|
|
|
|
if (analysBufferImag != NULL) {
|
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL temp1 = bufferReal[l] << (int)preShift;
|
|
|
|
FIXP_DBL temp2 = bufferImag[l] << (int)preShift;
|
|
|
|
accu = fPow2AddDiv2(accu, temp1);
|
|
|
|
accu = fPow2AddDiv2(accu, temp2);
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL temp = bufferReal[l] << (int)preShift;
|
|
|
|
accu = fPow2AddDiv2(accu, temp);
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else { /* if negative shift value */
|
|
|
|
int l;
|
2012-07-11 10:15:24 -07:00
|
|
|
int negpreShift = -preShift;
|
2018-02-26 20:17:00 +01:00
|
|
|
if (analysBufferImag != NULL) {
|
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL temp1 = bufferReal[l] >> (int)negpreShift;
|
|
|
|
FIXP_DBL temp2 = bufferImag[l] >> (int)negpreShift;
|
|
|
|
accu = fPow2AddDiv2(accu, temp1);
|
|
|
|
accu = fPow2AddDiv2(accu, temp2);
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL temp = bufferReal[l] >> (int)negpreShift;
|
|
|
|
accu = fPow2AddDiv2(accu, temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
accu <<= 1;
|
|
|
|
|
|
|
|
/* Convert double precision to Mantissa/Exponent: */
|
|
|
|
shift = fNorm(accu);
|
|
|
|
sum = accu << (int)shift;
|
|
|
|
|
|
|
|
/* Divide by width of envelope and apply frame scale: */
|
|
|
|
*nrgEst++ = fMult(sum, invWidth);
|
|
|
|
shift += 2 * preShift;
|
2018-02-26 20:17:00 +01:00
|
|
|
if (analysBufferImag != NULL)
|
2012-07-11 10:15:24 -07:00
|
|
|
*nrgEst_e++ = frameExp - shift;
|
|
|
|
else
|
2018-02-26 20:17:00 +01:00
|
|
|
*nrgEst_e++ = frameExp - shift + 1; /* +1 due to missing imag. part */
|
|
|
|
} /* maxVal!=0 */
|
2012-07-11 10:15:24 -07:00
|
|
|
else {
|
|
|
|
/* Prevent a zero-mantissa-number from being misinterpreted
|
|
|
|
due to its exponent. */
|
|
|
|
*nrgEst++ = FL2FXCONST_DBL(0.0f);
|
|
|
|
*nrgEst_e++ = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Estimates the mean energy of each Scale factor band for the
|
|
|
|
duration of the current envelope.
|
|
|
|
|
|
|
|
This function is used when interpolFreq is false.
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
static void calcNrgPerSfb(
|
|
|
|
FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */
|
|
|
|
FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */
|
|
|
|
int nSfb, /*!< Number of scale factor bands */
|
|
|
|
UCHAR *freqBandTable, /*!< First Subband for each Sfb */
|
|
|
|
int start_pos, /*!< First QMF-slot of current envelope */
|
|
|
|
int next_pos, /*!< Last QMF-slot of current envelope + 1 */
|
|
|
|
SCHAR input_e, /*!< Common exponent for all input samples */
|
|
|
|
FIXP_DBL *nrgEst, /*!< resulting Energy (0..1) */
|
|
|
|
SCHAR *nrgEst_e) /*!< Exponent of resulting Energy */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_SGL invWidth;
|
|
|
|
FIXP_DBL temp;
|
|
|
|
SCHAR preShift;
|
|
|
|
SCHAR shift, sum_e;
|
|
|
|
FIXP_DBL sum;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
int j, k, l, li, ui;
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL sumAll, sumLine; /* Single precision would be sufficient,
|
|
|
|
but overflow bits are required for accumulation */
|
|
|
|
|
|
|
|
/* Divide by width of envelope later: */
|
|
|
|
invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos));
|
2018-02-26 20:17:00 +01:00
|
|
|
/* The common exponent needs to be doubled because all mantissas are squared:
|
|
|
|
*/
|
2012-07-11 10:15:24 -07:00
|
|
|
input_e = input_e << 1;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (j = 0; j < nSfb; j++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
li = freqBandTable[j];
|
2018-02-26 20:17:00 +01:00
|
|
|
ui = freqBandTable[j + 1];
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL maxVal = maxSubbandSample(analysBufferReal, analysBufferImag, li,
|
|
|
|
ui, start_pos, next_pos);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (maxVal != FL2FXCONST_DBL(0.f)) {
|
|
|
|
preShift = CntLeadingZeros(maxVal) - 1;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* If the accu does not provide enough overflow bits, we cannot
|
|
|
|
shift the samples up to the limit.
|
|
|
|
Instead, keep up to 3 free bits in each sample, i.e. up to
|
|
|
|
6 bits after calculation of square.
|
|
|
|
Please note the comment on saturated arithmetic above!
|
|
|
|
*/
|
|
|
|
preShift -= SHIFT_BEFORE_SQUARE;
|
|
|
|
|
|
|
|
sumAll = FL2FXCONST_DBL(0.0f);
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = li; k < ui; k++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
sumLine = FL2FXCONST_DBL(0.0f);
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (analysBufferImag != NULL) {
|
|
|
|
if (preShift >= 0) {
|
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
|
|
|
temp = analysBufferReal[l][k] << (int)preShift;
|
2012-07-11 10:15:24 -07:00
|
|
|
sumLine += fPow2Div2(temp);
|
2018-02-26 20:17:00 +01:00
|
|
|
temp = analysBufferImag[l][k] << (int)preShift;
|
2012-07-11 10:15:24 -07:00
|
|
|
sumLine += fPow2Div2(temp);
|
|
|
|
}
|
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
|
|
|
temp = analysBufferReal[l][k] >> -(int)preShift;
|
2012-07-11 10:15:24 -07:00
|
|
|
sumLine += fPow2Div2(temp);
|
2018-02-26 20:17:00 +01:00
|
|
|
temp = analysBufferImag[l][k] >> -(int)preShift;
|
2012-07-11 10:15:24 -07:00
|
|
|
sumLine += fPow2Div2(temp);
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
if (preShift >= 0) {
|
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
|
|
|
temp = analysBufferReal[l][k] << (int)preShift;
|
2012-07-11 10:15:24 -07:00
|
|
|
sumLine += fPow2Div2(temp);
|
|
|
|
}
|
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
for (l = start_pos; l < next_pos; l++) {
|
|
|
|
temp = analysBufferReal[l][k] >> -(int)preShift;
|
2012-07-11 10:15:24 -07:00
|
|
|
sumLine += fPow2Div2(temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The number of QMF-channels per SBR bands may be up to 15.
|
|
|
|
Shift right to avoid overflows in sum over all channels. */
|
2018-02-26 20:17:00 +01:00
|
|
|
sumLine = sumLine >> (4 - 1);
|
|
|
|
sumAll += sumLine;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert double precision to Mantissa/Exponent: */
|
|
|
|
shift = fNorm(sumAll);
|
|
|
|
sum = sumAll << (int)shift;
|
|
|
|
|
|
|
|
/* Divide by width of envelope: */
|
2018-02-26 20:17:00 +01:00
|
|
|
sum = fMult(sum, invWidth);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Divide by width of Sfb: */
|
2018-02-26 20:17:00 +01:00
|
|
|
sum = fMult(sum, FX_DBL2FX_SGL(GetInvInt(ui - li)));
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Set all Subband energies in the Sfb to the average energy: */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (analysBufferImag != NULL)
|
|
|
|
sum_e = input_e + 4 - shift; /* -4 to compensate right-shift */
|
2012-07-11 10:15:24 -07:00
|
|
|
else
|
2018-02-26 20:17:00 +01:00
|
|
|
sum_e = input_e + 4 + 1 -
|
|
|
|
shift; /* -4 to compensate right-shift; +1 due to missing
|
|
|
|
imag. part */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
sum_e -= 2 * preShift;
|
|
|
|
} /* maxVal!=0 */
|
|
|
|
else {
|
|
|
|
/* Prevent a zero-mantissa-number from being misinterpreted
|
|
|
|
due to its exponent. */
|
|
|
|
sum = FL2FXCONST_DBL(0.0f);
|
|
|
|
sum_e = 0;
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = li; k < ui; k++) {
|
|
|
|
*nrgEst++ = sum;
|
2012-07-11 10:15:24 -07:00
|
|
|
*nrgEst_e++ = sum_e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Calculate gain, noise, and additional sine level for one subband.
|
|
|
|
|
|
|
|
The resulting energy gain is given by mantissa and exponent.
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
static void calcSubbandGain(
|
|
|
|
FIXP_DBL nrgRef, /*!< Reference Energy according to envelope data */
|
|
|
|
SCHAR
|
|
|
|
nrgRef_e, /*!< Reference Energy according to envelope data (exponent) */
|
|
|
|
ENV_CALC_NRGS *nrgs, int i, FIXP_DBL tmpNoise, /*!< Relative noise level */
|
|
|
|
SCHAR tmpNoise_e, /*!< Relative noise level (exponent) */
|
|
|
|
UCHAR sinePresentFlag, /*!< Indicates if sine is present on band */
|
|
|
|
UCHAR sineMapped, /*!< Indicates if sine must be added */
|
|
|
|
int noNoiseFlag) /*!< Flag to suppress noise addition */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL nrgEst = nrgs->nrgEst[i]; /*!< Energy in transposed signal */
|
|
|
|
SCHAR nrgEst_e =
|
|
|
|
nrgs->nrgEst_e[i]; /*!< Energy in transposed signal (exponent) */
|
|
|
|
FIXP_DBL *ptrNrgGain = &nrgs->nrgGain[i]; /*!< Resulting energy gain */
|
|
|
|
SCHAR *ptrNrgGain_e =
|
|
|
|
&nrgs->nrgGain_e[i]; /*!< Resulting energy gain (exponent) */
|
|
|
|
FIXP_DBL *ptrNoiseLevel =
|
|
|
|
&nrgs->noiseLevel[i]; /*!< Resulting absolute noise energy */
|
|
|
|
SCHAR *ptrNoiseLevel_e =
|
|
|
|
&nrgs->noiseLevel_e[i]; /*!< Resulting absolute noise energy (exponent) */
|
|
|
|
FIXP_DBL *ptrNrgSine = &nrgs->nrgSine[i]; /*!< Additional sine energy */
|
|
|
|
SCHAR *ptrNrgSine_e =
|
|
|
|
&nrgs->nrgSine_e[i]; /*!< Additional sine energy (exponent) */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
FIXP_DBL a, b, c;
|
2018-02-26 20:17:00 +01:00
|
|
|
SCHAR a_e, b_e, c_e;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
This addition of 1 prevents divisions by zero in the reference code.
|
|
|
|
For very small energies in nrgEst, it prevents the gains from becoming
|
|
|
|
very high which could cause some trouble due to the smoothing.
|
|
|
|
*/
|
|
|
|
b_e = (int)(nrgEst_e - 1);
|
2018-02-26 20:17:00 +01:00
|
|
|
if (b_e >= 0) {
|
|
|
|
nrgEst = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e + 1, DFRACT_BITS - 1)) +
|
|
|
|
(nrgEst >> 1);
|
|
|
|
nrgEst_e += 1; /* shift by 1 bit to avoid overflow */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
nrgEst = (nrgEst >> (INT)(fixMin(-b_e + 1, DFRACT_BITS - 1))) +
|
|
|
|
(FL2FXCONST_DBL(0.5f) >> 1);
|
|
|
|
nrgEst_e = 2; /* shift by 1 bit to avoid overflow */
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* A = NrgRef * TmpNoise */
|
2018-02-26 20:17:00 +01:00
|
|
|
a = fMult(nrgRef, tmpNoise);
|
2012-07-11 10:15:24 -07:00
|
|
|
a_e = nrgRef_e + tmpNoise_e;
|
|
|
|
|
|
|
|
/* B = 1 + TmpNoise */
|
|
|
|
b_e = (int)(tmpNoise_e - 1);
|
2018-02-26 20:17:00 +01:00
|
|
|
if (b_e >= 0) {
|
|
|
|
b = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e + 1, DFRACT_BITS - 1)) +
|
|
|
|
(tmpNoise >> 1);
|
|
|
|
b_e = tmpNoise_e + 1; /* shift by 1 bit to avoid overflow */
|
2012-07-11 10:15:24 -07:00
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
b = (tmpNoise >> (INT)(fixMin(-b_e + 1, DFRACT_BITS - 1))) +
|
|
|
|
(FL2FXCONST_DBL(0.5f) >> 1);
|
|
|
|
b_e = 2; /* shift by 1 bit to avoid overflow */
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* noiseLevel = A / B = (NrgRef * TmpNoise) / (1 + TmpNoise) */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_divide_MantExp(a, a_e, b, b_e, ptrNoiseLevel, ptrNoiseLevel_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
if (sinePresentFlag) {
|
|
|
|
/* C = (1 + TmpNoise) * NrgEst */
|
2018-02-26 20:17:00 +01:00
|
|
|
c = fMult(b, nrgEst);
|
2012-07-11 10:15:24 -07:00
|
|
|
c_e = b_e + nrgEst_e;
|
|
|
|
|
|
|
|
/* gain = A / C = (NrgRef * TmpNoise) / (1 + TmpNoise) * NrgEst */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_divide_MantExp(a, a_e, c, c_e, ptrNrgGain, ptrNrgGain_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
if (sineMapped) {
|
|
|
|
/* sineLevel = nrgRef/ (1 + TmpNoise) */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_divide_MantExp(nrgRef, nrgRef_e, b, b_e, ptrNrgSine, ptrNrgSine_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
if (noNoiseFlag) {
|
|
|
|
/* B = NrgEst */
|
|
|
|
b = nrgEst;
|
|
|
|
b_e = nrgEst_e;
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* B = NrgEst * (1 + TmpNoise) */
|
2018-02-26 20:17:00 +01:00
|
|
|
b = fMult(b, nrgEst);
|
2012-07-11 10:15:24 -07:00
|
|
|
b_e = b_e + nrgEst_e;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* gain = nrgRef / B */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_divide_MantExp(nrgRef, nrgRef_e, b, b_e, ptrNrgGain, ptrNrgGain_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Calculate "average gain" for the specified subband range.
|
|
|
|
|
|
|
|
This is rather a gain of the average magnitude than the average
|
|
|
|
of gains!
|
|
|
|
The result is used as a relative limit for all gains within the
|
|
|
|
current "limiter band" (a certain frequency range).
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
static void calcAvgGain(
|
|
|
|
ENV_CALC_NRGS *nrgs, int lowSubband, /*!< Begin of the limiter band */
|
|
|
|
int highSubband, /*!< High end of the limiter band */
|
|
|
|
FIXP_DBL *ptrSumRef, SCHAR *ptrSumRef_e,
|
|
|
|
FIXP_DBL *ptrAvgGain, /*!< Resulting overall gain (mantissa) */
|
|
|
|
SCHAR *ptrAvgGain_e) /*!< Resulting overall gain (exponent) */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL *nrgRef =
|
|
|
|
nrgs->nrgRef; /*!< Reference Energy according to envelope data */
|
|
|
|
SCHAR *nrgRef_e =
|
|
|
|
nrgs->nrgRef_e; /*!< Reference Energy according to envelope data
|
|
|
|
(exponent) */
|
|
|
|
FIXP_DBL *nrgEst = nrgs->nrgEst; /*!< Energy in transposed signal */
|
|
|
|
SCHAR *nrgEst_e =
|
|
|
|
nrgs->nrgEst_e; /*!< Energy in transposed signal (exponent) */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
FIXP_DBL sumRef = 1;
|
|
|
|
FIXP_DBL sumEst = 1;
|
2018-02-26 20:17:00 +01:00
|
|
|
SCHAR sumRef_e = -FRACT_BITS;
|
|
|
|
SCHAR sumEst_e = -FRACT_BITS;
|
|
|
|
int k;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = lowSubband; k < highSubband; k++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* Add nrgRef[k] to sumRef: */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_add_MantExp(sumRef, sumRef_e, nrgRef[k], nrgRef_e[k], &sumRef,
|
|
|
|
&sumRef_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/* Add nrgEst[k] to sumEst: */
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_add_MantExp(sumEst, sumEst_e, nrgEst[k], nrgEst_e[k], &sumEst,
|
|
|
|
&sumEst_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FDK_divide_MantExp(sumRef, sumRef_e, sumEst, sumEst_e, ptrAvgGain,
|
|
|
|
ptrAvgGain_e);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
*ptrSumRef = sumRef;
|
|
|
|
*ptrSumRef_e = sumRef_e;
|
|
|
|
}
|
|
|
|
|
2016-04-08 12:05:12 -07:00
|
|
|
static void adjustTimeSlot_EldGrid(
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL *RESTRICT
|
|
|
|
ptrReal, /*!< Subband samples to be adjusted, real part */
|
|
|
|
ENV_CALC_NRGS *nrgs, UCHAR *ptrHarmIndex, /*!< Harmonic index */
|
|
|
|
int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
|
|
|
|
int noSubbands, /*!< Number of QMF subbands */
|
|
|
|
int scale_change, /*!< Number of bits to shift adjusted samples */
|
|
|
|
int noNoiseFlag, /*!< Flag to suppress noise addition */
|
|
|
|
int *ptrPhaseIndex, /*!< Start index to random number array */
|
|
|
|
int scale_diff_low) /*!< */
|
|
|
|
|
2016-04-08 12:05:12 -07:00
|
|
|
{
|
|
|
|
int k;
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL signalReal, sbNoise;
|
2016-04-08 12:05:12 -07:00
|
|
|
int tone_count = 0;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL *pGain = nrgs->nrgGain; /*!< Gains of current envelope */
|
|
|
|
FIXP_DBL *RESTRICT pNoiseLevel =
|
|
|
|
nrgs->noiseLevel; /*!< Noise levels of current envelope */
|
|
|
|
FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
int phaseIndex = *ptrPhaseIndex;
|
|
|
|
UCHAR harmIndex = *ptrHarmIndex;
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
static const INT harmonicPhase[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
static const FIXP_DBL harmonicPhaseX[4][2] = {
|
|
|
|
{FL2FXCONST_DBL(2.0 * 1.245183154539139e-001),
|
|
|
|
FL2FXCONST_DBL(2.0 * 1.245183154539139e-001)},
|
|
|
|
{FL2FXCONST_DBL(2.0 * -1.123767859325028e-001),
|
|
|
|
FL2FXCONST_DBL(2.0 * 1.123767859325028e-001)},
|
|
|
|
{FL2FXCONST_DBL(2.0 * -1.245183154539139e-001),
|
|
|
|
FL2FXCONST_DBL(2.0 * -1.245183154539139e-001)},
|
|
|
|
{FL2FXCONST_DBL(2.0 * 1.123767859325028e-001),
|
|
|
|
FL2FXCONST_DBL(2.0 * -1.123767859325028e-001)}};
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
const FIXP_DBL *p_harmonicPhaseX = &harmonicPhaseX[harmIndex][0];
|
|
|
|
const INT *p_harmonicPhase = &harmonicPhase[harmIndex][0];
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
*(ptrReal - 1) = fAddSaturate(
|
|
|
|
*(ptrReal - 1),
|
|
|
|
SATURATE_SHIFT(fMultDiv2(p_harmonicPhaseX[lowSubband & 1], pSineLevel[0]),
|
|
|
|
scale_diff_low, DFRACT_BITS));
|
|
|
|
FIXP_DBL pSineLevel_prev = (FIXP_DBL)0;
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
int idx_k = lowSubband & 1;
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
FIXP_DBL sineLevel_curr = *pSineLevel++;
|
|
|
|
phaseIndex = (phaseIndex + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
|
|
|
|
sbNoise = *pNoiseLevel++;
|
|
|
|
if (((INT)sineLevel_curr | noNoiseFlag) == 0) {
|
|
|
|
signalReal +=
|
|
|
|
(fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[phaseIndex][0], sbNoise)
|
|
|
|
<< 4);
|
2016-04-08 12:05:12 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
signalReal += sineLevel_curr * p_harmonicPhase[0];
|
|
|
|
signalReal =
|
|
|
|
fMultAddDiv2(signalReal, pSineLevel_prev, p_harmonicPhaseX[idx_k]);
|
|
|
|
pSineLevel_prev = sineLevel_curr;
|
|
|
|
idx_k = !idx_k;
|
|
|
|
if (k < noSubbands - 1) {
|
|
|
|
signalReal =
|
|
|
|
fMultAddDiv2(signalReal, pSineLevel[0], p_harmonicPhaseX[idx_k]);
|
|
|
|
} else /* (k == noSubbands - 1) */
|
|
|
|
{
|
|
|
|
if (k + lowSubband + 1 < 63) {
|
|
|
|
*(ptrReal + 1) += fMultDiv2(pSineLevel_prev, p_harmonicPhaseX[idx_k]);
|
2016-04-08 12:05:12 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
}
|
|
|
|
*ptrReal++ = signalReal;
|
|
|
|
|
|
|
|
if (pSineLevel_prev != FL2FXCONST_DBL(0.0f)) {
|
|
|
|
if (++tone_count == 16) {
|
|
|
|
k++;
|
|
|
|
break;
|
2016-04-08 12:05:12 -07:00
|
|
|
}
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
}
|
|
|
|
/* Run again, if previous loop got breaked with tone_count = 16 */
|
|
|
|
for (; k < noSubbands; k++) {
|
|
|
|
FIXP_DBL sineLevel_curr = *pSineLevel++;
|
|
|
|
phaseIndex = (phaseIndex + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
|
|
|
|
sbNoise = *pNoiseLevel++;
|
|
|
|
if (((INT)sineLevel_curr | noNoiseFlag) == 0) {
|
|
|
|
signalReal +=
|
|
|
|
(fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[phaseIndex][0], sbNoise)
|
|
|
|
<< 4);
|
2016-04-08 12:05:12 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
signalReal += sineLevel_curr * p_harmonicPhase[0];
|
|
|
|
*ptrReal++ = signalReal;
|
2016-04-08 12:05:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
*ptrHarmIndex = (harmIndex + 1) & 3;
|
|
|
|
*ptrPhaseIndex = phaseIndex & (SBR_NF_NO_RANDOM_VAL - 1);
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Amplify one timeslot of the signal with the calculated gains
|
|
|
|
and add the noisefloor.
|
|
|
|
*/
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
static void adjustTimeSlotLC(
|
|
|
|
FIXP_DBL *ptrReal, /*!< Subband samples to be adjusted, real part */
|
|
|
|
ENV_CALC_NRGS *nrgs, UCHAR *ptrHarmIndex, /*!< Harmonic index */
|
|
|
|
int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
|
|
|
|
int noSubbands, /*!< Number of QMF subbands */
|
|
|
|
int scale_change, /*!< Number of bits to shift adjusted samples */
|
|
|
|
int noNoiseFlag, /*!< Flag to suppress noise addition */
|
|
|
|
int *ptrPhaseIndex) /*!< Start index to random number array */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL *pGain = nrgs->nrgGain; /*!< Gains of current envelope */
|
|
|
|
FIXP_DBL *pNoiseLevel =
|
|
|
|
nrgs->noiseLevel; /*!< Noise levels of current envelope */
|
|
|
|
FIXP_DBL *pSineLevel = nrgs->nrgSine; /*!< Sine levels */
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
int k;
|
|
|
|
int index = *ptrPhaseIndex;
|
|
|
|
UCHAR harmIndex = *ptrHarmIndex;
|
|
|
|
UCHAR freqInvFlag = (lowSubband & 1);
|
|
|
|
FIXP_DBL signalReal, sineLevel, sineLevelNext, sineLevelPrev;
|
|
|
|
int tone_count = 0;
|
|
|
|
int sineSign = 1;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
#define C1 ((FIXP_SGL)FL2FXCONST_SGL(2.f * 0.00815f))
|
|
|
|
#define C1_CLDFB ((FIXP_SGL)FL2FXCONST_SGL(2.f * 0.16773f))
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
First pass for k=0 pulled out of the loop:
|
|
|
|
*/
|
|
|
|
|
|
|
|
index = (index + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
The next multiplication constitutes the actual envelope adjustment
|
|
|
|
of the signal and should be carried out with full accuracy
|
|
|
|
(supplying #FRACT_BITS valid bits).
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
|
|
|
|
sineLevel = *pSineLevel++;
|
2012-07-11 10:15:24 -07:00
|
|
|
sineLevelNext = (noSubbands > 1) ? pSineLevel[0] : FL2FXCONST_DBL(0.0f);
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (sineLevel != FL2FXCONST_DBL(0.0f))
|
|
|
|
tone_count++;
|
2012-07-11 10:15:24 -07:00
|
|
|
else if (!noNoiseFlag)
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Add noisefloor to the amplified signal */
|
|
|
|
signalReal +=
|
|
|
|
(fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])
|
|
|
|
<< 4);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
if (!(harmIndex & 0x1)) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* harmIndex 0,2 */
|
2018-02-26 20:17:00 +01:00
|
|
|
signalReal += (harmIndex & 0x2) ? -sineLevel : sineLevel;
|
2012-07-11 10:15:24 -07:00
|
|
|
*ptrReal++ = signalReal;
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* harmIndex 1,3 in combination with freqInvFlag */
|
2018-02-26 20:17:00 +01:00
|
|
|
int shift = (int)(scale_change + 1);
|
|
|
|
shift = (shift >= 0) ? fixMin(DFRACT_BITS - 1, shift)
|
|
|
|
: fixMax(-(DFRACT_BITS - 1), shift);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL tmp1 = (shift >= 0) ? (fMultDiv2(C1, sineLevel) >> shift)
|
|
|
|
: (fMultDiv2(C1, sineLevel) << (-shift));
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL tmp2 = fMultDiv2(C1, sineLevelNext);
|
|
|
|
|
|
|
|
/* save switch and compare operations and reduce to XOR statement */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (((harmIndex >> 1) & 0x1) ^ freqInvFlag) {
|
|
|
|
*(ptrReal - 1) += tmp1;
|
|
|
|
signalReal -= tmp2;
|
2012-07-11 10:15:24 -07:00
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
*(ptrReal - 1) -= tmp1;
|
|
|
|
signalReal += tmp2;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
*ptrReal++ = signalReal;
|
|
|
|
freqInvFlag = !freqInvFlag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pNoiseLevel++;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (noSubbands > 2) {
|
|
|
|
if (!(harmIndex & 0x1)) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* harmIndex 0,2 */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (!harmIndex) {
|
2012-07-11 10:15:24 -07:00
|
|
|
sineSign = 0;
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = noSubbands - 2; k != 0; k--) {
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL sinelevel = *pSineLevel++;
|
|
|
|
index++;
|
2018-02-26 20:17:00 +01:00
|
|
|
if (((signalReal = (sineSign ? -sinelevel : sinelevel)) ==
|
|
|
|
FL2FXCONST_DBL(0.0f)) &&
|
|
|
|
!noNoiseFlag) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* Add noisefloor to the amplified signal */
|
|
|
|
index &= (SBR_NF_NO_RANDOM_VAL - 1);
|
2018-02-26 20:17:00 +01:00
|
|
|
signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0],
|
|
|
|
pNoiseLevel[0])
|
|
|
|
<< 4);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
|
|
|
|
/* The next multiplication constitutes the actual envelope adjustment of
|
|
|
|
* the signal. */
|
|
|
|
signalReal += fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
pNoiseLevel++;
|
|
|
|
*ptrReal++ = signalReal;
|
|
|
|
} /* for ... */
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* harmIndex 1,3 in combination with freqInvFlag */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (harmIndex == 1) freqInvFlag = !freqInvFlag;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = noSubbands - 2; k != 0; k--) {
|
2012-07-11 10:15:24 -07:00
|
|
|
index++;
|
2018-02-26 20:17:00 +01:00
|
|
|
/* The next multiplication constitutes the actual envelope adjustment of
|
|
|
|
* the signal. */
|
|
|
|
signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (*pSineLevel++ != FL2FXCONST_DBL(0.0f))
|
|
|
|
tone_count++;
|
2012-07-11 10:15:24 -07:00
|
|
|
else if (!noNoiseFlag) {
|
|
|
|
/* Add noisefloor to the amplified signal */
|
|
|
|
index &= (SBR_NF_NO_RANDOM_VAL - 1);
|
2018-02-26 20:17:00 +01:00
|
|
|
signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0],
|
|
|
|
pNoiseLevel[0])
|
|
|
|
<< 4);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pNoiseLevel++;
|
|
|
|
|
|
|
|
if (tone_count <= 16) {
|
|
|
|
FIXP_DBL addSine = fMultDiv2((pSineLevel[-2] - pSineLevel[0]), C1);
|
|
|
|
signalReal += (freqInvFlag) ? (-addSine) : (addSine);
|
|
|
|
}
|
|
|
|
|
|
|
|
*ptrReal++ = signalReal;
|
|
|
|
freqInvFlag = !freqInvFlag;
|
|
|
|
} /* for ... */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (noSubbands > -1) {
|
|
|
|
index++;
|
2018-02-26 20:17:00 +01:00
|
|
|
/* The next multiplication constitutes the actual envelope adjustment of the
|
|
|
|
* signal. */
|
|
|
|
signalReal = fMultDiv2(*ptrReal, *pGain) << ((int)scale_change);
|
|
|
|
sineLevelPrev = fMultDiv2(pSineLevel[-1], FL2FX_SGL(0.0163f));
|
|
|
|
sineLevel = pSineLevel[0];
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (pSineLevel[0] != FL2FXCONST_DBL(0.0f))
|
|
|
|
tone_count++;
|
2012-07-11 10:15:24 -07:00
|
|
|
else if (!noNoiseFlag) {
|
2018-02-26 20:17:00 +01:00
|
|
|
/* Add noisefloor to the amplified signal */
|
|
|
|
index &= (SBR_NF_NO_RANDOM_VAL - 1);
|
|
|
|
signalReal =
|
|
|
|
signalReal +
|
|
|
|
(fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])
|
|
|
|
<< 4);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (!(harmIndex & 0x1)) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* harmIndex 0,2 */
|
2018-02-26 20:17:00 +01:00
|
|
|
*ptrReal = signalReal + ((sineSign) ? -sineLevel : sineLevel);
|
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* harmIndex 1,3 in combination with freqInvFlag */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (tone_count <= 16) {
|
2012-07-11 10:15:24 -07:00
|
|
|
if (freqInvFlag) {
|
2018-02-26 20:17:00 +01:00
|
|
|
*ptrReal++ = signalReal - sineLevelPrev;
|
2012-07-11 10:15:24 -07:00
|
|
|
if (noSubbands + lowSubband < 63)
|
|
|
|
*ptrReal = *ptrReal + fMultDiv2(C1, sineLevel);
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
*ptrReal++ = signalReal + sineLevelPrev;
|
|
|
|
if (noSubbands + lowSubband < 63)
|
|
|
|
*ptrReal = *ptrReal - fMultDiv2(C1, sineLevel);
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else
|
|
|
|
*ptrReal = signalReal;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*ptrHarmIndex = (harmIndex + 1) & 3;
|
|
|
|
*ptrPhaseIndex = index & (SBR_NF_NO_RANDOM_VAL - 1);
|
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
|
|
|
|
static void adjustTimeSlotHQ_GainAndNoise(
|
|
|
|
FIXP_DBL *RESTRICT
|
|
|
|
ptrReal, /*!< Subband samples to be adjusted, real part */
|
|
|
|
FIXP_DBL *RESTRICT
|
|
|
|
ptrImag, /*!< Subband samples to be adjusted, imag part */
|
|
|
|
HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
|
|
|
|
int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
|
|
|
|
int noSubbands, /*!< Number of QMF subbands */
|
|
|
|
int scale_change, /*!< Number of bits to shift adjusted samples */
|
|
|
|
FIXP_SGL smooth_ratio, /*!< Impact of last envelope */
|
|
|
|
int noNoiseFlag, /*!< Start index to random number array */
|
|
|
|
int filtBufferNoiseShift) /*!< Shift factor of filtBufferNoise */
|
2012-07-11 10:15:24 -07:00
|
|
|
{
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL *RESTRICT gain = nrgs->nrgGain; /*!< Gains of current envelope */
|
|
|
|
FIXP_DBL *RESTRICT noiseLevel =
|
|
|
|
nrgs->noiseLevel; /*!< Noise levels of current envelope */
|
|
|
|
FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
|
|
|
|
|
|
|
|
FIXP_DBL *RESTRICT filtBuffer =
|
|
|
|
h_sbr_cal_env->filtBuffer; /*!< Gains of last envelope */
|
|
|
|
FIXP_DBL *RESTRICT filtBufferNoise =
|
|
|
|
h_sbr_cal_env->filtBufferNoise; /*!< Noise levels of last envelope */
|
|
|
|
int *RESTRICT ptrPhaseIndex =
|
|
|
|
&h_sbr_cal_env->phaseIndex; /*!< Start index to random number array */
|
|
|
|
|
|
|
|
int k;
|
|
|
|
FIXP_DBL signalReal, signalImag;
|
|
|
|
FIXP_DBL noiseReal, noiseImag;
|
|
|
|
FIXP_DBL smoothedGain, smoothedNoise;
|
|
|
|
FIXP_SGL direct_ratio =
|
|
|
|
/*FL2FXCONST_SGL(1.0f) */ (FIXP_SGL)MAXVAL_SGL - smooth_ratio;
|
|
|
|
int index = *ptrPhaseIndex;
|
|
|
|
int shift;
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
*ptrPhaseIndex = (index + noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
filtBufferNoiseShift +=
|
|
|
|
1; /* due to later use of fMultDiv2 instead of fMult */
|
|
|
|
if (filtBufferNoiseShift < 0) {
|
|
|
|
shift = fixMin(DFRACT_BITS - 1, -filtBufferNoiseShift);
|
|
|
|
} else {
|
|
|
|
shift = fixMin(DFRACT_BITS - 1, filtBufferNoiseShift);
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (smooth_ratio > FL2FXCONST_SGL(0.0f)) {
|
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
/*
|
|
|
|
Smoothing: The old envelope has been bufferd and a certain ratio
|
|
|
|
of the old gains and noise levels is used.
|
|
|
|
*/
|
|
|
|
smoothedGain =
|
|
|
|
fMult(smooth_ratio, filtBuffer[k]) + fMult(direct_ratio, gain[k]);
|
|
|
|
|
|
|
|
if (filtBufferNoiseShift < 0) {
|
|
|
|
smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) >> shift) +
|
|
|
|
fMult(direct_ratio, noiseLevel[k]);
|
|
|
|
} else {
|
|
|
|
smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) << shift) +
|
|
|
|
fMult(direct_ratio, noiseLevel[k]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
The next 2 multiplications constitute the actual envelope adjustment
|
|
|
|
of the signal and should be carried out with full accuracy
|
|
|
|
(supplying #DFRACT_BITS valid bits).
|
|
|
|
*/
|
|
|
|
signalReal = fMultDiv2(*ptrReal, smoothedGain) << ((int)scale_change);
|
|
|
|
signalImag = fMultDiv2(*ptrImag, smoothedGain) << ((int)scale_change);
|
|
|
|
|
|
|
|
index++;
|
|
|
|
|
|
|
|
if ((pSineLevel[k] != FL2FXCONST_DBL(0.0f)) || noNoiseFlag) {
|
|
|
|
/* Just the amplified signal is saved */
|
|
|
|
*ptrReal++ = signalReal;
|
|
|
|
*ptrImag++ = signalImag;
|
|
|
|
} else {
|
|
|
|
/* Add noisefloor to the amplified signal */
|
|
|
|
index &= (SBR_NF_NO_RANDOM_VAL - 1);
|
|
|
|
noiseReal =
|
|
|
|
fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise)
|
|
|
|
<< 4;
|
|
|
|
noiseImag =
|
|
|
|
fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise)
|
|
|
|
<< 4;
|
|
|
|
*ptrReal++ = (signalReal + noiseReal);
|
|
|
|
*ptrImag++ = (signalImag + noiseImag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
smoothedGain = gain[k];
|
|
|
|
signalReal = fMultDiv2(*ptrReal, smoothedGain) << scale_change;
|
|
|
|
signalImag = fMultDiv2(*ptrImag, smoothedGain) << scale_change;
|
|
|
|
|
|
|
|
index++;
|
|
|
|
|
|
|
|
if ((pSineLevel[k] == FL2FXCONST_DBL(0.0f)) && (noNoiseFlag == 0)) {
|
|
|
|
/* Add noisefloor to the amplified signal */
|
|
|
|
smoothedNoise = noiseLevel[k];
|
|
|
|
index &= (SBR_NF_NO_RANDOM_VAL - 1);
|
|
|
|
noiseReal =
|
|
|
|
fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise);
|
|
|
|
noiseImag =
|
|
|
|
fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise);
|
|
|
|
|
|
|
|
/* FDK_sbrDecoder_sbr_randomPhase is downscaled by 2^3 */
|
|
|
|
signalReal += noiseReal << 4;
|
|
|
|
signalImag += noiseImag << 4;
|
|
|
|
}
|
|
|
|
*ptrReal++ = signalReal;
|
|
|
|
*ptrImag++ = signalImag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void adjustTimeSlotHQ_AddHarmonics(
|
|
|
|
FIXP_DBL *RESTRICT
|
|
|
|
ptrReal, /*!< Subband samples to be adjusted, real part */
|
|
|
|
FIXP_DBL *RESTRICT
|
|
|
|
ptrImag, /*!< Subband samples to be adjusted, imag part */
|
|
|
|
HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
|
|
|
|
int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
|
|
|
|
int noSubbands, /*!< Number of QMF subbands */
|
|
|
|
int scale_change /*!< Scale mismatch between QMF input and sineLevel
|
|
|
|
exponent. */
|
|
|
|
) {
|
|
|
|
FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
|
|
|
|
UCHAR *RESTRICT ptrHarmIndex =
|
|
|
|
&h_sbr_cal_env->harmIndex; /*!< Harmonic index */
|
|
|
|
|
|
|
|
int k;
|
|
|
|
FIXP_DBL signalReal, signalImag;
|
|
|
|
UCHAR harmIndex = *ptrHarmIndex;
|
|
|
|
int freqInvFlag = (lowSubband & 1);
|
|
|
|
FIXP_DBL sineLevel;
|
|
|
|
|
|
|
|
*ptrHarmIndex = (harmIndex + 1) & 3;
|
|
|
|
|
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
sineLevel = pSineLevel[k];
|
|
|
|
freqInvFlag ^= 1;
|
|
|
|
if (sineLevel != FL2FXCONST_DBL(0.f)) {
|
|
|
|
signalReal = ptrReal[k];
|
|
|
|
signalImag = ptrImag[k];
|
|
|
|
sineLevel = scaleValue(sineLevel, scale_change);
|
|
|
|
if (harmIndex & 2) {
|
|
|
|
/* case 2,3 */
|
|
|
|
sineLevel = -sineLevel;
|
|
|
|
}
|
|
|
|
if (!(harmIndex & 1)) {
|
|
|
|
/* case 0,2: */
|
|
|
|
ptrReal[k] = signalReal + sineLevel;
|
|
|
|
} else {
|
|
|
|
/* case 1,3 */
|
|
|
|
if (!freqInvFlag) sineLevel = -sineLevel;
|
|
|
|
ptrImag[k] = signalImag + sineLevel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void adjustTimeSlotHQ(
|
|
|
|
FIXP_DBL *RESTRICT
|
|
|
|
ptrReal, /*!< Subband samples to be adjusted, real part */
|
|
|
|
FIXP_DBL *RESTRICT
|
|
|
|
ptrImag, /*!< Subband samples to be adjusted, imag part */
|
|
|
|
HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
|
|
|
|
int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
|
|
|
|
int noSubbands, /*!< Number of QMF subbands */
|
|
|
|
int scale_change, /*!< Number of bits to shift adjusted samples */
|
|
|
|
FIXP_SGL smooth_ratio, /*!< Impact of last envelope */
|
|
|
|
int noNoiseFlag, /*!< Start index to random number array */
|
|
|
|
int filtBufferNoiseShift) /*!< Shift factor of filtBufferNoise */
|
|
|
|
{
|
|
|
|
FIXP_DBL *RESTRICT gain = nrgs->nrgGain; /*!< Gains of current envelope */
|
|
|
|
FIXP_DBL *RESTRICT noiseLevel =
|
|
|
|
nrgs->noiseLevel; /*!< Noise levels of current envelope */
|
|
|
|
FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
|
|
|
|
|
|
|
|
FIXP_DBL *RESTRICT filtBuffer =
|
|
|
|
h_sbr_cal_env->filtBuffer; /*!< Gains of last envelope */
|
|
|
|
FIXP_DBL *RESTRICT filtBufferNoise =
|
|
|
|
h_sbr_cal_env->filtBufferNoise; /*!< Noise levels of last envelope */
|
|
|
|
UCHAR *RESTRICT ptrHarmIndex =
|
|
|
|
&h_sbr_cal_env->harmIndex; /*!< Harmonic index */
|
|
|
|
int *RESTRICT ptrPhaseIndex =
|
|
|
|
&h_sbr_cal_env->phaseIndex; /*!< Start index to random number array */
|
|
|
|
|
|
|
|
int k;
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL signalReal, signalImag;
|
2018-02-26 20:17:00 +01:00
|
|
|
FIXP_DBL noiseReal, noiseImag;
|
|
|
|
FIXP_DBL smoothedGain, smoothedNoise;
|
|
|
|
FIXP_SGL direct_ratio =
|
|
|
|
/*FL2FXCONST_SGL(1.0f) */ (FIXP_SGL)MAXVAL_SGL - smooth_ratio;
|
|
|
|
int index = *ptrPhaseIndex;
|
|
|
|
UCHAR harmIndex = *ptrHarmIndex;
|
2016-10-18 09:08:02 +03:00
|
|
|
int freqInvFlag = (lowSubband & 1);
|
2012-07-11 10:15:24 -07:00
|
|
|
FIXP_DBL sineLevel;
|
|
|
|
int shift;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
*ptrPhaseIndex = (index + noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1);
|
2012-07-11 10:15:24 -07:00
|
|
|
*ptrHarmIndex = (harmIndex + 1) & 3;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Possible optimization:
|
|
|
|
smooth_ratio and harmIndex stay constant during the loop.
|
|
|
|
It might be faster to include a separate loop in each path.
|
|
|
|
|
|
|
|
the check for smooth_ratio is now outside the loop and the workload
|
|
|
|
of the whole function decreased by about 20 %
|
|
|
|
*/
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
filtBufferNoiseShift +=
|
|
|
|
1; /* due to later use of fMultDiv2 instead of fMult */
|
|
|
|
if (filtBufferNoiseShift < 0)
|
|
|
|
shift = fixMin(DFRACT_BITS - 1, -filtBufferNoiseShift);
|
2012-07-11 10:15:24 -07:00
|
|
|
else
|
2018-02-26 20:17:00 +01:00
|
|
|
shift = fixMin(DFRACT_BITS - 1, filtBufferNoiseShift);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
if (smooth_ratio > FL2FXCONST_SGL(0.0f)) {
|
2018-02-26 20:17:00 +01:00
|
|
|
for (k = 0; k < noSubbands; k++) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/*
|
|
|
|
Smoothing: The old envelope has been bufferd and a certain ratio
|
|
|
|
of the old gains and noise levels is used.
|
|
|
|
*/
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
smoothedGain =
|
|
|
|
fMult(smooth_ratio, filtBuffer[k]) + fMult(direct_ratio, gain[k]);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if (filtBufferNoiseShift < 0) {
|
|
|
|
smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) >> shift) +
|
|
|
|
fMult(direct_ratio, noiseLevel[k]);
|
|
|
|
} else {
|
|
|
|
smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) << shift) +
|
|
|
|
fMult(direct_ratio, noiseLevel[k]);
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
The next 2 multiplications constitute the actual envelope adjustment
|
|
|
|
of the signal and should be carried out with full accuracy
|
|
|
|
(supplying #DFRACT_BITS valid bits).
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
signalReal = fMultDiv2(*ptrReal, smoothedGain) << ((int)scale_change);
|
|
|
|
signalImag = fMultDiv2(*ptrImag, smoothedGain) << ((int)scale_change);
|
2012-07-11 10:15:24 -07:00
|
|
|
|
|
|
|
index++;
|
|
|
|
|
|
|
|
if (pSineLevel[k] != FL2FXCONST_DBL(0.0f)) {
|
|
|
|
sineLevel = pSineLevel[k];
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
switch (harmIndex) {
|
|
|
|
case 0:
|
|
|
|
*ptrReal++ = (signalReal + sineLevel);
|
|
|
|
*ptrImag++ = (signalImag);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
*ptrReal++ = (signalReal - sineLevel);
|
|
|
|
*ptrImag++ = (signalImag);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
*ptrReal++ = (signalReal);
|
|
|
|
if (freqInvFlag)
|
|
|
|
*ptrImag++ = (signalImag - sineLevel);
|
|
|
|
else
|
|
|
|
*ptrImag++ = (signalImag + sineLevel);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
*ptrReal++ = signalReal;
|
|
|
|
if (freqInvFlag)
|
|
|
|
*ptrImag++ = (signalImag + sineLevel);
|
|
|
|
else
|
|
|
|
*ptrImag++ = (signalImag - sineLevel);
|
|
|
|
break;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
if (noNoiseFlag) {
|
|
|
|
/* Just the amplified signal is saved */
|
|
|
|
*ptrReal++ = (signalReal);
|
|
|
|
*ptrImag++ = (signalImag);
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* Add noisefloor to the amplified signal */
|
|
|
|
index &= (SBR_NF_NO_RANDOM_VAL - 1);
|
2018-02-26 20:17:00 +01:00
|
|
|
/* FDK_sbrDecoder_sbr_randomPhase is downscaled by 2^3 */
|
|
|
|
noiseReal =
|
|
|
|
fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise)
|
|
|
|
<< 4;
|
|
|
|
noiseImag =
|
|
|
|
fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise)
|
|
|
|
<< 4;
|
2012-07-11 10:15:24 -07:00
|
|
|
*ptrReal++ = (signalReal + noiseReal);
|
|
|
|
*ptrImag++ = (signalImag + noiseImag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
freqInvFlag ^= 1;
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
for (k = 0; k < noSubbands; k++) {
|
|
|
|
smoothedGain = gain[k];
|
2012-07-11 10:15:24 -07:00
|
|
|
signalReal = fMultDiv2(*ptrReal, smoothedGain) << scale_change;
|
|
|
|
signalImag = fMultDiv2(*ptrImag, smoothedGain) << scale_change;
|
|
|
|
|
|
|
|
index++;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
if ((sineLevel = pSineLevel[k]) != FL2FXCONST_DBL(0.0f)) {
|
|
|
|
switch (harmIndex) {
|
|
|
|
case 0:
|
|
|
|
signalReal += sineLevel;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (freqInvFlag)
|
|
|
|
signalImag -= sineLevel;
|
|
|
|
else
|
|
|
|
signalImag += sineLevel;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
signalReal -= sineLevel;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (freqInvFlag)
|
|
|
|
signalImag += sineLevel;
|
|
|
|
else
|
|
|
|
signalImag -= sineLevel;
|
|
|
|
break;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
2018-02-26 20:17:00 +01:00
|
|
|
} else {
|
|
|
|
if (noNoiseFlag == 0) {
|
2012-07-11 10:15:24 -07:00
|
|
|
/* Add noisefloor to the amplified signal */
|
|
|
|
smoothedNoise = noiseLevel[k];
|
|
|
|
index &= (SBR_NF_NO_RANDOM_VAL - 1);
|
2018-02-26 20:17:00 +01:00
|
|
|
noiseReal = fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0],
|
|
|
|
smoothedNoise);
|
|
|
|
noiseImag = fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1],
|
|
|
|
smoothedNoise);
|
|
|
|
|
|
|
|
/* FDK_sbrDecoder_sbr_randomPhase is downscaled by 2^3 */
|
|
|
|
signalReal += noiseReal << 4;
|
|
|
|
signalImag += noiseImag << 4;
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*ptrReal++ = signalReal;
|
|
|
|
*ptrImag++ = signalImag;
|
|
|
|
|
|
|
|
freqInvFlag ^= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Reset limiter bands.
|
|
|
|
|
|
|
|
Build frequency band table for the gain limiter dependent on
|
|
|
|
the previously generated transposer patch areas.
|
|
|
|
|
|
|
|
\return SBRDEC_OK if ok, SBRDEC_UNSUPPORTED_CONFIG on error
|
|
|
|
*/
|
|
|
|
SBR_ERROR
|
2018-02-26 20:17:00 +01:00
|
|
|
ResetLimiterBands(
|
|
|
|
UCHAR *limiterBandTable, /*!< Resulting band borders in QMF channels */
|
|
|
|
UCHAR *noLimiterBands, /*!< Resulting number of limiter band */
|
|
|
|
UCHAR *freqBandTable, /*!< Table with possible band borders */
|
|
|
|
int noFreqBands, /*!< Number of bands in freqBandTable */
|
|
|
|
const PATCH_PARAM *patchParam, /*!< Transposer patch parameters */
|
|
|
|
int noPatches, /*!< Number of transposer patches */
|
|
|
|
int limiterBands, /*!< Selected 'band density' from bitstream */
|
|
|
|
UCHAR sbrPatchingMode, int xOverQmf[MAX_NUM_PATCHES], int b41Sbr) {
|
2012-07-11 10:15:24 -07:00
|
|
|
int i, k, isPatchBorder[2], loLimIndex, hiLimIndex, tempNoLim, nBands;
|
|
|
|
UCHAR workLimiterBandTable[MAX_FREQ_COEFFS / 2 + MAX_NUM_PATCHES + 1];
|
|
|
|
int patchBorders[MAX_NUM_PATCHES + 1];
|
|
|
|
int kx, k2;
|
|
|
|
|
|
|
|
int lowSubband = freqBandTable[0];
|
|
|
|
int highSubband = freqBandTable[noFreqBands];
|
|
|
|
|
|
|
|
/* 1 limiter band. */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (limiterBands == 0) {
|
2012-07-11 10:15:24 -07:00
|
|
|
limiterBandTable[0] = 0;
|
|
|
|
limiterBandTable[1] = highSubband - lowSubband;
|
|
|
|
nBands = 1;
|
|
|
|
} else {
|
2018-02-26 20:17:00 +01:00
|
|
|
if (!sbrPatchingMode && xOverQmf != NULL) {
|
|
|
|
noPatches = 0;
|
|
|
|
|
|
|
|
if (b41Sbr == 1) {
|
|
|
|
for (i = 1; i < MAX_NUM_PATCHES_HBE; i++)
|
|
|
|
if (xOverQmf[i] != 0) noPatches++;
|
|
|
|
} else {
|
|
|
|
for (i = 1; i < MAX_STRETCH_HBE; i++)
|
|
|
|
if (xOverQmf[i] != 0) noPatches++;
|
|
|
|
}
|
|
|
|
for (i = 0; i < noPatches; i++) {
|
|
|
|
patchBorders[i] = xOverQmf[i] - lowSubband;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < noPatches; i++) {
|
|
|
|
patchBorders[i] = patchParam[i].guardStartBand - lowSubband;
|
|
|
|
}
|
2012-07-11 10:15:24 -07:00
|
|
|
}
|
|
|
|
patchBorders[i] = highSubband - lowSubband;
|
|
|
|
|
|
|
|
/* 1.2, 2, or 3 limiter bands/octave plus bandborders at patchborders. */
|
|
|
|
for (k = 0; k <= noFreqBands; k++) {
|
|
|
|
workLimiterBandTable[k] = freqBandTable[k] - lowSubband;
|
|
|
|
}
|
|
|
|
for (k = 1; k < noPatches; k++) {
|
|
|
|
workLimiterBandTable[noFreqBands + k] = patchBorders[k];
|
|
|
|
}
|
|
|
|
|
|
|
|
tempNoLim = nBands = noFreqBands + noPatches - 1;
|
|
|
|
shellsort(workLimiterBandTable, tempNoLim + 1);
|
|
|
|
|
|
|
|
loLimIndex = 0;
|
|
|
|
hiLimIndex = 1;
|
|
|
|
|
|
|
|
while (hiLimIndex <= tempNoLim) {
|
2016-04-08 12:05:12 -07:00
|
|
|
FIXP_DBL div_m, oct_m, temp;
|
2018-02-26 20:17:00 +01:00
|
|
|
INT div_e = 0, oct_e = 0, temp_e = 0;
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2012-07-11 10:15:24 -07:00
|
|
|
k2 = workLimiterBandTable[hiLimIndex] + lowSubband;
|
|
|
|
kx = workLimiterBandTable[loLimIndex] + lowSubband;
|
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
div_m = fDivNorm(k2, kx, &div_e);
|
2016-04-08 12:05:12 -07:00
|
|
|
|
|
|
|
/* calculate number of octaves */
|
2018-02-26 20:17:00 +01:00
|
|
|
oct_m = fLog2(div_m, div_e, &oct_e);
|
2016-04-08 12:05:12 -07:00
|
|
|
|
|
|
|
/* multiply with limiterbands per octave */
|
|
|
|
/* values 1, 1.2, 2, 3 -> scale factor of 2 */
|
2018-02-26 20:17:00 +01:00
|
|
|
temp = fMultNorm(
|
|
|
|
oct_m, FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4_DBL[limiterBands],
|
|
|
|
&temp_e);
|
2016-04-08 12:05:12 -07:00
|
|
|
|
2018-02-26 20:17:00 +01:00
|
|
|
/* overall scale factor of temp ist addition of scalefactors from log2
|
|
|
|
calculation, limiter bands scalefactor (2) and limiter bands
|
|
|
|
multiplication */
|
2016-04-08 12:05:12 -07:00
|
|
|
temp_e += oct_e + 2;
|
|
|
|
|
|
|
|
/* div can be a maximum of 64 (k2 = 64 and kx = 1)
|
|
|
|
-> oct can be a maximum of 6
|
2018-02-26 20:17:00 +01:00
|
|
|
-> temp can be a maximum of 18 (as limiterBandsPerOctoave is a maximum
|
|
|
|
factor of 3)
|
2016-04-08 12:05:12 -07:00
|
|
|
-> we need a scale factor of 5 for comparisson
|
|
|
|
*/
|
2018-02-26 20:17:00 +01:00
|
|
|
if (temp >> (5 - temp_e) < FL2FXCONST_DBL(0.49f) >> 5) {
|
|
|
|
if (workLimiterBandTable[hiLimIndex] ==
|
|
|
|
workLimiterBandTable[loLimIndex]) {
|
2012-07-11 10:15:24 -07:00
|
|
|
workLimiterBandTable[hiLimIndex] = highSubband;
|
|
|
|
nBands--;
|
|
|
|
hiLimIndex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
isPatchBorder[0] = isPatchBorder[1] = 0;
|
|
|
|
for (k = 0; k <= noPatches; k++) {
|
|
|
|
if (workLimiterBandTable[hiLimIndex] == patchBorders[k]) {
|
|
|
|
isPatchBorder[1] = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!isPatchBorder[1]) {
|
|
|
|
workLimiterBandTable[hiLimIndex] = highSubband;
|
|
|
|
nBands--;
|
|
|
|
hiLimIndex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (k = 0; k <= noPatches; k++) {
|
|
|
|
if (workLimiterBandTable[loLimIndex] == patchBorders[k]) {
|
|
|
|
isPatchBorder[0] = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!isPatchBorder[0]) {
|
|
|
|
workLimiterBandTable[loLimIndex] = highSubband;
|
|
|
|
nBands--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
loLimIndex = hiLimIndex;
|
|
|
|
hiLimIndex++;
|
|
|
|
}
|
|
|
|
shellsort(workLimiterBandTable, tempNoLim + 1);
|
|
|
|
|
|
|
|
/* Test if algorithm exceeded maximum allowed limiterbands */
|
2018-02-26 20:17:00 +01:00
|
|
|
if (nBands > MAX_NUM_LIMITERS || nBands <= 0) {
|
2012-07-11 10:15:24 -07:00
|
|
|
return SBRDEC_UNSUPPORTED_CONFIG;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy limiterbands from working buffer into final destination */
|
|
|
|
for (k = 0; k <= nBands; k++) {
|
|
|
|
limiterBandTable[k] = workLimiterBandTable[k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*noLimiterBands = nBands;
|
|
|
|
|
|
|
|
return SBRDEC_OK;
|
|
|
|
}
|