mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-03-13 06:10:03 +01:00
* AAC-Encoder - AAC-ELD core encoder audio quality tuning. Update tuning tables, configure bitreservoir size and adapt afterburner iteration value. Modified file(s): libAACenc/src/aacenc.h libAACenc/src/aacenc_lib.cpp libAACenc/src/adj_thr.cpp libAACenc/src/adj_thr.h libAACenc/src/adj_thr_data.h libAACenc/src/bandwidth.cpp libAACenc/src/pnsparam.cpp libAACenc/src/qc_main.cpp - Introduze dead zone quantizer for ELD to improve audio quality at certain configurations. Modified file(s): libAACenc/src/aacenc_lib.cpp libAACenc/src/adj_thr.cpp libAACenc/src/adj_thr.h libAACenc/src/qc_data.h libAACenc/src/qc_main.cpp libAACenc/src/quantize.cpp libAACenc/src/quantize.h libAACenc/src/sf_estim.cpp libAACenc/src/sf_estim.h - Revise TNS module to improve ELD audio quality. - Use new window function and separate prediction gain according TNS filters. - Add missing memory initilization to TNS configuration. Modified file(s): libAACenc/src/aacenc_lib.cpp libAACenc/src/aacenc_tns.cpp libAACenc/src/aacenc_tns.h libAACenc/src/psy_main.cpp libAACenc/src/tns_func.h * SBR-Encoder - Revise frequency resolution calculation and handle differently depending on number of envelopes and split frames decision. - Add and adjust ELD SBR tuning tables. Modified file(s): libSBRenc/include/sbr_encoder.h libSBRenc/src/bit_sbr.h libSBRenc/src/env_est.cpp libSBRenc/src/fram_gen.cpp libSBRenc/src/fram_gen.h libSBRenc/src/mh_det.cpp libSBRenc/src/sbr_def.h libSBRenc/src/sbr_encoder.cpp libSBRenc/src/sbr_rom.cpp libSBRenc/src/tran_det.cpp - Replace ELD transient detector with fast implementation. Modified file(s): libSBRenc/src/env_est.cpp libSBRenc/src/env_est.h libSBRenc/src/fram_gen.cpp libSBRenc/src/sbr_def.h libSBRenc/src/sbr_encoder.cpp libSBRenc/src/tran_det.cpp libSBRenc/src/tran_det.h * FDK-Library - Introduce generic compare function in tools library. Modified file(s): libFDK/include/fixpoint_math.h libFDK/src/FDK_core.cpp * SBR-Encoder - Revise ELD frame splitter to improve bit distribution. Modified file(s): libSBRenc/include/sbr_encoder.h libSBRenc/src/bit_sbr.h libSBRenc/src/env_est.cpp libSBRenc/src/fram_gen.cpp libSBRenc/src/fram_gen.h libSBRenc/src/sbr_encoder.cpp libSBRenc/src/tran_det.cpp libSBRenc/src/tran_det.h - Configure amplitude resolution according the tonality of the audio signal. Modified file(s): libSBRenc/include/sbr_encoder.h libSBRenc/src/bit_sbr.h libSBRenc/src/env_est.cpp libSBRenc/src/nf_est.cpp libSBRenc/src/nf_est.h libSBRenc/src/sbr_def.h libSBRenc/src/sbr_encoder.cpp libSBRenc/src/ton_corr.cpp libSBRenc/src/ton_corr.h libSBRenc/src/tran_det.cpp libSBRenc/src/tran_det.h Change-Id: Ie0672b989a06ee63b50240616b8d1d4b790b6cb2
2031 lines
74 KiB
C++
2031 lines
74 KiB
C++
|
|
/* -----------------------------------------------------------------------------------------------------------
|
|
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
|
|
|
© Copyright 1995 - 2015 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
|
|
All rights reserved.
|
|
|
|
1. INTRODUCTION
|
|
The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
|
|
the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
|
|
This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
|
|
|
|
AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
|
|
audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
|
|
independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
|
|
of the MPEG specifications.
|
|
|
|
Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
|
|
may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
|
|
individually for the purpose of encoding or decoding bit streams in products that are compliant with
|
|
the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
|
|
these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
|
|
software may already be covered under those patent licenses when it is used for those licensed purposes only.
|
|
|
|
Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
|
|
are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
|
|
applications information and documentation.
|
|
|
|
2. COPYRIGHT LICENSE
|
|
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted without
|
|
payment of copyright license fees provided that you satisfy the following conditions:
|
|
|
|
You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
|
|
your modifications thereto in source code form.
|
|
|
|
You must retain the complete text of this software license in the documentation and/or other materials
|
|
provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
|
|
You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
|
|
modifications thereto to recipients of copies in binary form.
|
|
|
|
The name of Fraunhofer may not be used to endorse or promote products derived from this library without
|
|
prior written permission.
|
|
|
|
You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
|
|
software or your modifications thereto.
|
|
|
|
Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
|
|
and the date of any change. For modified versions of the FDK AAC Codec, the term
|
|
"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
|
|
"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
|
|
|
|
3. NO PATENT LICENSE
|
|
|
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
|
|
ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
|
|
respect to this software.
|
|
|
|
You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
|
|
by appropriate patent licenses.
|
|
|
|
4. DISCLAIMER
|
|
|
|
This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
|
|
"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
|
|
of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
|
|
including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
|
|
or business interruption, however caused and on any theory of liability, whether in contract, strict
|
|
liability, or tort (including negligence), arising in any way out of the use of this software, even if
|
|
advised of the possibility of such damage.
|
|
|
|
5. CONTACT INFORMATION
|
|
|
|
Fraunhofer Institute for Integrated Circuits IIS
|
|
Attention: Audio and Multimedia Departments - FDK AAC LL
|
|
Am Wolfsmantel 33
|
|
91058 Erlangen, Germany
|
|
|
|
www.iis.fraunhofer.de/amm
|
|
amm-info@iis.fraunhofer.de
|
|
----------------------------------------------------------------------------------------------------------- */
|
|
|
|
#include "env_est.h"
|
|
#include "tran_det.h"
|
|
|
|
#include "qmf.h"
|
|
|
|
#include "fram_gen.h"
|
|
#include "bit_sbr.h"
|
|
#include "cmondata.h"
|
|
#include "sbr_ram.h"
|
|
|
|
|
|
#include "genericStds.h"
|
|
|
|
#define QUANT_ERROR_THRES 200
|
|
#define Y_NRG_SCALE 5 /* noCols = 32 -> shift(5) */
|
|
|
|
|
|
static const UCHAR panTable[2][10] = { { 0, 2, 4, 6, 8,12,16,20,24},
|
|
{ 0, 2, 4, 8,12, 0, 0, 0, 0 } };
|
|
static const UCHAR maxIndex[2] = {9, 5};
|
|
|
|
|
|
/******************************************************************************
|
|
Functionname: FDKsbrEnc_GetTonality
|
|
******************************************************************************/
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief Calculates complete energy per band from the energy values
|
|
of the QMF subsamples.
|
|
|
|
\brief quotaMatrix - calculated in FDKsbrEnc_CalculateTonalityQuotas()
|
|
\brief noEstPerFrame - number of estimations per frame
|
|
\brief startIndex - start index for the quota matrix
|
|
\brief Energies - energy matrix
|
|
\brief startBand - start band
|
|
\brief stopBand - number of QMF bands
|
|
\brief numberCols - number of QMF subsamples
|
|
|
|
\return mean tonality of the 5 bands with the highest energy
|
|
scaled by 2^(RELAXATION_SHIFT+2)*RELAXATION_FRACT
|
|
|
|
****************************************************************************/
|
|
static FIXP_DBL FDKsbrEnc_GetTonality(
|
|
const FIXP_DBL *const *quotaMatrix,
|
|
const INT noEstPerFrame,
|
|
const INT startIndex,
|
|
const FIXP_DBL *const *Energies,
|
|
const UCHAR startBand,
|
|
const INT stopBand,
|
|
const INT numberCols
|
|
)
|
|
{
|
|
UCHAR b, e, k;
|
|
INT no_enMaxBand[SBR_MAX_ENERGY_VALUES] = { -1, -1, -1, -1, -1 };
|
|
FIXP_DBL energyMax[SBR_MAX_ENERGY_VALUES] = { FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f) };
|
|
FIXP_DBL energyMaxMin = MAXVAL_DBL; /* min. energy in energyMax array */
|
|
UCHAR posEnergyMaxMin = 0; /* min. energy in energyMax array position */
|
|
FIXP_DBL tonalityBand[SBR_MAX_ENERGY_VALUES] = { FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f) };
|
|
FIXP_DBL globalTonality = FL2FXCONST_DBL(0.0f);
|
|
FIXP_DBL energyBand[QMF_CHANNELS];
|
|
INT maxNEnergyValues; /* max. number of max. energy values */
|
|
|
|
/*** Sum up energies for each band ***/
|
|
FDK_ASSERT(numberCols==15||numberCols==16);
|
|
/* numberCols is always 15 or 16 for ELD. In case of 16 bands, the
|
|
energyBands are initialized with the [15]th column.
|
|
The rest of the column energies are added in the next step. */
|
|
if (numberCols==15) {
|
|
for (b=startBand; b<stopBand; b++) {
|
|
energyBand[b]=FL2FXCONST_DBL(0.0f);
|
|
}
|
|
} else {
|
|
for (b=startBand; b<stopBand; b++) {
|
|
energyBand[b]=Energies[15][b]>>4;
|
|
}
|
|
}
|
|
|
|
for (k=0; k<15; k++) {
|
|
for (b=startBand; b<stopBand; b++) {
|
|
energyBand[b] += Energies[k][b]>>4;
|
|
}
|
|
}
|
|
|
|
/*** Determine 5 highest band-energies ***/
|
|
maxNEnergyValues = fMin(SBR_MAX_ENERGY_VALUES, stopBand-startBand);
|
|
|
|
/* Get min. value in energyMax array */
|
|
energyMaxMin = energyMax[0] = energyBand[startBand];
|
|
no_enMaxBand[0] = startBand;
|
|
posEnergyMaxMin = 0;
|
|
for (k=1; k<maxNEnergyValues; k++) {
|
|
energyMax[k] = energyBand[startBand+k];
|
|
no_enMaxBand[k] = startBand+k;
|
|
if (energyMaxMin > energyMax[k]) {
|
|
energyMaxMin = energyMax[k];
|
|
posEnergyMaxMin = k;
|
|
}
|
|
}
|
|
|
|
for (b=startBand+maxNEnergyValues; b<stopBand; b++) {
|
|
if (energyBand[b] > energyMaxMin) {
|
|
energyMax[posEnergyMaxMin] = energyBand[b];
|
|
no_enMaxBand[posEnergyMaxMin] = b;
|
|
|
|
/* Again, get min. value in energyMax array */
|
|
energyMaxMin = energyMax[0];
|
|
posEnergyMaxMin = 0;
|
|
for (k=1; k<maxNEnergyValues; k++) {
|
|
if (energyMaxMin > energyMax[k]) {
|
|
energyMaxMin = energyMax[k];
|
|
posEnergyMaxMin = k;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*** End determine 5 highest band-energies ***/
|
|
|
|
/* Get tonality values for 5 highest energies */
|
|
for (e=0; e<maxNEnergyValues; e++) {
|
|
tonalityBand[e]=FL2FXCONST_DBL(0.0f);
|
|
for (k=0; k<noEstPerFrame; k++) {
|
|
tonalityBand[e] += quotaMatrix[startIndex + k][no_enMaxBand[e]] >> 1;
|
|
}
|
|
globalTonality += tonalityBand[e] >> 2; /* headroom of 2+1 (max. 5 additions) */
|
|
}
|
|
|
|
return globalTonality;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief Calculates energy form real and imaginary part of
|
|
the QMF subsamples
|
|
|
|
\return none
|
|
|
|
****************************************************************************/
|
|
LNK_SECTION_CODE_L1
|
|
static void
|
|
FDKsbrEnc_getEnergyFromCplxQmfData(FIXP_DBL **RESTRICT energyValues,/*!< the result of the operation */
|
|
FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */
|
|
FIXP_DBL **RESTRICT imagValues, /*!< the imaginary part of the QMF subsamples */
|
|
INT numberBands, /*!< number of QMF bands */
|
|
INT numberCols, /*!< number of QMF subsamples */
|
|
INT *qmfScale, /*!< sclefactor of QMF subsamples */
|
|
INT *energyScale) /*!< scalefactor of energies */
|
|
{
|
|
int j, k;
|
|
int scale;
|
|
FIXP_DBL max_val = FL2FXCONST_DBL(0.0f);
|
|
|
|
/* Get Scratch buffer */
|
|
C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, QMF_CHANNELS*QMF_MAX_TIME_SLOTS/2);
|
|
|
|
/* Get max possible scaling of QMF data */
|
|
scale = DFRACT_BITS;
|
|
for (k=0; k<numberCols; k++) {
|
|
scale = fixMin(scale, fixMin(getScalefactor(realValues[k], numberBands), getScalefactor(imagValues[k], numberBands)));
|
|
}
|
|
|
|
/* Tweak scaling stability for zero signal to non-zero signal transitions */
|
|
if (scale >= DFRACT_BITS-1) {
|
|
scale = (FRACT_BITS-1-*qmfScale);
|
|
}
|
|
/* prevent scaling of QFM values to -1.f */
|
|
scale = fixMax(0,scale-1);
|
|
|
|
/* Update QMF scale */
|
|
*qmfScale += scale;
|
|
|
|
/*
|
|
Calculate energy of each time slot pair, max energy
|
|
and shift QMF values as far as possible to the left.
|
|
*/
|
|
{
|
|
FIXP_DBL *nrgValues = tmpNrg;
|
|
for (k=0; k<numberCols; k+=2)
|
|
{
|
|
/* Load band vector addresses of 2 consecutive timeslots */
|
|
FIXP_DBL *RESTRICT r0 = realValues[k];
|
|
FIXP_DBL *RESTRICT i0 = imagValues[k];
|
|
FIXP_DBL *RESTRICT r1 = realValues[k+1];
|
|
FIXP_DBL *RESTRICT i1 = imagValues[k+1];
|
|
for (j=0; j<numberBands; j++)
|
|
{
|
|
FIXP_DBL energy;
|
|
FIXP_DBL tr0,tr1,ti0,ti1;
|
|
|
|
/* Read QMF values of 2 timeslots */
|
|
tr0 = r0[j]; tr1 = r1[j]; ti0 = i0[j]; ti1 = i1[j];
|
|
|
|
/* Scale QMF Values and Calc Energy of both timeslots */
|
|
tr0 <<= scale;
|
|
ti0 <<= scale;
|
|
energy = fPow2AddDiv2(fPow2Div2(tr0), ti0) >> 1;
|
|
|
|
tr1 <<= scale;
|
|
ti1 <<= scale;
|
|
energy += fPow2AddDiv2(fPow2Div2(tr1), ti1) >> 1;
|
|
|
|
/* Write timeslot pair energy to scratch */
|
|
*nrgValues++ = energy;
|
|
max_val = fixMax(max_val, energy);
|
|
|
|
/* Write back scaled QMF values */
|
|
r0[j] = tr0; r1[j] = tr1; i0[j] = ti0; i1[j] = ti1;
|
|
}
|
|
}
|
|
}
|
|
/* energyScale: scalefactor energies of current frame */
|
|
*energyScale = 2*(*qmfScale)-1; /* if qmfScale > 0: nr of right shifts otherwise nr of left shifts */
|
|
|
|
/* Scale timeslot pair energies and write to output buffer */
|
|
scale = CountLeadingBits(max_val);
|
|
{
|
|
FIXP_DBL *nrgValues = tmpNrg;
|
|
for (k=0; k<numberCols>>1; k++) {
|
|
scaleValues(energyValues[k], nrgValues, numberBands, scale);
|
|
nrgValues += numberBands;
|
|
}
|
|
*energyScale += scale;
|
|
}
|
|
|
|
/* Free Scratch buffer */
|
|
C_ALLOC_SCRATCH_END(tmpNrg, FIXP_DBL, QMF_CHANNELS*QMF_MAX_TIME_SLOTS/2);
|
|
}
|
|
|
|
LNK_SECTION_CODE_L1
|
|
static void
|
|
FDKsbrEnc_getEnergyFromCplxQmfDataFull(FIXP_DBL **RESTRICT energyValues,/*!< the result of the operation */
|
|
FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */
|
|
FIXP_DBL **RESTRICT imagValues, /*!< the imaginary part of the QMF subsamples */
|
|
int numberBands, /*!< number of QMF bands */
|
|
int numberCols, /*!< number of QMF subsamples */
|
|
int *qmfScale, /*!< sclefactor of QMF subsamples */
|
|
int *energyScale) /*!< scalefactor of energies */
|
|
{
|
|
int j, k;
|
|
int scale;
|
|
FIXP_DBL max_val = FL2FXCONST_DBL(0.0f);
|
|
|
|
/* Get Scratch buffer */
|
|
C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2);
|
|
|
|
FDK_ASSERT(numberBands <= QMF_CHANNELS);
|
|
FDK_ASSERT(numberCols <= QMF_MAX_TIME_SLOTS/2);
|
|
|
|
/* Get max possible scaling of QMF data */
|
|
scale = DFRACT_BITS;
|
|
for (k=0; k<numberCols; k++) {
|
|
scale = fixMin(scale, fixMin(getScalefactor(realValues[k], numberBands), getScalefactor(imagValues[k], numberBands)));
|
|
}
|
|
|
|
/* Tweak scaling stability for zero signal to non-zero signal transitions */
|
|
if (scale >= DFRACT_BITS-1) {
|
|
scale = (FRACT_BITS-1-*qmfScale);
|
|
}
|
|
/* prevent scaling of QFM values to -1.f */
|
|
scale = fixMax(0,scale-1);
|
|
|
|
/* Update QMF scale */
|
|
*qmfScale += scale;
|
|
|
|
/*
|
|
Calculate energy of each time slot pair, max energy
|
|
and shift QMF values as far as possible to the left.
|
|
*/
|
|
{
|
|
FIXP_DBL *nrgValues = tmpNrg;
|
|
for (k=0; k<numberCols; k++)
|
|
{
|
|
/* Load band vector addresses of 2 consecutive timeslots */
|
|
FIXP_DBL *RESTRICT r0 = realValues[k];
|
|
FIXP_DBL *RESTRICT i0 = imagValues[k];
|
|
for (j=0; j<numberBands; j++)
|
|
{
|
|
FIXP_DBL energy;
|
|
FIXP_DBL tr0,ti0;
|
|
|
|
/* Read QMF values of 2 timeslots */
|
|
tr0 = r0[j]; ti0 = i0[j];
|
|
|
|
/* Scale QMF Values and Calc Energy of both timeslots */
|
|
tr0 <<= scale;
|
|
ti0 <<= scale;
|
|
energy = fPow2AddDiv2(fPow2Div2(tr0), ti0);
|
|
*nrgValues++ = energy;
|
|
|
|
max_val = fixMax(max_val, energy);
|
|
|
|
/* Write back scaled QMF values */
|
|
r0[j] = tr0; i0[j] = ti0;
|
|
}
|
|
}
|
|
}
|
|
/* energyScale: scalefactor energies of current frame */
|
|
*energyScale = 2*(*qmfScale)-1; /* if qmfScale > 0: nr of right shifts otherwise nr of left shifts */
|
|
|
|
/* Scale timeslot pair energies and write to output buffer */
|
|
scale = CountLeadingBits(max_val);
|
|
{
|
|
FIXP_DBL *nrgValues = tmpNrg;
|
|
for (k=0; k<numberCols; k++) {
|
|
scaleValues(energyValues[k], nrgValues, numberBands, scale);
|
|
nrgValues += numberBands;
|
|
}
|
|
*energyScale += scale;
|
|
}
|
|
|
|
/* Free Scratch buffer */
|
|
C_ALLOC_SCRATCH_END(tmpNrg, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief Quantisation of the panorama value (balance)
|
|
|
|
\return the quantized pan value
|
|
|
|
****************************************************************************/
|
|
static INT
|
|
mapPanorama(INT nrgVal, /*! integer value of the energy */
|
|
INT ampRes, /*! amplitude resolution [1.5/3dB] */
|
|
INT *quantError /*! quantization error of energy val*/
|
|
)
|
|
{
|
|
int i;
|
|
INT min_val, val;
|
|
UCHAR panIndex;
|
|
INT sign;
|
|
|
|
sign = nrgVal > 0 ? 1 : -1;
|
|
|
|
nrgVal *= sign;
|
|
|
|
min_val = FDK_INT_MAX;
|
|
panIndex = 0;
|
|
for (i = 0; i < maxIndex[ampRes]; i++) {
|
|
val = fixp_abs ((nrgVal - (INT)panTable[ampRes][i]));
|
|
|
|
if (val < min_val) {
|
|
min_val = val;
|
|
panIndex = i;
|
|
}
|
|
}
|
|
|
|
*quantError=min_val;
|
|
|
|
return panTable[ampRes][maxIndex[ampRes]-1] + sign * panTable[ampRes][panIndex];
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief Quantisation of the noise floor levels
|
|
|
|
\return void
|
|
|
|
****************************************************************************/
|
|
static void
|
|
sbrNoiseFloorLevelsQuantisation(SCHAR *RESTRICT iNoiseLevels, /*! quantized noise levels */
|
|
FIXP_DBL *RESTRICT NoiseLevels, /*! the noise levels */
|
|
INT coupling /*! the coupling flag */
|
|
)
|
|
{
|
|
INT i;
|
|
INT tmp, dummy;
|
|
|
|
/* Quantisation, similar to sfb quant... */
|
|
for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) {
|
|
/* tmp = NoiseLevels[i] > (PFLOAT)30.0f ? 30: (INT) (NoiseLevels[i] + (PFLOAT)0.5); */
|
|
/* 30>>6 = 0.46875 */
|
|
if ((FIXP_DBL)NoiseLevels[i] > FL2FXCONST_DBL(0.46875f)) {
|
|
tmp = 30;
|
|
}
|
|
else {
|
|
/* tmp = (INT)((FIXP_DBL)NoiseLevels[i] + (FL2FXCONST_DBL(0.5f)>>(*/ /* FRACT_BITS+ */ /* 6-1)));*/
|
|
/* tmp = tmp >> (DFRACT_BITS-1-6); */ /* conversion to integer happens here */
|
|
/* rounding is done by shifting one bit less than necessary to the right, adding '1' and then shifting the final bit */
|
|
tmp = ((((INT)NoiseLevels[i])>>(DFRACT_BITS-1-LD_DATA_SHIFT)) ); /* conversion to integer */
|
|
if (tmp != 0)
|
|
tmp += 1;
|
|
}
|
|
|
|
if (coupling) {
|
|
tmp = tmp < -30 ? -30 : tmp;
|
|
tmp = mapPanorama (tmp,1,&dummy);
|
|
}
|
|
iNoiseLevels[i] = tmp;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief Calculation of noise floor for coupling
|
|
|
|
\return void
|
|
|
|
****************************************************************************/
|
|
static void
|
|
coupleNoiseFloor(FIXP_DBL *RESTRICT noise_level_left, /*! noise level left (modified)*/
|
|
FIXP_DBL *RESTRICT noise_level_right /*! noise level right (modified)*/
|
|
)
|
|
{
|
|
FIXP_DBL cmpValLeft,cmpValRight;
|
|
INT i;
|
|
FIXP_DBL temp1,temp2;
|
|
|
|
for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) {
|
|
|
|
/* Calculation of the power function using ld64:
|
|
z = x^y;
|
|
z' = CalcLd64(z) = y*CalcLd64(x)/64;
|
|
z = CalcInvLd64(z');
|
|
*/
|
|
cmpValLeft = NOISE_FLOOR_OFFSET_64 - noise_level_left[i];
|
|
cmpValRight = NOISE_FLOOR_OFFSET_64 - noise_level_right[i];
|
|
|
|
if (cmpValRight < FL2FXCONST_DBL(0.0f)) {
|
|
temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]);
|
|
}
|
|
else {
|
|
temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]);
|
|
temp1 = temp1 << (DFRACT_BITS-1-LD_DATA_SHIFT-1); /* INT to fract conversion of result, if input of CalcInvLdData is positiv */
|
|
}
|
|
|
|
if (cmpValLeft < FL2FXCONST_DBL(0.0f)) {
|
|
temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]);
|
|
}
|
|
else {
|
|
temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]);
|
|
temp2 = temp2 << (DFRACT_BITS-1-LD_DATA_SHIFT-1); /* INT to fract conversion of result, if input of CalcInvLdData is positiv */
|
|
}
|
|
|
|
|
|
if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && (cmpValRight < FL2FXCONST_DBL(0.0f))) {
|
|
noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>1) + (temp2>>1)))); /* no scaling needed! both values are dfract */
|
|
noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1);
|
|
}
|
|
|
|
if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && (cmpValRight >= FL2FXCONST_DBL(0.0f))) {
|
|
noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>1) + (temp2>>1))) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */
|
|
noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1);
|
|
}
|
|
|
|
if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && (cmpValRight < FL2FXCONST_DBL(0.0f))) {
|
|
noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>(7+1)) + (temp2>>1))) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */
|
|
noise_level_right[i] = (CalcLdData(temp2) + FL2FXCONST_DBL(0.109375f)) - CalcLdData(temp1);
|
|
}
|
|
|
|
if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && (cmpValRight >= FL2FXCONST_DBL(0.0f))) {
|
|
noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>1) + (temp2>>(7+1)))) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */
|
|
noise_level_right[i] = CalcLdData(temp2) - (CalcLdData(temp1) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief Calculation of energy starting in lower band (li) up to upper band (ui)
|
|
over slots (start_pos) to (stop_pos)
|
|
|
|
\return void
|
|
|
|
****************************************************************************/
|
|
static FIXP_DBL
|
|
getEnvSfbEnergy(INT li, /*! lower band */
|
|
INT ui, /*! upper band */
|
|
INT start_pos, /*! start slot */
|
|
INT stop_pos, /*! stop slot */
|
|
INT border_pos, /*! slots scaling border */
|
|
FIXP_DBL **YBuffer, /*! sfb energy buffer */
|
|
INT YBufferSzShift, /*! Energy buffer index scale */
|
|
INT scaleNrg0, /*! scaling of lower slots */
|
|
INT scaleNrg1) /*! scaling of upper slots */
|
|
{
|
|
/* use dynamic scaling for outer energy loop;
|
|
energies are critical and every bit is important */
|
|
int sc0, sc1, k, l;
|
|
|
|
FIXP_DBL nrgSum, nrg1, nrg2, accu1, accu2;
|
|
INT dynScale, dynScale1, dynScale2;
|
|
if(ui-li==0) dynScale = DFRACT_BITS-1;
|
|
else
|
|
dynScale = CalcLdInt(ui-li)>>(DFRACT_BITS-1-LD_DATA_SHIFT);
|
|
|
|
sc0 = fixMin(scaleNrg0,Y_NRG_SCALE); sc1 = fixMin(scaleNrg1,Y_NRG_SCALE);
|
|
/* dynScale{1,2} is set such that the right shift below is positive */
|
|
dynScale1 = fixMin((scaleNrg0-sc0),dynScale);
|
|
dynScale2 = fixMin((scaleNrg1-sc1),dynScale);
|
|
nrgSum = accu1 = accu2 = (FIXP_DBL)0;
|
|
|
|
for (k = li; k < ui; k++) {
|
|
nrg1 = nrg2 = (FIXP_DBL)0;
|
|
for (l = start_pos; l < border_pos; l++) {
|
|
nrg1 += YBuffer[l>>YBufferSzShift][k] >> sc0;
|
|
}
|
|
for (; l < stop_pos; l++) {
|
|
nrg2 += YBuffer[l>>YBufferSzShift][k] >> sc1;
|
|
}
|
|
accu1 += (nrg1>>dynScale1);
|
|
accu2 += (nrg2>>dynScale2);
|
|
}
|
|
/* This shift factor is always positive. See comment above. */
|
|
nrgSum += ( accu1 >> fixMin((scaleNrg0-sc0-dynScale1),(DFRACT_BITS-1)) )
|
|
+ ( accu2 >> fixMin((scaleNrg1-sc1-dynScale2),(DFRACT_BITS-1)) );
|
|
|
|
return nrgSum;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief Energy compensation in missing harmonic mode
|
|
|
|
\return void
|
|
|
|
****************************************************************************/
|
|
static FIXP_DBL
|
|
mhLoweringEnergy(FIXP_DBL nrg, INT M)
|
|
{
|
|
/*
|
|
Compensating for the fact that we in the decoder map the "average energy to every QMF
|
|
band, and use this when we calculate the boost-factor. Since the mapped energy isn't
|
|
the average energy but the maximum energy in case of missing harmonic creation, we will
|
|
in the boost function calculate that too much limiting has been applied and hence we will
|
|
boost the signal although it isn't called for. Hence we need to compensate for this by
|
|
lowering the transmitted energy values for the sines so they will get the correct level
|
|
after the boost is applied.
|
|
*/
|
|
if(M > 2){
|
|
INT tmpScale;
|
|
tmpScale = CountLeadingBits(nrg);
|
|
nrg <<= tmpScale;
|
|
nrg = fMult(nrg, FL2FXCONST_DBL(0.398107267f)); /* The maximum boost is 1.584893, so the maximum attenuation should be square(1/1.584893) = 0.398107267 */
|
|
nrg >>= tmpScale;
|
|
}
|
|
else{
|
|
if(M > 1){
|
|
nrg >>= 1;
|
|
}
|
|
}
|
|
|
|
return nrg;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief Energy compensation in none missing harmonic mode
|
|
|
|
\return void
|
|
|
|
****************************************************************************/
|
|
static FIXP_DBL nmhLoweringEnergy(
|
|
FIXP_DBL nrg,
|
|
const FIXP_DBL nrgSum,
|
|
const INT nrgSum_scale,
|
|
const INT M
|
|
)
|
|
{
|
|
if (nrg>FL2FXCONST_DBL(0)) {
|
|
int sc=0;
|
|
/* gain = nrgSum / (nrg*(M+1)) */
|
|
FIXP_DBL gain = fMult(fDivNorm(nrgSum, nrg, &sc), GetInvInt(M+1));
|
|
sc += nrgSum_scale;
|
|
|
|
/* reduce nrg if gain smaller 1.f */
|
|
if ( !((sc>=0) && ( gain > ((FIXP_DBL)MAXVAL_DBL>>sc) )) ) {
|
|
nrg = fMult(scaleValue(gain,sc), nrg);
|
|
}
|
|
}
|
|
return nrg;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief calculates the envelope values from the energies, depending on
|
|
framing and stereo mode
|
|
|
|
\return void
|
|
|
|
****************************************************************************/
|
|
static void
|
|
calculateSbrEnvelope (FIXP_DBL **RESTRICT YBufferLeft, /*! energy buffer left */
|
|
FIXP_DBL **RESTRICT YBufferRight, /*! energy buffer right */
|
|
int *RESTRICT YBufferScaleLeft, /*! scale energy buffer left */
|
|
int *RESTRICT YBufferScaleRight, /*! scale energy buffer right */
|
|
const SBR_FRAME_INFO *frame_info, /*! frame info vector */
|
|
SCHAR *RESTRICT sfb_nrgLeft, /*! sfb energy buffer left */
|
|
SCHAR *RESTRICT sfb_nrgRight, /*! sfb energy buffer right */
|
|
HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */
|
|
HANDLE_ENV_CHANNEL h_sbr, /*! envelope channel handle */
|
|
SBR_STEREO_MODE stereoMode, /*! stereo coding mode */
|
|
INT* maxQuantError, /*! maximum quantization error, for panorama. */
|
|
int YBufferSzShift) /*! Energy buffer index scale */
|
|
|
|
{
|
|
int i, j, m = 0;
|
|
INT no_of_bands, start_pos, stop_pos, li, ui;
|
|
FREQ_RES freq_res;
|
|
|
|
INT ca = 2 - h_sbr->encEnvData.init_sbr_amp_res;
|
|
INT oneBitLess = 0;
|
|
if (ca == 2)
|
|
oneBitLess = 1; /* LD_DATA_SHIFT => ld64 scaling; one bit less for rounding */
|
|
|
|
INT quantError;
|
|
INT nEnvelopes = frame_info->nEnvelopes;
|
|
INT short_env = frame_info->shortEnv - 1;
|
|
INT timeStep = h_sbr->sbrExtractEnvelope.time_step;
|
|
INT commonScale,scaleLeft0,scaleLeft1;
|
|
INT scaleRight0=0,scaleRight1=0;
|
|
|
|
commonScale = fixMin(YBufferScaleLeft[0],YBufferScaleLeft[1]);
|
|
|
|
if (stereoMode == SBR_COUPLING) {
|
|
commonScale = fixMin(commonScale,YBufferScaleRight[0]);
|
|
commonScale = fixMin(commonScale,YBufferScaleRight[1]);
|
|
}
|
|
|
|
commonScale = commonScale - 7;
|
|
|
|
scaleLeft0 = YBufferScaleLeft[0] - commonScale;
|
|
scaleLeft1 = YBufferScaleLeft[1] - commonScale ;
|
|
FDK_ASSERT ((scaleLeft0 >= 0) && (scaleLeft1 >= 0));
|
|
|
|
if (stereoMode == SBR_COUPLING) {
|
|
scaleRight0 = YBufferScaleRight[0] - commonScale;
|
|
scaleRight1 = YBufferScaleRight[1] - commonScale;
|
|
FDK_ASSERT ((scaleRight0 >= 0) && (scaleRight1 >= 0));
|
|
*maxQuantError = 0;
|
|
}
|
|
|
|
for (i = 0; i < nEnvelopes; i++) {
|
|
|
|
FIXP_DBL pNrgLeft[QMF_MAX_TIME_SLOTS];
|
|
FIXP_DBL pNrgRight[QMF_MAX_TIME_SLOTS];
|
|
int envNrg_scale;
|
|
FIXP_DBL envNrgLeft = FL2FXCONST_DBL(0.0f);
|
|
FIXP_DBL envNrgRight = FL2FXCONST_DBL(0.0f);
|
|
int missingHarmonic[QMF_MAX_TIME_SLOTS];
|
|
int count[QMF_MAX_TIME_SLOTS];
|
|
|
|
start_pos = timeStep * frame_info->borders[i];
|
|
stop_pos = timeStep * frame_info->borders[i + 1];
|
|
freq_res = frame_info->freqRes[i];
|
|
no_of_bands = h_con->nSfb[freq_res];
|
|
envNrg_scale = DFRACT_BITS-fNormz((FIXP_DBL)no_of_bands);
|
|
|
|
if (i == short_env) {
|
|
stop_pos -= fixMax(2, timeStep); /* consider at least 2 QMF slots less for short envelopes (envelopes just before transients) */
|
|
}
|
|
|
|
for (j = 0; j < no_of_bands; j++) {
|
|
FIXP_DBL nrgLeft = FL2FXCONST_DBL(0.0f);
|
|
FIXP_DBL nrgRight = FL2FXCONST_DBL(0.0f);
|
|
|
|
li = h_con->freqBandTable[freq_res][j];
|
|
ui = h_con->freqBandTable[freq_res][j + 1];
|
|
|
|
if(freq_res == FREQ_RES_HIGH){
|
|
if(j == 0 && ui-li > 1){
|
|
li++;
|
|
}
|
|
}
|
|
else{
|
|
if(j == 0 && ui-li > 2){
|
|
li++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Find out whether a sine will be missing in the scale-factor
|
|
band that we're currently processing.
|
|
*/
|
|
missingHarmonic[j] = 0;
|
|
|
|
if(h_sbr->encEnvData.addHarmonicFlag){
|
|
|
|
if(freq_res == FREQ_RES_HIGH){
|
|
if(h_sbr->encEnvData.addHarmonic[j]){ /*A missing sine in the current band*/
|
|
missingHarmonic[j] = 1;
|
|
}
|
|
}
|
|
else{
|
|
INT i;
|
|
INT startBandHigh = 0;
|
|
INT stopBandHigh = 0;
|
|
|
|
while(h_con->freqBandTable[FREQ_RES_HIGH][startBandHigh] < h_con->freqBandTable[FREQ_RES_LOW][j])
|
|
startBandHigh++;
|
|
while(h_con->freqBandTable[FREQ_RES_HIGH][stopBandHigh] < h_con->freqBandTable[FREQ_RES_LOW][j + 1])
|
|
stopBandHigh++;
|
|
|
|
for(i = startBandHigh; i<stopBandHigh; i++){
|
|
if(h_sbr->encEnvData.addHarmonic[i]){
|
|
missingHarmonic[j] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
If a sine is missing in a scalefactorband, with more than one qmf channel
|
|
use the nrg from the channel with the largest nrg rather than the mean.
|
|
Compensate for the boost calculation in the decdoder.
|
|
*/
|
|
int border_pos = fixMin(stop_pos, h_sbr->sbrExtractEnvelope.YBufferWriteOffset<<YBufferSzShift);
|
|
|
|
if(missingHarmonic[j]){
|
|
|
|
int k;
|
|
count[j] = stop_pos - start_pos;
|
|
nrgLeft = FL2FXCONST_DBL(0.0f);
|
|
|
|
for (k = li; k < ui; k++) {
|
|
FIXP_DBL tmpNrg;
|
|
tmpNrg = getEnvSfbEnergy(k,
|
|
k+1,
|
|
start_pos,
|
|
stop_pos,
|
|
border_pos,
|
|
YBufferLeft,
|
|
YBufferSzShift,
|
|
scaleLeft0,
|
|
scaleLeft1);
|
|
|
|
nrgLeft = fixMax(nrgLeft, tmpNrg);
|
|
}
|
|
|
|
/* Energy lowering compensation */
|
|
nrgLeft = mhLoweringEnergy(nrgLeft, ui-li);
|
|
|
|
if (stereoMode == SBR_COUPLING) {
|
|
|
|
nrgRight = FL2FXCONST_DBL(0.0f);
|
|
|
|
for (k = li; k < ui; k++) {
|
|
FIXP_DBL tmpNrg;
|
|
tmpNrg = getEnvSfbEnergy(k,
|
|
k+1,
|
|
start_pos,
|
|
stop_pos,
|
|
border_pos,
|
|
YBufferRight,
|
|
YBufferSzShift,
|
|
scaleRight0,
|
|
scaleRight1);
|
|
|
|
nrgRight = fixMax(nrgRight, tmpNrg);
|
|
}
|
|
|
|
/* Energy lowering compensation */
|
|
nrgRight = mhLoweringEnergy(nrgRight, ui-li);
|
|
}
|
|
} /* end missingHarmonic */
|
|
else{
|
|
count[j] = (stop_pos - start_pos) * (ui - li);
|
|
|
|
nrgLeft = getEnvSfbEnergy(li,
|
|
ui,
|
|
start_pos,
|
|
stop_pos,
|
|
border_pos,
|
|
YBufferLeft,
|
|
YBufferSzShift,
|
|
scaleLeft0,
|
|
scaleLeft1);
|
|
|
|
if (stereoMode == SBR_COUPLING) {
|
|
nrgRight = getEnvSfbEnergy(li,
|
|
ui,
|
|
start_pos,
|
|
stop_pos,
|
|
border_pos,
|
|
YBufferRight,
|
|
YBufferSzShift,
|
|
scaleRight0,
|
|
scaleRight1);
|
|
}
|
|
} /* !missingHarmonic */
|
|
|
|
/* save energies */
|
|
pNrgLeft[j] = nrgLeft;
|
|
pNrgRight[j] = nrgRight;
|
|
envNrgLeft += (nrgLeft>>envNrg_scale);
|
|
envNrgRight += (nrgRight>>envNrg_scale);
|
|
} /* j */
|
|
|
|
for (j = 0; j < no_of_bands; j++) {
|
|
|
|
FIXP_DBL nrgLeft2 = FL2FXCONST_DBL(0.0f);
|
|
FIXP_DBL nrgLeft = pNrgLeft[j];
|
|
FIXP_DBL nrgRight = pNrgRight[j];
|
|
|
|
/* None missing harmonic Energy lowering compensation */
|
|
if(!missingHarmonic[j] && h_sbr->fLevelProtect) {
|
|
/* in case of missing energy in base band,
|
|
reduce reference energy to prevent overflows in decoder output */
|
|
nrgLeft = nmhLoweringEnergy(nrgLeft, envNrgLeft, envNrg_scale, no_of_bands);
|
|
if (stereoMode == SBR_COUPLING) {
|
|
nrgRight = nmhLoweringEnergy(nrgRight, envNrgRight, envNrg_scale, no_of_bands);
|
|
}
|
|
}
|
|
|
|
if (stereoMode == SBR_COUPLING) {
|
|
/* calc operation later with log */
|
|
nrgLeft2 = nrgLeft;
|
|
nrgLeft = (nrgRight + nrgLeft) >> 1;
|
|
}
|
|
|
|
/* nrgLeft = f20_log2(nrgLeft / (PFLOAT)(count * h_sbr->sbrQmf.no_channels))+(PFLOAT)44; */
|
|
/* If nrgLeft == 0 then the Log calculations below do fail. */
|
|
if (nrgLeft > FL2FXCONST_DBL(0.0f))
|
|
{
|
|
FIXP_DBL tmp0,tmp1,tmp2,tmp3;
|
|
INT tmpScale;
|
|
|
|
tmpScale = CountLeadingBits(nrgLeft);
|
|
nrgLeft = nrgLeft << tmpScale;
|
|
|
|
tmp0 = CalcLdData(nrgLeft); /* scaled by 1/64 */
|
|
tmp1 = ((FIXP_DBL) (commonScale+tmpScale)) << (DFRACT_BITS-1-LD_DATA_SHIFT-1); /* scaled by 1/64 */
|
|
tmp2 = ((FIXP_DBL)(count[j]*h_con->noQmfBands)) << (DFRACT_BITS-1-14-1);
|
|
tmp2 = CalcLdData(tmp2); /* scaled by 1/64 */
|
|
tmp3 = FL2FXCONST_DBL(0.6875f-0.21875f-0.015625f)>>1; /* scaled by 1/64 */
|
|
|
|
nrgLeft = ((tmp0-tmp2)>>1) + (tmp3 - tmp1);
|
|
} else {
|
|
nrgLeft = FL2FXCONST_DBL(-1.0f);
|
|
}
|
|
|
|
/* ld64 to integer conversion */
|
|
nrgLeft = fixMin(fixMax(nrgLeft,FL2FXCONST_DBL(0.0f)),(FL2FXCONST_DBL(0.5f)>>oneBitLess));
|
|
nrgLeft = (FIXP_DBL)(LONG)nrgLeft >> (DFRACT_BITS-1-LD_DATA_SHIFT-1-oneBitLess-1);
|
|
sfb_nrgLeft[m] = ((INT)nrgLeft+1)>>1; /* rounding */
|
|
|
|
if (stereoMode == SBR_COUPLING) {
|
|
FIXP_DBL scaleFract;
|
|
int sc0, sc1;
|
|
|
|
nrgLeft2 = fixMax((FIXP_DBL)0x1, nrgLeft2);
|
|
nrgRight = fixMax((FIXP_DBL)0x1, nrgRight);
|
|
|
|
sc0 = CountLeadingBits(nrgLeft2);
|
|
sc1 = CountLeadingBits(nrgRight);
|
|
|
|
scaleFract = ((FIXP_DBL)(sc0-sc1)) << (DFRACT_BITS-1-LD_DATA_SHIFT); /* scale value in ld64 representation */
|
|
nrgRight = CalcLdData(nrgLeft2<<sc0) - CalcLdData(nrgRight<<sc1) - scaleFract;
|
|
|
|
/* ld64 to integer conversion */
|
|
nrgRight = (FIXP_DBL)(LONG)(nrgRight) >> (DFRACT_BITS-1-LD_DATA_SHIFT-1-oneBitLess);
|
|
nrgRight = (nrgRight+(FIXP_DBL)1)>>1; /* rounding */
|
|
|
|
sfb_nrgRight[m] = mapPanorama (nrgRight,h_sbr->encEnvData.init_sbr_amp_res,&quantError);
|
|
|
|
*maxQuantError = fixMax(quantError, *maxQuantError);
|
|
}
|
|
|
|
m++;
|
|
} /* j */
|
|
|
|
/* Do energy compensation for sines that are present in two
|
|
QMF-bands in the original, but will only occur in one band in
|
|
the decoder due to the synthetic sine coding.*/
|
|
if (h_con->useParametricCoding) {
|
|
m-=no_of_bands;
|
|
for (j = 0; j < no_of_bands; j++) {
|
|
if (freq_res==FREQ_RES_HIGH && h_sbr->sbrExtractEnvelope.envelopeCompensation[j]){
|
|
sfb_nrgLeft[m] -= (ca * fixp_abs((INT)h_sbr->sbrExtractEnvelope.envelopeCompensation[j]));
|
|
}
|
|
sfb_nrgLeft[m] = fixMax(0, sfb_nrgLeft[m]);
|
|
m++;
|
|
}
|
|
} /* useParametricCoding */
|
|
|
|
} /* i*/
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief calculates the noise floor and the envelope values from the
|
|
energies, depending on framing and stereo mode
|
|
|
|
FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the
|
|
envelope and the noise floor. The function includes the following processes:
|
|
|
|
-Analysis subband filtering.
|
|
-Encoding SA and pan parameters (if enabled).
|
|
-Transient detection.
|
|
|
|
****************************************************************************/
|
|
|
|
LNK_SECTION_CODE_L1
|
|
void
|
|
FDKsbrEnc_extractSbrEnvelope1 (
|
|
HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */
|
|
HANDLE_SBR_HEADER_DATA sbrHeaderData,
|
|
HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData,
|
|
HANDLE_ENV_CHANNEL hEnvChan,
|
|
HANDLE_COMMON_DATA hCmonData,
|
|
SBR_ENV_TEMP_DATA *eData,
|
|
SBR_FRAME_TEMP_DATA *fData
|
|
)
|
|
{
|
|
|
|
HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope;
|
|
|
|
if (sbrExtrEnv->YBufferSzShift == 0)
|
|
FDKsbrEnc_getEnergyFromCplxQmfDataFull(&sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset],
|
|
sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset,
|
|
sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset,
|
|
h_con->noQmfBands,
|
|
sbrExtrEnv->no_cols,
|
|
&hEnvChan->qmfScale,
|
|
&sbrExtrEnv->YBufferScale[1]);
|
|
else
|
|
FDKsbrEnc_getEnergyFromCplxQmfData(&sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset],
|
|
sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset,
|
|
sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset,
|
|
h_con->noQmfBands,
|
|
sbrExtrEnv->no_cols,
|
|
&hEnvChan->qmfScale,
|
|
&sbrExtrEnv->YBufferScale[1]);
|
|
|
|
|
|
|
|
/*
|
|
Precalculation of Tonality Quotas COEFF Transform OK
|
|
*/
|
|
FDKsbrEnc_CalculateTonalityQuotas(&hEnvChan->TonCorr,
|
|
sbrExtrEnv->rBuffer,
|
|
sbrExtrEnv->iBuffer,
|
|
h_con->freqBandTable[HI][h_con->nSfb[HI]],
|
|
hEnvChan->qmfScale);
|
|
|
|
|
|
if(h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
|
|
FIXP_DBL tonality = FDKsbrEnc_GetTonality (
|
|
hEnvChan->TonCorr.quotaMatrix,
|
|
hEnvChan->TonCorr.numberOfEstimatesPerFrame,
|
|
hEnvChan->TonCorr.startIndexMatrix,
|
|
sbrExtrEnv->YBuffer + sbrExtrEnv->YBufferWriteOffset,
|
|
h_con->freqBandTable[HI][0]+1,
|
|
h_con->noQmfBands,
|
|
sbrExtrEnv->no_cols
|
|
);
|
|
|
|
hEnvChan->encEnvData.ton_HF[1] = hEnvChan->encEnvData.ton_HF[0];
|
|
hEnvChan->encEnvData.ton_HF[0] = tonality;
|
|
|
|
/* tonality is scaled by 2^19/0.524288f (fract part of RELAXATION) */
|
|
hEnvChan->encEnvData.global_tonality = (hEnvChan->encEnvData.ton_HF[0]>>1) + (hEnvChan->encEnvData.ton_HF[1]>>1);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Transient detection COEFF Transform OK
|
|
*/
|
|
if(h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY)
|
|
{
|
|
FDKsbrEnc_fastTransientDetect(
|
|
&hEnvChan->sbrFastTransientDetector,
|
|
sbrExtrEnv->YBuffer,
|
|
sbrExtrEnv->YBufferScale,
|
|
sbrExtrEnv->YBufferWriteOffset,
|
|
eData->transient_info
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
FDKsbrEnc_transientDetect(&hEnvChan->sbrTransientDetector,
|
|
sbrExtrEnv->YBuffer,
|
|
sbrExtrEnv->YBufferScale,
|
|
eData->transient_info,
|
|
sbrExtrEnv->YBufferWriteOffset,
|
|
sbrExtrEnv->YBufferSzShift,
|
|
sbrExtrEnv->time_step,
|
|
hEnvChan->SbrEnvFrame.frameMiddleSlot);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Generate flags for 2 env in a FIXFIX-frame.
|
|
Remove this function to get always 1 env per FIXFIX-frame.
|
|
*/
|
|
|
|
/*
|
|
frame Splitter COEFF Transform OK
|
|
*/
|
|
FDKsbrEnc_frameSplitter(sbrExtrEnv->YBuffer,
|
|
sbrExtrEnv->YBufferScale,
|
|
&hEnvChan->sbrTransientDetector,
|
|
h_con->freqBandTable[1],
|
|
eData->transient_info,
|
|
sbrExtrEnv->YBufferWriteOffset,
|
|
sbrExtrEnv->YBufferSzShift,
|
|
h_con->nSfb[1],
|
|
sbrExtrEnv->time_step,
|
|
sbrExtrEnv->no_cols,
|
|
&hEnvChan->encEnvData.global_tonality);
|
|
|
|
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief calculates the noise floor and the envelope values from the
|
|
energies, depending on framing and stereo mode
|
|
|
|
FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the
|
|
envelope and the noise floor. The function includes the following processes:
|
|
|
|
-Determine time/frequency division of current granule.
|
|
-Sending transient info to bitstream.
|
|
-Set amp_res to 1.5 dB if the current frame contains only one envelope.
|
|
-Lock dynamic bandwidth frequency change if the next envelope not starts on a
|
|
frame boundary.
|
|
-MDCT transposer (needed to detect where harmonics will be missing).
|
|
-Spectrum Estimation (used for pulse train and missing harmonics detection).
|
|
-Pulse train detection.
|
|
-Inverse Filtering detection.
|
|
-Waveform Coding.
|
|
-Missing Harmonics detection.
|
|
-Extract envelope of current frame.
|
|
-Noise floor estimation.
|
|
-Noise floor quantisation and coding.
|
|
-Encode envelope of current frame.
|
|
-Send the encoded data to the bitstream.
|
|
-Write to bitstream.
|
|
|
|
****************************************************************************/
|
|
|
|
LNK_SECTION_CODE_L1
|
|
void
|
|
FDKsbrEnc_extractSbrEnvelope2 (
|
|
HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */
|
|
HANDLE_SBR_HEADER_DATA sbrHeaderData,
|
|
HANDLE_PARAMETRIC_STEREO hParametricStereo,
|
|
HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData,
|
|
HANDLE_ENV_CHANNEL h_envChan0,
|
|
HANDLE_ENV_CHANNEL h_envChan1,
|
|
HANDLE_COMMON_DATA hCmonData,
|
|
SBR_ENV_TEMP_DATA *eData,
|
|
SBR_FRAME_TEMP_DATA *fData,
|
|
int clearOutput
|
|
)
|
|
{
|
|
HANDLE_ENV_CHANNEL h_envChan[MAX_NUM_CHANNELS] = {h_envChan0, h_envChan1};
|
|
int ch, i, j, c, YSzShift = h_envChan[0]->sbrExtractEnvelope.YBufferSzShift;
|
|
|
|
SBR_STEREO_MODE stereoMode = h_con->stereoMode;
|
|
int nChannels = h_con->nChannels;
|
|
const int *v_tuning;
|
|
static const int v_tuningHEAAC[6] = { 0, 2, 4, 0, 0, 0 };
|
|
|
|
static const int v_tuningELD[6] = { 0, 2, 3, 0, 0, 0 };
|
|
|
|
if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY)
|
|
v_tuning = v_tuningELD;
|
|
else
|
|
v_tuning = v_tuningHEAAC;
|
|
|
|
|
|
/*
|
|
Select stereo mode.
|
|
*/
|
|
if (stereoMode == SBR_COUPLING) {
|
|
if (eData[0].transient_info[1] && eData[1].transient_info[1]) {
|
|
eData[0].transient_info[0] = fixMin(eData[1].transient_info[0], eData[0].transient_info[0]);
|
|
eData[1].transient_info[0] = eData[0].transient_info[0];
|
|
}
|
|
else {
|
|
if (eData[0].transient_info[1] && !eData[1].transient_info[1]) {
|
|
eData[1].transient_info[0] = eData[0].transient_info[0];
|
|
}
|
|
else {
|
|
if (!eData[0].transient_info[1] && eData[1].transient_info[1])
|
|
eData[0].transient_info[0] = eData[1].transient_info[0];
|
|
else {
|
|
eData[0].transient_info[0] = fixMax(eData[1].transient_info[0], eData[0].transient_info[0]);
|
|
eData[1].transient_info[0] = eData[0].transient_info[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Determine time/frequency division of current granule
|
|
*/
|
|
eData[0].frame_info = FDKsbrEnc_frameInfoGenerator(&h_envChan[0]->SbrEnvFrame,
|
|
eData[0].transient_info,
|
|
h_envChan[0]->sbrExtractEnvelope.pre_transient_info,
|
|
h_envChan[0]->encEnvData.ldGrid,
|
|
v_tuning);
|
|
|
|
h_envChan[0]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid;
|
|
|
|
/* AAC LD patch for transient prediction */
|
|
if (h_envChan[0]->encEnvData.ldGrid && eData[0].transient_info[2]) {
|
|
/* if next frame will start with transient, set shortEnv to numEnvelopes(shortend Envelope = shortEnv-1)*/
|
|
h_envChan[0]->SbrEnvFrame.SbrFrameInfo.shortEnv = h_envChan[0]->SbrEnvFrame.SbrFrameInfo.nEnvelopes;
|
|
}
|
|
|
|
|
|
switch (stereoMode) {
|
|
case SBR_LEFT_RIGHT:
|
|
case SBR_SWITCH_LRC:
|
|
eData[1].frame_info = FDKsbrEnc_frameInfoGenerator(&h_envChan[1]->SbrEnvFrame,
|
|
eData[1].transient_info,
|
|
h_envChan[1]->sbrExtractEnvelope.pre_transient_info,
|
|
h_envChan[1]->encEnvData.ldGrid,
|
|
v_tuning);
|
|
|
|
h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[1]->SbrEnvFrame.SbrGrid;
|
|
|
|
if (h_envChan[1]->encEnvData.ldGrid && eData[1].transient_info[2]) {
|
|
/* if next frame will start with transient, set shortEnv to numEnvelopes(shortend Envelope = shortEnv-1)*/
|
|
h_envChan[1]->SbrEnvFrame.SbrFrameInfo.shortEnv = h_envChan[1]->SbrEnvFrame.SbrFrameInfo.nEnvelopes;
|
|
}
|
|
|
|
/* compare left and right frame_infos */
|
|
if (eData[0].frame_info->nEnvelopes != eData[1].frame_info->nEnvelopes) {
|
|
stereoMode = SBR_LEFT_RIGHT;
|
|
} else {
|
|
for (i = 0; i < eData[0].frame_info->nEnvelopes + 1; i++) {
|
|
if (eData[0].frame_info->borders[i] != eData[1].frame_info->borders[i]) {
|
|
stereoMode = SBR_LEFT_RIGHT;
|
|
break;
|
|
}
|
|
}
|
|
for (i = 0; i < eData[0].frame_info->nEnvelopes; i++) {
|
|
if (eData[0].frame_info->freqRes[i] != eData[1].frame_info->freqRes[i]) {
|
|
stereoMode = SBR_LEFT_RIGHT;
|
|
break;
|
|
}
|
|
}
|
|
if (eData[0].frame_info->shortEnv != eData[1].frame_info->shortEnv) {
|
|
stereoMode = SBR_LEFT_RIGHT;
|
|
}
|
|
}
|
|
break;
|
|
case SBR_COUPLING:
|
|
eData[1].frame_info = eData[0].frame_info;
|
|
h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid;
|
|
break;
|
|
case SBR_MONO:
|
|
/* nothing to do */
|
|
break;
|
|
default:
|
|
FDK_ASSERT (0);
|
|
}
|
|
|
|
|
|
for (ch = 0; ch < nChannels;ch++)
|
|
{
|
|
HANDLE_ENV_CHANNEL hEnvChan = h_envChan[ch];
|
|
HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope;
|
|
SBR_ENV_TEMP_DATA *ed = &eData[ch];
|
|
|
|
|
|
/*
|
|
Send transient info to bitstream and store for next call
|
|
*/
|
|
sbrExtrEnv->pre_transient_info[0] = ed->transient_info[0];/* tran_pos */
|
|
sbrExtrEnv->pre_transient_info[1] = ed->transient_info[1];/* tran_flag */
|
|
hEnvChan->encEnvData.noOfEnvelopes = ed->nEnvelopes = ed->frame_info->nEnvelopes; /* number of envelopes of current frame */
|
|
|
|
/*
|
|
Check if the current frame is divided into one envelope only. If so, set the amplitude
|
|
resolution to 1.5 dB, otherwise may set back to chosen value
|
|
*/
|
|
if( ( hEnvChan->encEnvData.hSbrBSGrid->frameClass == FIXFIX )
|
|
&& ( ed->nEnvelopes == 1 ) )
|
|
{
|
|
|
|
if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY)
|
|
{
|
|
/* Note: global_tonaliy_float_value == ((float)hEnvChan->encEnvData.global_tonality/((INT64)(1)<<(31-(19+2)))/0.524288*(2.0/3.0)));
|
|
threshold_float_value == ((float)h_con->thresholdAmpResFF_m/((INT64)(1)<<(31-(h_con->thresholdAmpResFF_e)))/0.524288*(2.0/3.0))); */
|
|
/* decision of SBR_AMP_RES */
|
|
if (fIsLessThan( /* global_tonality > threshold ? */
|
|
h_con->thresholdAmpResFF_m, h_con->thresholdAmpResFF_e,
|
|
hEnvChan->encEnvData.global_tonality, RELAXATION_SHIFT+2 )
|
|
)
|
|
{
|
|
hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5;
|
|
}
|
|
else {
|
|
hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_3_0;
|
|
}
|
|
} else {
|
|
hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5;
|
|
}
|
|
|
|
if ( hEnvChan->encEnvData.currentAmpResFF != hEnvChan->encEnvData.init_sbr_amp_res) {
|
|
|
|
FDKsbrEnc_InitSbrHuffmanTables(&hEnvChan->encEnvData,
|
|
&hEnvChan->sbrCodeEnvelope,
|
|
&hEnvChan->sbrCodeNoiseFloor,
|
|
hEnvChan->encEnvData.currentAmpResFF);
|
|
}
|
|
}
|
|
else {
|
|
if(sbrHeaderData->sbr_amp_res != hEnvChan->encEnvData.init_sbr_amp_res ) {
|
|
|
|
FDKsbrEnc_InitSbrHuffmanTables(&hEnvChan->encEnvData,
|
|
&hEnvChan->sbrCodeEnvelope,
|
|
&hEnvChan->sbrCodeNoiseFloor,
|
|
sbrHeaderData->sbr_amp_res);
|
|
}
|
|
}
|
|
|
|
if (!clearOutput) {
|
|
|
|
/*
|
|
Tonality correction parameter extraction (inverse filtering level, noise floor additional sines).
|
|
*/
|
|
FDKsbrEnc_TonCorrParamExtr(&hEnvChan->TonCorr,
|
|
hEnvChan->encEnvData.sbr_invf_mode_vec,
|
|
ed->noiseFloor,
|
|
&hEnvChan->encEnvData.addHarmonicFlag,
|
|
hEnvChan->encEnvData.addHarmonic,
|
|
sbrExtrEnv->envelopeCompensation,
|
|
ed->frame_info,
|
|
ed->transient_info,
|
|
h_con->freqBandTable[HI],
|
|
h_con->nSfb[HI],
|
|
hEnvChan->encEnvData.sbr_xpos_mode,
|
|
h_con->sbrSyntaxFlags);
|
|
|
|
}
|
|
|
|
/* Low energy in low band fix */
|
|
if ( hEnvChan->sbrTransientDetector.prevLowBandEnergy < hEnvChan->sbrTransientDetector.prevHighBandEnergy
|
|
&& hEnvChan->sbrTransientDetector.prevHighBandEnergy > FL2FX_DBL(0.03)
|
|
/* The fix needs the non-fast transient detector running.
|
|
It sets prevLowBandEnergy and prevHighBandEnergy. */
|
|
&& !(h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY)
|
|
)
|
|
{
|
|
int i;
|
|
|
|
hEnvChan->fLevelProtect = 1;
|
|
|
|
for (i=0; i<MAX_NUM_NOISE_VALUES; i++)
|
|
hEnvChan->encEnvData.sbr_invf_mode_vec[i] = INVF_HIGH_LEVEL;
|
|
} else {
|
|
hEnvChan->fLevelProtect = 0;
|
|
}
|
|
|
|
hEnvChan->encEnvData.sbr_invf_mode = hEnvChan->encEnvData.sbr_invf_mode_vec[0];
|
|
|
|
hEnvChan->encEnvData.noOfnoisebands = hEnvChan->TonCorr.sbrNoiseFloorEstimate.noNoiseBands;
|
|
|
|
|
|
} /* ch */
|
|
|
|
|
|
|
|
/*
|
|
Save number of scf bands per envelope
|
|
*/
|
|
for (ch = 0; ch < nChannels;ch++) {
|
|
for (i = 0; i < eData[ch].nEnvelopes; i++){
|
|
h_envChan[ch]->encEnvData.noScfBands[i] =
|
|
(eData[ch].frame_info->freqRes[i] == FREQ_RES_HIGH ? h_con->nSfb[FREQ_RES_HIGH] : h_con->nSfb[FREQ_RES_LOW]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Extract envelope of current frame.
|
|
*/
|
|
switch (stereoMode) {
|
|
case SBR_MONO:
|
|
calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL,
|
|
h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL,
|
|
eData[0].frame_info, eData[0].sfb_nrg, NULL,
|
|
h_con, h_envChan[0], SBR_MONO, NULL, YSzShift);
|
|
break;
|
|
case SBR_LEFT_RIGHT:
|
|
calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL,
|
|
h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL,
|
|
eData[0].frame_info, eData[0].sfb_nrg, NULL,
|
|
h_con, h_envChan[0], SBR_MONO, NULL, YSzShift);
|
|
calculateSbrEnvelope (h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL,
|
|
h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL,
|
|
eData[1].frame_info,eData[1].sfb_nrg, NULL,
|
|
h_con, h_envChan[1], SBR_MONO, NULL, YSzShift);
|
|
break;
|
|
case SBR_COUPLING:
|
|
calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, h_envChan[1]->sbrExtractEnvelope.YBuffer,
|
|
h_envChan[0]->sbrExtractEnvelope.YBufferScale, h_envChan[1]->sbrExtractEnvelope.YBufferScale,
|
|
eData[0].frame_info, eData[0].sfb_nrg, eData[1].sfb_nrg,
|
|
h_con, h_envChan[0], SBR_COUPLING, &fData->maxQuantError, YSzShift);
|
|
break;
|
|
case SBR_SWITCH_LRC:
|
|
calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL,
|
|
h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL,
|
|
eData[0].frame_info, eData[0].sfb_nrg, NULL,
|
|
h_con, h_envChan[0], SBR_MONO, NULL, YSzShift);
|
|
calculateSbrEnvelope (h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL,
|
|
h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL,
|
|
eData[1].frame_info, eData[1].sfb_nrg, NULL,
|
|
h_con, h_envChan[1], SBR_MONO,NULL, YSzShift);
|
|
calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, h_envChan[1]->sbrExtractEnvelope.YBuffer,
|
|
h_envChan[0]->sbrExtractEnvelope.YBufferScale, h_envChan[1]->sbrExtractEnvelope.YBufferScale,
|
|
eData[0].frame_info, eData[0].sfb_nrg_coupling, eData[1].sfb_nrg_coupling,
|
|
h_con, h_envChan[0], SBR_COUPLING, &fData->maxQuantError, YSzShift);
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Noise floor quantisation and coding.
|
|
*/
|
|
|
|
switch (stereoMode) {
|
|
case SBR_MONO:
|
|
sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, 0);
|
|
|
|
FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res,
|
|
&h_envChan[0]->sbrCodeNoiseFloor,
|
|
h_envChan[0]->encEnvData.domain_vec_noise, 0,
|
|
(eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
break;
|
|
case SBR_LEFT_RIGHT:
|
|
sbrNoiseFloorLevelsQuantisation(eData[0].noise_level,eData[0].noiseFloor, 0);
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[0].noise_level, fData->res,
|
|
&h_envChan[0]->sbrCodeNoiseFloor,
|
|
h_envChan[0]->encEnvData.domain_vec_noise, 0,
|
|
(eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
sbrNoiseFloorLevelsQuantisation(eData[1].noise_level,eData[1].noiseFloor, 0);
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[1].noise_level, fData->res,
|
|
&h_envChan[1]->sbrCodeNoiseFloor,
|
|
h_envChan[1]->encEnvData.domain_vec_noise, 0,
|
|
(eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
break;
|
|
|
|
case SBR_COUPLING:
|
|
coupleNoiseFloor(eData[0].noiseFloor,eData[1].noiseFloor);
|
|
|
|
sbrNoiseFloorLevelsQuantisation(eData[0].noise_level,eData[0].noiseFloor, 0);
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[0].noise_level, fData->res,
|
|
&h_envChan[0]->sbrCodeNoiseFloor,
|
|
h_envChan[0]->encEnvData.domain_vec_noise, 1,
|
|
(eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
sbrNoiseFloorLevelsQuantisation(eData[1].noise_level,eData[1].noiseFloor, 1);
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[1].noise_level, fData->res,
|
|
&h_envChan[1]->sbrCodeNoiseFloor,
|
|
h_envChan[1]->encEnvData.domain_vec_noise, 1,
|
|
(eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
break;
|
|
case SBR_SWITCH_LRC:
|
|
sbrNoiseFloorLevelsQuantisation(eData[0].noise_level,eData[0].noiseFloor, 0);
|
|
sbrNoiseFloorLevelsQuantisation(eData[1].noise_level,eData[1].noiseFloor, 0);
|
|
coupleNoiseFloor(eData[0].noiseFloor,eData[1].noiseFloor);
|
|
sbrNoiseFloorLevelsQuantisation(eData[0].noise_level_coupling,eData[0].noiseFloor, 0);
|
|
sbrNoiseFloorLevelsQuantisation(eData[1].noise_level_coupling,eData[1].noiseFloor, 1);
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Encode envelope of current frame.
|
|
*/
|
|
switch (stereoMode) {
|
|
case SBR_MONO:
|
|
sbrHeaderData->coupling = 0;
|
|
h_envChan[0]->encEnvData.balance = 0;
|
|
FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes,
|
|
&h_envChan[0]->sbrCodeEnvelope,
|
|
h_envChan[0]->encEnvData.domain_vec,
|
|
sbrHeaderData->coupling,
|
|
eData[0].frame_info->nEnvelopes, 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
break;
|
|
case SBR_LEFT_RIGHT:
|
|
sbrHeaderData->coupling = 0;
|
|
|
|
h_envChan[0]->encEnvData.balance = 0;
|
|
h_envChan[1]->encEnvData.balance = 0;
|
|
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes,
|
|
&h_envChan[0]->sbrCodeEnvelope,
|
|
h_envChan[0]->encEnvData.domain_vec,
|
|
sbrHeaderData->coupling,
|
|
eData[0].frame_info->nEnvelopes, 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg, eData[1].frame_info->freqRes,
|
|
&h_envChan[1]->sbrCodeEnvelope,
|
|
h_envChan[1]->encEnvData.domain_vec,
|
|
sbrHeaderData->coupling,
|
|
eData[1].frame_info->nEnvelopes, 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
break;
|
|
case SBR_COUPLING:
|
|
sbrHeaderData->coupling = 1;
|
|
h_envChan[0]->encEnvData.balance = 0;
|
|
h_envChan[1]->encEnvData.balance = 1;
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes,
|
|
&h_envChan[0]->sbrCodeEnvelope,
|
|
h_envChan[0]->encEnvData.domain_vec,
|
|
sbrHeaderData->coupling,
|
|
eData[0].frame_info->nEnvelopes, 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg, eData[1].frame_info->freqRes,
|
|
&h_envChan[1]->sbrCodeEnvelope,
|
|
h_envChan[1]->encEnvData.domain_vec,
|
|
sbrHeaderData->coupling,
|
|
eData[1].frame_info->nEnvelopes, 1,
|
|
sbrBitstreamData->HeaderActive);
|
|
break;
|
|
case SBR_SWITCH_LRC:
|
|
{
|
|
INT payloadbitsLR;
|
|
INT payloadbitsCOUPLING;
|
|
|
|
SCHAR sfbNrgPrevTemp[MAX_NUM_CHANNELS][MAX_FREQ_COEFFS];
|
|
SCHAR noisePrevTemp[MAX_NUM_CHANNELS][MAX_NUM_NOISE_COEFFS];
|
|
INT upDateNrgTemp[MAX_NUM_CHANNELS];
|
|
INT upDateNoiseTemp[MAX_NUM_CHANNELS];
|
|
INT domainVecTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES];
|
|
INT domainVecNoiseTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES];
|
|
|
|
INT tempFlagRight = 0;
|
|
INT tempFlagLeft = 0;
|
|
|
|
/*
|
|
Store previous values, in order to be able to "undo" what is being done.
|
|
*/
|
|
|
|
for(ch = 0; ch < nChannels;ch++){
|
|
FDKmemcpy (sfbNrgPrevTemp[ch], h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev,
|
|
MAX_FREQ_COEFFS * sizeof (SCHAR));
|
|
|
|
FDKmemcpy (noisePrevTemp[ch], h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev,
|
|
MAX_NUM_NOISE_COEFFS * sizeof (SCHAR));
|
|
|
|
upDateNrgTemp[ch] = h_envChan[ch]->sbrCodeEnvelope.upDate;
|
|
upDateNoiseTemp[ch] = h_envChan[ch]->sbrCodeNoiseFloor.upDate;
|
|
|
|
/*
|
|
forbid time coding in the first envelope in case of a different
|
|
previous stereomode
|
|
*/
|
|
if(sbrHeaderData->prev_coupling){
|
|
h_envChan[ch]->sbrCodeEnvelope.upDate = 0;
|
|
h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0;
|
|
}
|
|
} /* ch */
|
|
|
|
|
|
/*
|
|
Code ordinary Left/Right stereo
|
|
*/
|
|
FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes,
|
|
&h_envChan[0]->sbrCodeEnvelope,
|
|
h_envChan[0]->encEnvData.domain_vec, 0,
|
|
eData[0].frame_info->nEnvelopes, 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg, eData[1].frame_info->freqRes,
|
|
&h_envChan[1]->sbrCodeEnvelope,
|
|
h_envChan[1]->encEnvData.domain_vec, 0,
|
|
eData[1].frame_info->nEnvelopes, 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
c = 0;
|
|
for (i = 0; i < eData[0].nEnvelopes; i++) {
|
|
for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++)
|
|
{
|
|
h_envChan[0]->encEnvData.ienvelope[i][j] = eData[0].sfb_nrg[c];
|
|
h_envChan[1]->encEnvData.ienvelope[i][j] = eData[1].sfb_nrg[c];
|
|
c++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[0].noise_level, fData->res,
|
|
&h_envChan[0]->sbrCodeNoiseFloor,
|
|
h_envChan[0]->encEnvData.domain_vec_noise, 0,
|
|
(eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
|
|
for (i = 0; i < MAX_NUM_NOISE_VALUES; i++)
|
|
h_envChan[0]->encEnvData.sbr_noise_levels[i] = eData[0].noise_level[i];
|
|
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[1].noise_level, fData->res,
|
|
&h_envChan[1]->sbrCodeNoiseFloor,
|
|
h_envChan[1]->encEnvData.domain_vec_noise, 0,
|
|
(eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
for (i = 0; i < MAX_NUM_NOISE_VALUES; i++)
|
|
h_envChan[1]->encEnvData.sbr_noise_levels[i] = eData[1].noise_level[i];
|
|
|
|
|
|
sbrHeaderData->coupling = 0;
|
|
h_envChan[0]->encEnvData.balance = 0;
|
|
h_envChan[1]->encEnvData.balance = 0;
|
|
|
|
payloadbitsLR = FDKsbrEnc_CountSbrChannelPairElement (sbrHeaderData,
|
|
hParametricStereo,
|
|
sbrBitstreamData,
|
|
&h_envChan[0]->encEnvData,
|
|
&h_envChan[1]->encEnvData,
|
|
hCmonData,
|
|
h_con->sbrSyntaxFlags);
|
|
|
|
/*
|
|
swap saved stored with current values
|
|
*/
|
|
for(ch = 0; ch < nChannels;ch++){
|
|
INT itmp;
|
|
for(i=0;i<MAX_FREQ_COEFFS;i++){
|
|
/*
|
|
swap sfb energies
|
|
*/
|
|
itmp = h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev[i];
|
|
h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev[i]=sfbNrgPrevTemp[ch][i];
|
|
sfbNrgPrevTemp[ch][i]=itmp;
|
|
}
|
|
for(i=0;i<MAX_NUM_NOISE_COEFFS;i++){
|
|
/*
|
|
swap noise energies
|
|
*/
|
|
itmp = h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev[i];
|
|
h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev[i]=noisePrevTemp[ch][i];
|
|
noisePrevTemp[ch][i]=itmp;
|
|
}
|
|
/* swap update flags */
|
|
itmp = h_envChan[ch]->sbrCodeEnvelope.upDate;
|
|
h_envChan[ch]->sbrCodeEnvelope.upDate=upDateNrgTemp[ch];
|
|
upDateNrgTemp[ch] = itmp;
|
|
|
|
itmp = h_envChan[ch]->sbrCodeNoiseFloor.upDate;
|
|
h_envChan[ch]->sbrCodeNoiseFloor.upDate=upDateNoiseTemp[ch];
|
|
upDateNoiseTemp[ch]=itmp;
|
|
|
|
/*
|
|
save domain vecs
|
|
*/
|
|
FDKmemcpy(domainVecTemp[ch],h_envChan[ch]->encEnvData.domain_vec,sizeof(INT)*MAX_ENVELOPES);
|
|
FDKmemcpy(domainVecNoiseTemp[ch],h_envChan[ch]->encEnvData.domain_vec_noise,sizeof(INT)*MAX_ENVELOPES);
|
|
|
|
/*
|
|
forbid time coding in the first envelope in case of a different
|
|
previous stereomode
|
|
*/
|
|
|
|
if(!sbrHeaderData->prev_coupling){
|
|
h_envChan[ch]->sbrCodeEnvelope.upDate = 0;
|
|
h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0;
|
|
}
|
|
} /* ch */
|
|
|
|
|
|
/*
|
|
Coupling
|
|
*/
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg_coupling, eData[0].frame_info->freqRes,
|
|
&h_envChan[0]->sbrCodeEnvelope,
|
|
h_envChan[0]->encEnvData.domain_vec, 1,
|
|
eData[0].frame_info->nEnvelopes, 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg_coupling, eData[1].frame_info->freqRes,
|
|
&h_envChan[1]->sbrCodeEnvelope,
|
|
h_envChan[1]->encEnvData.domain_vec, 1,
|
|
eData[1].frame_info->nEnvelopes, 1,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
|
|
c = 0;
|
|
for (i = 0; i < eData[0].nEnvelopes; i++) {
|
|
for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++) {
|
|
h_envChan[0]->encEnvData.ienvelope[i][j] = eData[0].sfb_nrg_coupling[c];
|
|
h_envChan[1]->encEnvData.ienvelope[i][j] = eData[1].sfb_nrg_coupling[c];
|
|
c++;
|
|
}
|
|
}
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[0].noise_level_coupling, fData->res,
|
|
&h_envChan[0]->sbrCodeNoiseFloor,
|
|
h_envChan[0]->encEnvData.domain_vec_noise, 1,
|
|
(eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
for (i = 0; i < MAX_NUM_NOISE_VALUES; i++)
|
|
h_envChan[0]->encEnvData.sbr_noise_levels[i] = eData[0].noise_level_coupling[i];
|
|
|
|
|
|
FDKsbrEnc_codeEnvelope (eData[1].noise_level_coupling, fData->res,
|
|
&h_envChan[1]->sbrCodeNoiseFloor,
|
|
h_envChan[1]->encEnvData.domain_vec_noise, 1,
|
|
(eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1,
|
|
sbrBitstreamData->HeaderActive);
|
|
|
|
for (i = 0; i < MAX_NUM_NOISE_VALUES; i++)
|
|
h_envChan[1]->encEnvData.sbr_noise_levels[i] = eData[1].noise_level_coupling[i];
|
|
|
|
sbrHeaderData->coupling = 1;
|
|
|
|
h_envChan[0]->encEnvData.balance = 0;
|
|
h_envChan[1]->encEnvData.balance = 1;
|
|
|
|
tempFlagLeft = h_envChan[0]->encEnvData.addHarmonicFlag;
|
|
tempFlagRight = h_envChan[1]->encEnvData.addHarmonicFlag;
|
|
|
|
payloadbitsCOUPLING =
|
|
FDKsbrEnc_CountSbrChannelPairElement (sbrHeaderData,
|
|
hParametricStereo,
|
|
sbrBitstreamData,
|
|
&h_envChan[0]->encEnvData,
|
|
&h_envChan[1]->encEnvData,
|
|
hCmonData,
|
|
h_con->sbrSyntaxFlags);
|
|
|
|
|
|
h_envChan[0]->encEnvData.addHarmonicFlag = tempFlagLeft;
|
|
h_envChan[1]->encEnvData.addHarmonicFlag = tempFlagRight;
|
|
|
|
if (payloadbitsCOUPLING < payloadbitsLR) {
|
|
|
|
/*
|
|
copy coded coupling envelope and noise data to l/r
|
|
*/
|
|
for(ch = 0; ch < nChannels;ch++){
|
|
SBR_ENV_TEMP_DATA *ed = &eData[ch];
|
|
FDKmemcpy (ed->sfb_nrg, ed->sfb_nrg_coupling,
|
|
MAX_NUM_ENVELOPE_VALUES * sizeof (SCHAR));
|
|
FDKmemcpy (ed->noise_level, ed->noise_level_coupling,
|
|
MAX_NUM_NOISE_VALUES * sizeof (SCHAR));
|
|
}
|
|
|
|
sbrHeaderData->coupling = 1;
|
|
h_envChan[0]->encEnvData.balance = 0;
|
|
h_envChan[1]->encEnvData.balance = 1;
|
|
}
|
|
else{
|
|
/*
|
|
restore saved l/r items
|
|
*/
|
|
for(ch = 0; ch < nChannels;ch++){
|
|
|
|
FDKmemcpy (h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev,
|
|
sfbNrgPrevTemp[ch], MAX_FREQ_COEFFS * sizeof (SCHAR));
|
|
|
|
h_envChan[ch]->sbrCodeEnvelope.upDate = upDateNrgTemp[ch];
|
|
|
|
FDKmemcpy (h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev,
|
|
noisePrevTemp[ch], MAX_NUM_NOISE_COEFFS * sizeof (SCHAR));
|
|
|
|
FDKmemcpy (h_envChan[ch]->encEnvData.domain_vec,domainVecTemp[ch],sizeof(INT)*MAX_ENVELOPES);
|
|
FDKmemcpy (h_envChan[ch]->encEnvData.domain_vec_noise,domainVecNoiseTemp[ch],sizeof(INT)*MAX_ENVELOPES);
|
|
|
|
h_envChan[ch]->sbrCodeNoiseFloor.upDate = upDateNoiseTemp[ch];
|
|
}
|
|
|
|
sbrHeaderData->coupling = 0;
|
|
h_envChan[0]->encEnvData.balance = 0;
|
|
h_envChan[1]->encEnvData.balance = 0;
|
|
}
|
|
}
|
|
break;
|
|
} /* switch */
|
|
|
|
|
|
/* tell the envelope encoders how long it has been, since we last sent
|
|
a frame starting with a dF-coded envelope */
|
|
if (stereoMode == SBR_MONO ) {
|
|
if (h_envChan[0]->encEnvData.domain_vec[0] == TIME)
|
|
h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++;
|
|
else
|
|
h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0;
|
|
}
|
|
else {
|
|
if (h_envChan[0]->encEnvData.domain_vec[0] == TIME ||
|
|
h_envChan[1]->encEnvData.domain_vec[0] == TIME) {
|
|
h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++;
|
|
h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac++;
|
|
}
|
|
else {
|
|
h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0;
|
|
h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Send the encoded data to the bitstream
|
|
*/
|
|
for(ch = 0; ch < nChannels;ch++){
|
|
SBR_ENV_TEMP_DATA *ed = &eData[ch];
|
|
c = 0;
|
|
for (i = 0; i < ed->nEnvelopes; i++) {
|
|
for (j = 0; j < h_envChan[ch]->encEnvData.noScfBands[i]; j++) {
|
|
h_envChan[ch]->encEnvData.ienvelope[i][j] = ed->sfb_nrg[c];
|
|
|
|
c++;
|
|
}
|
|
}
|
|
for (i = 0; i < MAX_NUM_NOISE_VALUES; i++){
|
|
h_envChan[ch]->encEnvData.sbr_noise_levels[i] = ed->noise_level[i];
|
|
}
|
|
}/* ch */
|
|
|
|
|
|
/*
|
|
Write bitstream
|
|
*/
|
|
if (nChannels == 2) {
|
|
FDKsbrEnc_WriteEnvChannelPairElement(sbrHeaderData,
|
|
hParametricStereo,
|
|
sbrBitstreamData,
|
|
&h_envChan[0]->encEnvData,
|
|
&h_envChan[1]->encEnvData,
|
|
hCmonData,
|
|
h_con->sbrSyntaxFlags);
|
|
}
|
|
else {
|
|
FDKsbrEnc_WriteEnvSingleChannelElement(sbrHeaderData,
|
|
hParametricStereo,
|
|
sbrBitstreamData,
|
|
&h_envChan[0]->encEnvData,
|
|
hCmonData,
|
|
h_con->sbrSyntaxFlags);
|
|
}
|
|
|
|
/*
|
|
* Update buffers.
|
|
*/
|
|
for (ch=0; ch<nChannels; ch++)
|
|
{
|
|
int YBufferLength = h_envChan[ch]->sbrExtractEnvelope.no_cols >> h_envChan[ch]->sbrExtractEnvelope.YBufferSzShift;
|
|
for (i = 0; i < h_envChan[ch]->sbrExtractEnvelope.YBufferWriteOffset; i++) {
|
|
FDKmemcpy(h_envChan[ch]->sbrExtractEnvelope.YBuffer[i],
|
|
h_envChan[ch]->sbrExtractEnvelope.YBuffer[i + YBufferLength],
|
|
sizeof(FIXP_DBL)*QMF_CHANNELS);
|
|
}
|
|
h_envChan[ch]->sbrExtractEnvelope.YBufferScale[0] = h_envChan[ch]->sbrExtractEnvelope.YBufferScale[1];
|
|
}
|
|
|
|
sbrHeaderData->prev_coupling = sbrHeaderData->coupling;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief creates an envelope extractor handle
|
|
|
|
\return error status
|
|
|
|
****************************************************************************/
|
|
INT
|
|
FDKsbrEnc_CreateExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut,
|
|
INT channel
|
|
,INT chInEl
|
|
,UCHAR* dynamic_RAM
|
|
)
|
|
{
|
|
INT i;
|
|
FIXP_DBL* YBuffer = GetRam_Sbr_envYBuffer(channel);
|
|
|
|
FDKmemclear(hSbrCut,sizeof(SBR_EXTRACT_ENVELOPE));
|
|
hSbrCut->p_YBuffer = YBuffer;
|
|
|
|
|
|
for (i = 0; i < (QMF_MAX_TIME_SLOTS>>1); i++) {
|
|
hSbrCut->YBuffer[i] = YBuffer + (i*QMF_CHANNELS);
|
|
}
|
|
FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM);
|
|
INT n=0;
|
|
for (; i < QMF_MAX_TIME_SLOTS; i++,n++) {
|
|
hSbrCut->YBuffer[i] = YBufferDyn + (n*QMF_CHANNELS);
|
|
}
|
|
|
|
FIXP_DBL* rBuffer = GetRam_Sbr_envRBuffer(0, dynamic_RAM);
|
|
FIXP_DBL* iBuffer = GetRam_Sbr_envIBuffer(0, dynamic_RAM);
|
|
|
|
for (i = 0; i < QMF_MAX_TIME_SLOTS; i++) {
|
|
hSbrCut->rBuffer[i] = rBuffer + (i*QMF_CHANNELS);
|
|
hSbrCut->iBuffer[i] = iBuffer + (i*QMF_CHANNELS);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief Initialize an envelope extractor instance.
|
|
|
|
\return error status
|
|
|
|
****************************************************************************/
|
|
INT
|
|
FDKsbrEnc_InitExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut,
|
|
int no_cols,
|
|
int no_rows,
|
|
int start_index,
|
|
int time_slots,
|
|
int time_step,
|
|
int tran_off,
|
|
ULONG statesInitFlag
|
|
,int chInEl
|
|
,UCHAR* dynamic_RAM
|
|
,UINT sbrSyntaxFlags
|
|
)
|
|
{
|
|
int YBufferLength, rBufferLength;
|
|
int i;
|
|
|
|
if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
|
|
int off = TRANSIENT_OFFSET_LD;
|
|
#ifndef FULL_DELAY
|
|
hSbrCut->YBufferWriteOffset = (no_cols>>1)+off*time_step;
|
|
#else
|
|
hSbrCut->YBufferWriteOffset = no_cols+off*time_step;
|
|
#endif
|
|
} else
|
|
{
|
|
hSbrCut->YBufferWriteOffset = tran_off*time_step;
|
|
}
|
|
hSbrCut->rBufferReadOffset = 0;
|
|
|
|
|
|
YBufferLength = hSbrCut->YBufferWriteOffset + no_cols;
|
|
rBufferLength = no_cols;
|
|
|
|
hSbrCut->pre_transient_info[0] = 0;
|
|
hSbrCut->pre_transient_info[1] = 0;
|
|
|
|
|
|
hSbrCut->no_cols = no_cols;
|
|
hSbrCut->no_rows = no_rows;
|
|
hSbrCut->start_index = start_index;
|
|
|
|
hSbrCut->time_slots = time_slots;
|
|
hSbrCut->time_step = time_step;
|
|
|
|
FDK_ASSERT(no_rows <= QMF_CHANNELS);
|
|
|
|
/* Use half the Energy values if time step is 2 or greater */
|
|
if (time_step >= 2)
|
|
hSbrCut->YBufferSzShift = 1;
|
|
else
|
|
hSbrCut->YBufferSzShift = 0;
|
|
|
|
YBufferLength >>= hSbrCut->YBufferSzShift;
|
|
hSbrCut->YBufferWriteOffset >>= hSbrCut->YBufferSzShift;
|
|
|
|
FDK_ASSERT(YBufferLength<=QMF_MAX_TIME_SLOTS);
|
|
|
|
FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM);
|
|
INT n=0;
|
|
for (i=(QMF_MAX_TIME_SLOTS>>1); i < QMF_MAX_TIME_SLOTS; i++,n++) {
|
|
hSbrCut->YBuffer[i] = YBufferDyn + (n*QMF_CHANNELS);
|
|
}
|
|
|
|
if(statesInitFlag) {
|
|
for (i=0; i<YBufferLength; i++) {
|
|
FDKmemclear( hSbrCut->YBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL));
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < rBufferLength; i++) {
|
|
FDKmemclear( hSbrCut->rBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL));
|
|
FDKmemclear( hSbrCut->iBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL));
|
|
}
|
|
|
|
FDKmemclear (hSbrCut->envelopeCompensation,sizeof(UCHAR)*MAX_FREQ_COEFFS);
|
|
|
|
if(statesInitFlag) {
|
|
hSbrCut->YBufferScale[0] = hSbrCut->YBufferScale[1] = FRACT_BITS-1;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
/*!
|
|
|
|
\brief deinitializes an envelope extractor handle
|
|
|
|
\return void
|
|
|
|
****************************************************************************/
|
|
|
|
void
|
|
FDKsbrEnc_deleteExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut)
|
|
{
|
|
|
|
if (hSbrCut) {
|
|
FreeRam_Sbr_envYBuffer(&hSbrCut->p_YBuffer);
|
|
}
|
|
}
|
|
|
|
INT
|
|
FDKsbrEnc_GetEnvEstDelay(HANDLE_SBR_EXTRACT_ENVELOPE hSbr)
|
|
{
|
|
return hSbr->no_rows*((hSbr->YBufferWriteOffset)*2 /* mult 2 because nrg's are grouped half */
|
|
- hSbr->rBufferReadOffset ); /* in reference hold half spec and calc nrg's on overlapped spec */
|
|
|
|
}
|
|
|
|
|
|
|
|
|