mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-02-10 00:20:35 +01:00
d6459f539c
am: f5512132f3 Change-Id: Ie01b6d6c881c4c9a52af921eee9f7ced6fd6880e
2096 lines
76 KiB
C++
2096 lines
76 KiB
C++
/* -----------------------------------------------------------------------------
|
|
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
|
|
|
© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
|
|
Forschung e.V. All rights reserved.
|
|
|
|
1. INTRODUCTION
|
|
The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
|
|
that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
|
|
scheme for digital audio. This FDK AAC Codec software is intended to be used on
|
|
a wide variety of Android devices.
|
|
|
|
AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
|
|
general perceptual audio codecs. AAC-ELD is considered the best-performing
|
|
full-bandwidth communications codec by independent studies and is widely
|
|
deployed. AAC has been standardized by ISO and IEC as part of the MPEG
|
|
specifications.
|
|
|
|
Patent licenses for necessary patent claims for the FDK AAC Codec (including
|
|
those of Fraunhofer) may be obtained through Via Licensing
|
|
(www.vialicensing.com) or through the respective patent owners individually for
|
|
the purpose of encoding or decoding bit streams in products that are compliant
|
|
with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
|
|
Android devices already license these patent claims through Via Licensing or
|
|
directly from the patent owners, and therefore FDK AAC Codec software may
|
|
already be covered under those patent licenses when it is used for those
|
|
licensed purposes only.
|
|
|
|
Commercially-licensed AAC software libraries, including floating-point versions
|
|
with enhanced sound quality, are also available from Fraunhofer. Users are
|
|
encouraged to check the Fraunhofer website for additional applications
|
|
information and documentation.
|
|
|
|
2. COPYRIGHT LICENSE
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
are permitted without payment of copyright license fees provided that you
|
|
satisfy the following conditions:
|
|
|
|
You must retain the complete text of this software license in redistributions of
|
|
the FDK AAC Codec or your modifications thereto in source code form.
|
|
|
|
You must retain the complete text of this software license in the documentation
|
|
and/or other materials provided with redistributions of the FDK AAC Codec or
|
|
your modifications thereto in binary form. You must make available free of
|
|
charge copies of the complete source code of the FDK AAC Codec and your
|
|
modifications thereto to recipients of copies in binary form.
|
|
|
|
The name of Fraunhofer may not be used to endorse or promote products derived
|
|
from this library without prior written permission.
|
|
|
|
You may not charge copyright license fees for anyone to use, copy or distribute
|
|
the FDK AAC Codec software or your modifications thereto.
|
|
|
|
Your modified versions of the FDK AAC Codec must carry prominent notices stating
|
|
that you changed the software and the date of any change. For modified versions
|
|
of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
|
|
must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
|
|
AAC Codec Library for Android."
|
|
|
|
3. NO PATENT LICENSE
|
|
|
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
|
|
limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
|
|
Fraunhofer provides no warranty of patent non-infringement with respect to this
|
|
software.
|
|
|
|
You may use this FDK AAC Codec software or modifications thereto only for
|
|
purposes that are authorized by appropriate patent licenses.
|
|
|
|
4. DISCLAIMER
|
|
|
|
This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
|
|
holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
including but not limited to the implied warranties of merchantability and
|
|
fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
|
|
or consequential damages, including but not limited to procurement of substitute
|
|
goods or services; loss of use, data, or profits, or business interruption,
|
|
however caused and on any theory of liability, whether in contract, strict
|
|
liability, or tort (including negligence), arising in any way out of the use of
|
|
this software, even if advised of the possibility of such damage.
|
|
|
|
5. CONTACT INFORMATION
|
|
|
|
Fraunhofer Institute for Integrated Circuits IIS
|
|
Attention: Audio and Multimedia Departments - FDK AAC LL
|
|
Am Wolfsmantel 33
|
|
91058 Erlangen, Germany
|
|
|
|
www.iis.fraunhofer.de/amm
|
|
amm-info@iis.fraunhofer.de
|
|
----------------------------------------------------------------------------- */
|
|
|
|
/**************************** AAC decoder library ******************************
|
|
|
|
Author(s): Josef Hoepfl
|
|
|
|
Description: independent channel concealment
|
|
|
|
*******************************************************************************/
|
|
|
|
/*!
|
|
\page concealment AAC core concealment
|
|
|
|
This AAC core implementation includes a concealment function, which can be
|
|
enabled using the several defines during compilation.
|
|
|
|
There are various tests inside the core, starting with simple CRC tests and
|
|
ending in a variety of plausibility checks. If such a check indicates an
|
|
invalid bitstream, then concealment is applied.
|
|
|
|
Concealment is also applied when the calling main program indicates a
|
|
distorted or missing data frame using the frameOK flag. This is used for error
|
|
detection on the transport layer. (See below)
|
|
|
|
There are three concealment-modes:
|
|
|
|
1) Muting: The spectral data is simply set to zero in case of an detected
|
|
error.
|
|
|
|
2) Noise substitution: In case of an detected error, concealment copies the
|
|
last frame and adds attenuates the spectral data. For this mode you have to
|
|
set the #CONCEAL_NOISE define. Noise substitution adds no additional delay.
|
|
|
|
3) Interpolation: The interpolation routine swaps the spectral data from the
|
|
previous and the current frame just before the final frequency to time
|
|
conversion. In case a single frame is corrupted, concealmant interpolates
|
|
between the last good and the first good frame to create the spectral data for
|
|
the missing frame. If multiple frames are corrupted, concealment implements
|
|
first a fade out based on slightly modified spectral values from the last good
|
|
frame. As soon as good frames are available, concealmant fades in the new
|
|
spectral data. For this mode you have to set the #CONCEAL_INTER define. Note
|
|
that in this case, you also need to set #SBR_BS_DELAY_ENABLE, which basically
|
|
adds approriate delay in the SBR decoder. Note that the
|
|
Interpolating-Concealment increases the delay of your decoder by one frame and
|
|
that it does require additional resources such as memory and computational
|
|
complexity.
|
|
|
|
<h2>How concealment can be used with errors on the transport layer</h2>
|
|
|
|
Many errors can or have to be detected on the transport layer. For example in
|
|
IP based systems packet loss can occur. The transport protocol used should
|
|
indicate such packet loss by inserting an empty frame with frameOK=0.
|
|
*/
|
|
|
|
#include "conceal.h"
|
|
|
|
#include "aac_rom.h"
|
|
#include "genericStds.h"
|
|
|
|
/* PNS (of block) */
|
|
#include "aacdec_pns.h"
|
|
#include "block.h"
|
|
|
|
#define CONCEAL_DFLT_COMF_NOISE_LEVEL (0x100000)
|
|
|
|
#define CONCEAL_NOT_DEFINED ((UCHAR)-1)
|
|
|
|
/* default settings */
|
|
#define CONCEAL_DFLT_FADEOUT_FRAMES (6)
|
|
#define CONCEAL_DFLT_FADEIN_FRAMES (5)
|
|
#define CONCEAL_DFLT_MUTE_RELEASE_FRAMES (0)
|
|
|
|
#define CONCEAL_DFLT_FADE_FACTOR (0.707106781186548f) /* 1/sqrt(2) */
|
|
|
|
/* some often used constants: */
|
|
#define FIXP_ZERO FL2FXCONST_DBL(0.0f)
|
|
#define FIXP_ONE FL2FXCONST_DBL(1.0f)
|
|
#define FIXP_FL_CORRECTION FL2FXCONST_DBL(0.53333333333333333f)
|
|
|
|
/* For parameter conversion */
|
|
#define CONCEAL_PARAMETER_BITS (8)
|
|
#define CONCEAL_MAX_QUANT_FACTOR ((1 << CONCEAL_PARAMETER_BITS) - 1)
|
|
/*#define CONCEAL_MIN_ATTENUATION_FACTOR_025 ( FL2FXCONST_DBL(0.971627951577106174) )*/ /* -0.25 dB */
|
|
#define CONCEAL_MIN_ATTENUATION_FACTOR_025_LD \
|
|
FL2FXCONST_DBL(-0.041524101186092029596853445212299)
|
|
/*#define CONCEAL_MIN_ATTENUATION_FACTOR_050 ( FL2FXCONST_DBL(0.944060876285923380) )*/ /* -0.50 dB */
|
|
#define CONCEAL_MIN_ATTENUATION_FACTOR_050_LD \
|
|
FL2FXCONST_DBL(-0.083048202372184059253597008145293)
|
|
|
|
typedef enum {
|
|
CConcealment_NoExpand,
|
|
CConcealment_Expand,
|
|
CConcealment_Compress
|
|
} CConcealmentExpandType;
|
|
|
|
static const FIXP_SGL facMod4Table[4] = {
|
|
FL2FXCONST_SGL(0.500000000f), /* FIXP_SGL(0x4000), 2^-(1-0,00) */
|
|
FL2FXCONST_SGL(0.594603558f), /* FIXP_SGL(0x4c1b), 2^-(1-0,25) */
|
|
FL2FXCONST_SGL(0.707106781f), /* FIXP_SGL(0x5a82), 2^-(1-0,50) */
|
|
FL2FXCONST_SGL(0.840896415f) /* FIXP_SGL(0x6ba2) 2^-(1-0,75) */
|
|
};
|
|
|
|
static void CConcealment_CalcBandEnergy(
|
|
FIXP_DBL *spectrum, const SamplingRateInfo *pSamplingRateInfo,
|
|
const int blockType, CConcealmentExpandType ex, int *sfbEnergy);
|
|
|
|
static void CConcealment_InterpolateBuffer(FIXP_DBL *spectrum,
|
|
SHORT *pSpecScalePrev,
|
|
SHORT *pSpecScaleAct,
|
|
SHORT *pSpecScaleOut, int *enPrv,
|
|
int *enAct, int sfbCnt,
|
|
const SHORT *pSfbOffset);
|
|
|
|
static int CConcealment_ApplyInter(
|
|
CConcealmentInfo *pConcealmentInfo,
|
|
CAacDecoderChannelInfo *pAacDecoderChannelInfo,
|
|
const SamplingRateInfo *pSamplingRateInfo, const int samplesPerFrame,
|
|
const int improveTonal, const int frameOk, const int mute_release_active);
|
|
|
|
static int CConcealment_ApplyNoise(
|
|
CConcealmentInfo *pConcealmentInfo,
|
|
CAacDecoderChannelInfo *pAacDecoderChannelInfo,
|
|
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
|
|
const SamplingRateInfo *pSamplingRateInfo, const int samplesPerFrame,
|
|
const UINT flags);
|
|
|
|
static void CConcealment_UpdateState(
|
|
CConcealmentInfo *pConcealmentInfo, int frameOk,
|
|
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
|
|
const int samplesPerFrame, CAacDecoderChannelInfo *pAacDecoderChannelInfo);
|
|
|
|
static void CConcealment_ApplyRandomSign(int iRandomPhase, FIXP_DBL *spec,
|
|
int samplesPerFrame);
|
|
|
|
/* TimeDomainFading */
|
|
static void CConcealment_TDFadePcmAtt(int start, int len, FIXP_DBL fadeStart,
|
|
FIXP_DBL fadeStop, FIXP_PCM *pcmdata);
|
|
static void CConcealment_TDFadeFillFadingStations(FIXP_DBL *fadingStations,
|
|
int *fadingSteps,
|
|
FIXP_DBL fadeStop,
|
|
FIXP_DBL fadeStart,
|
|
TDfadingType fadingType);
|
|
static void CConcealment_TDFading_doLinearFadingSteps(int *fadingSteps);
|
|
|
|
/* Streamline the state machine */
|
|
static int CConcealment_ApplyFadeOut(
|
|
int mode, CConcealmentInfo *pConcealmentInfo,
|
|
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
|
|
const int samplesPerFrame, CAacDecoderChannelInfo *pAacDecoderChannelInfo);
|
|
|
|
static int CConcealment_TDNoise_Random(ULONG *seed);
|
|
static void CConcealment_TDNoise_Apply(CConcealmentInfo *const pConcealmentInfo,
|
|
const int len, FIXP_PCM *const pcmdata);
|
|
|
|
static BLOCK_TYPE CConcealment_GetWinSeq(int prevWinSeq) {
|
|
BLOCK_TYPE newWinSeq = BLOCK_LONG;
|
|
|
|
/* Try to have only long blocks */
|
|
if (prevWinSeq == BLOCK_START || prevWinSeq == BLOCK_SHORT) {
|
|
newWinSeq = BLOCK_STOP;
|
|
}
|
|
|
|
return (newWinSeq);
|
|
}
|
|
|
|
/*!
|
|
\brief Init common concealment information data
|
|
|
|
\param pConcealCommonData Pointer to the concealment common data structure.
|
|
*/
|
|
void CConcealment_InitCommonData(CConcealParams *pConcealCommonData) {
|
|
if (pConcealCommonData != NULL) {
|
|
int i;
|
|
|
|
/* Set default error concealment technique */
|
|
pConcealCommonData->method = ConcealMethodInter;
|
|
|
|
pConcealCommonData->numFadeOutFrames = CONCEAL_DFLT_FADEOUT_FRAMES;
|
|
pConcealCommonData->numFadeInFrames = CONCEAL_DFLT_FADEIN_FRAMES;
|
|
pConcealCommonData->numMuteReleaseFrames = CONCEAL_DFLT_MUTE_RELEASE_FRAMES;
|
|
|
|
pConcealCommonData->comfortNoiseLevel =
|
|
(FIXP_DBL)CONCEAL_DFLT_COMF_NOISE_LEVEL;
|
|
|
|
/* Init fade factors (symetric) */
|
|
pConcealCommonData->fadeOutFactor[0] =
|
|
FL2FXCONST_SGL(CONCEAL_DFLT_FADE_FACTOR);
|
|
pConcealCommonData->fadeInFactor[0] = pConcealCommonData->fadeOutFactor[0];
|
|
|
|
for (i = 1; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) {
|
|
pConcealCommonData->fadeOutFactor[i] =
|
|
FX_DBL2FX_SGL(fMult(pConcealCommonData->fadeOutFactor[i - 1],
|
|
FL2FXCONST_SGL(CONCEAL_DFLT_FADE_FACTOR)));
|
|
pConcealCommonData->fadeInFactor[i] =
|
|
pConcealCommonData->fadeOutFactor[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief Get current concealment method.
|
|
|
|
\param pConcealCommonData Pointer to common concealment data (for all
|
|
channels)
|
|
*/
|
|
CConcealmentMethod CConcealment_GetMethod(CConcealParams *pConcealCommonData) {
|
|
CConcealmentMethod method = ConcealMethodNone;
|
|
|
|
if (pConcealCommonData != NULL) {
|
|
method = pConcealCommonData->method;
|
|
}
|
|
|
|
return (method);
|
|
}
|
|
|
|
/*!
|
|
\brief Init concealment information for each channel
|
|
|
|
\param pConcealChannelInfo Pointer to the channel related concealment info
|
|
structure to be initialized. \param pConcealCommonData Pointer to common
|
|
concealment data (for all channels) \param initRenderMode Initial render
|
|
mode to be set for the current channel. \param samplesPerFrame The number
|
|
of samples per frame.
|
|
*/
|
|
void CConcealment_InitChannelData(CConcealmentInfo *pConcealChannelInfo,
|
|
CConcealParams *pConcealCommonData,
|
|
AACDEC_RENDER_MODE initRenderMode,
|
|
int samplesPerFrame) {
|
|
int i;
|
|
pConcealChannelInfo->TDNoiseSeed = 0;
|
|
FDKmemclear(pConcealChannelInfo->TDNoiseStates,
|
|
sizeof(pConcealChannelInfo->TDNoiseStates));
|
|
pConcealChannelInfo->TDNoiseCoef[0] = FL2FXCONST_SGL(0.05f);
|
|
pConcealChannelInfo->TDNoiseCoef[1] = FL2FXCONST_SGL(0.5f);
|
|
pConcealChannelInfo->TDNoiseCoef[2] = FL2FXCONST_SGL(0.45f);
|
|
|
|
pConcealChannelInfo->pConcealParams = pConcealCommonData;
|
|
|
|
pConcealChannelInfo->lastRenderMode = initRenderMode;
|
|
|
|
pConcealChannelInfo->windowShape = CONCEAL_NOT_DEFINED;
|
|
pConcealChannelInfo->windowSequence = BLOCK_LONG; /* default type */
|
|
pConcealChannelInfo->lastWinGrpLen = 1;
|
|
|
|
pConcealChannelInfo->concealState = ConcealState_Ok;
|
|
|
|
FDKmemclear(pConcealChannelInfo->spectralCoefficient,
|
|
1024 * sizeof(FIXP_CNCL));
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
pConcealChannelInfo->specScale[i] = 0;
|
|
}
|
|
|
|
pConcealChannelInfo->iRandomPhase = 0;
|
|
|
|
pConcealChannelInfo->prevFrameOk[0] = 1;
|
|
pConcealChannelInfo->prevFrameOk[1] = 1;
|
|
|
|
pConcealChannelInfo->cntFadeFrames = 0;
|
|
pConcealChannelInfo->cntValidFrames = 0;
|
|
pConcealChannelInfo->fade_old = (FIXP_DBL)MAXVAL_DBL;
|
|
pConcealChannelInfo->winGrpOffset[0] = 0;
|
|
pConcealChannelInfo->winGrpOffset[1] = 0;
|
|
pConcealChannelInfo->attGrpOffset[0] = 0;
|
|
pConcealChannelInfo->attGrpOffset[1] = 0;
|
|
}
|
|
|
|
/*!
|
|
\brief Set error concealment parameters
|
|
|
|
\param concealParams
|
|
\param method
|
|
\param fadeOutSlope
|
|
\param fadeInSlope
|
|
\param muteRelease
|
|
\param comfNoiseLevel
|
|
*/
|
|
AAC_DECODER_ERROR
|
|
CConcealment_SetParams(CConcealParams *concealParams, int method,
|
|
int fadeOutSlope, int fadeInSlope, int muteRelease,
|
|
FIXP_DBL comfNoiseLevel) {
|
|
/* set concealment technique */
|
|
if (method != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) {
|
|
switch ((CConcealmentMethod)method) {
|
|
case ConcealMethodMute:
|
|
case ConcealMethodNoise:
|
|
case ConcealMethodInter:
|
|
/* Be sure to enable delay adjustment of SBR decoder! */
|
|
if (concealParams == NULL) {
|
|
return AAC_DEC_INVALID_HANDLE;
|
|
} else {
|
|
/* set param */
|
|
concealParams->method = (CConcealmentMethod)method;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
}
|
|
|
|
/* set number of frames for fade-out slope */
|
|
if (fadeOutSlope != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) {
|
|
if ((fadeOutSlope < CONCEAL_MAX_NUM_FADE_FACTORS) && (fadeOutSlope >= 0)) {
|
|
if (concealParams == NULL) {
|
|
return AAC_DEC_INVALID_HANDLE;
|
|
} else {
|
|
/* set param */
|
|
concealParams->numFadeOutFrames = fadeOutSlope;
|
|
}
|
|
} else {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
}
|
|
|
|
/* set number of frames for fade-in slope */
|
|
if (fadeInSlope != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) {
|
|
if ((fadeInSlope < CONCEAL_MAX_NUM_FADE_FACTORS) && (fadeInSlope >= 0)) {
|
|
if (concealParams == NULL) {
|
|
return AAC_DEC_INVALID_HANDLE;
|
|
} else {
|
|
/* set param */
|
|
concealParams->numFadeInFrames = fadeInSlope;
|
|
}
|
|
} else {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
}
|
|
|
|
/* set number of error-free frames after which the muting will be released */
|
|
if (muteRelease != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) {
|
|
if ((muteRelease < (CONCEAL_MAX_NUM_FADE_FACTORS << 1)) &&
|
|
(muteRelease >= 0)) {
|
|
if (concealParams == NULL) {
|
|
return AAC_DEC_INVALID_HANDLE;
|
|
} else {
|
|
/* set param */
|
|
concealParams->numMuteReleaseFrames = muteRelease;
|
|
}
|
|
} else {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
}
|
|
|
|
/* set confort noise level which will be inserted while in state 'muting' */
|
|
if (comfNoiseLevel != (FIXP_DBL)AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) {
|
|
if ((comfNoiseLevel < (FIXP_DBL)0) ||
|
|
(comfNoiseLevel > (FIXP_DBL)MAXVAL_DBL)) {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
if (concealParams == NULL) {
|
|
return AAC_DEC_INVALID_HANDLE;
|
|
} else {
|
|
concealParams->comfortNoiseLevel = (FIXP_DBL)comfNoiseLevel;
|
|
}
|
|
}
|
|
|
|
return (AAC_DEC_OK);
|
|
}
|
|
|
|
/*!
|
|
\brief Set fade-out/in attenuation factor vectors
|
|
|
|
\param concealParams
|
|
\param fadeOutAttenuationVector
|
|
\param fadeInAttenuationVector
|
|
|
|
\return 0 if OK all other values indicate errors
|
|
*/
|
|
AAC_DECODER_ERROR
|
|
CConcealment_SetAttenuation(CConcealParams *concealParams,
|
|
const SHORT *fadeOutAttenuationVector,
|
|
const SHORT *fadeInAttenuationVector) {
|
|
if ((fadeOutAttenuationVector == NULL) && (fadeInAttenuationVector == NULL)) {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
|
|
/* Fade-out factors */
|
|
if (fadeOutAttenuationVector != NULL) {
|
|
int i;
|
|
|
|
/* check quantized factors first */
|
|
for (i = 0; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) {
|
|
if ((fadeOutAttenuationVector[i] < 0) ||
|
|
(fadeOutAttenuationVector[i] > CONCEAL_MAX_QUANT_FACTOR)) {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
}
|
|
if (concealParams == NULL) {
|
|
return AAC_DEC_INVALID_HANDLE;
|
|
}
|
|
|
|
/* now dequantize factors */
|
|
for (i = 0; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) {
|
|
concealParams->fadeOutFactor[i] =
|
|
FX_DBL2FX_SGL(fLdPow(CONCEAL_MIN_ATTENUATION_FACTOR_025_LD, 0,
|
|
(FIXP_DBL)((INT)(FL2FXCONST_DBL(1.0 / 2.0) >>
|
|
(CONCEAL_PARAMETER_BITS - 1)) *
|
|
(INT)fadeOutAttenuationVector[i]),
|
|
CONCEAL_PARAMETER_BITS));
|
|
}
|
|
}
|
|
|
|
/* Fade-in factors */
|
|
if (fadeInAttenuationVector != NULL) {
|
|
int i;
|
|
|
|
/* check quantized factors first */
|
|
for (i = 0; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) {
|
|
if ((fadeInAttenuationVector[i] < 0) ||
|
|
(fadeInAttenuationVector[i] > CONCEAL_MAX_QUANT_FACTOR)) {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
}
|
|
if (concealParams == NULL) {
|
|
return AAC_DEC_INVALID_HANDLE;
|
|
}
|
|
|
|
/* now dequantize factors */
|
|
for (i = 0; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) {
|
|
concealParams->fadeInFactor[i] = FX_DBL2FX_SGL(
|
|
fLdPow(CONCEAL_MIN_ATTENUATION_FACTOR_025_LD, 0,
|
|
(FIXP_DBL)((INT)(FIXP_ONE >> CONCEAL_PARAMETER_BITS) *
|
|
(INT)fadeInAttenuationVector[i]),
|
|
CONCEAL_PARAMETER_BITS));
|
|
}
|
|
}
|
|
|
|
return (AAC_DEC_OK);
|
|
}
|
|
|
|
/*!
|
|
\brief Get state of concealment module.
|
|
|
|
\param pConcealChannelInfo
|
|
|
|
\return Concealment state.
|
|
*/
|
|
CConcealmentState CConcealment_GetState(CConcealmentInfo *pConcealChannelInfo) {
|
|
CConcealmentState state = ConcealState_Ok;
|
|
|
|
if (pConcealChannelInfo != NULL) {
|
|
state = pConcealChannelInfo->concealState;
|
|
}
|
|
|
|
return (state);
|
|
}
|
|
|
|
/*!
|
|
\brief Store data for concealment techniques applied later
|
|
|
|
Interface function to store data for different concealment strategies
|
|
*/
|
|
void CConcealment_Store(
|
|
CConcealmentInfo *hConcealmentInfo,
|
|
CAacDecoderChannelInfo *pAacDecoderChannelInfo,
|
|
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo) {
|
|
UCHAR nbDiv = NB_DIV;
|
|
|
|
if (!(pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_LPD &&
|
|
pAacDecoderChannelInfo->data.usac.mod[nbDiv - 1] == 0))
|
|
|
|
{
|
|
FIXP_DBL *pSpectralCoefficient =
|
|
SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient);
|
|
SHORT *pSpecScale = pAacDecoderChannelInfo->specScale;
|
|
CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo;
|
|
|
|
SHORT tSpecScale[8];
|
|
UCHAR tWindowShape;
|
|
BLOCK_TYPE tWindowSequence;
|
|
|
|
/* store old window infos for swapping */
|
|
tWindowSequence = hConcealmentInfo->windowSequence;
|
|
tWindowShape = hConcealmentInfo->windowShape;
|
|
|
|
/* store old scale factors for swapping */
|
|
FDKmemcpy(tSpecScale, hConcealmentInfo->specScale, 8 * sizeof(SHORT));
|
|
|
|
/* store new window infos */
|
|
hConcealmentInfo->windowSequence = GetWindowSequence(pIcsInfo);
|
|
hConcealmentInfo->windowShape = GetWindowShape(pIcsInfo);
|
|
hConcealmentInfo->lastWinGrpLen =
|
|
*(GetWindowGroupLengthTable(pIcsInfo) + GetWindowGroups(pIcsInfo) - 1);
|
|
|
|
/* store new scale factors */
|
|
FDKmemcpy(hConcealmentInfo->specScale, pSpecScale, 8 * sizeof(SHORT));
|
|
|
|
if (hConcealmentInfo->pConcealParams->method < ConcealMethodInter) {
|
|
/* store new spectral bins */
|
|
#if (CNCL_FRACT_BITS == DFRACT_BITS)
|
|
FDKmemcpy(hConcealmentInfo->spectralCoefficient, pSpectralCoefficient,
|
|
1024 * sizeof(FIXP_CNCL));
|
|
#else
|
|
FIXP_CNCL *RESTRICT pCncl =
|
|
&hConcealmentInfo->spectralCoefficient[1024 - 1];
|
|
FIXP_DBL *RESTRICT pSpec = &pSpectralCoefficient[1024 - 1];
|
|
int i;
|
|
for (i = 1024; i != 0; i--) {
|
|
*pCncl-- = FX_DBL2FX_CNCL(*pSpec--);
|
|
}
|
|
#endif
|
|
} else {
|
|
/* swap spectral data */
|
|
#if (FIXP_CNCL == FIXP_DBL)
|
|
C_ALLOC_SCRATCH_START(pSpecTmp, FIXP_DBL, 1024);
|
|
FDKmemcpy(pSpecTmp, pSpectralCoefficient, 1024 * sizeof(FIXP_DBL));
|
|
FDKmemcpy(pSpectralCoefficient, hConcealmentInfo->spectralCoefficient,
|
|
1024 * sizeof(FIXP_DBL));
|
|
FDKmemcpy(hConcealmentInfo->spectralCoefficient, pSpecTmp,
|
|
1024 * sizeof(FIXP_DBL));
|
|
C_ALLOC_SCRATCH_END(pSpecTmp, FIXP_DBL, 1024);
|
|
#else
|
|
FIXP_CNCL *RESTRICT pCncl =
|
|
&hConcealmentInfo->spectralCoefficient[1024 - 1];
|
|
FIXP_DBL *RESTRICT pSpec = &pSpectralCoefficient[1024 - 1];
|
|
FIXP_DBL tSpec;
|
|
|
|
for (int i = 1024; i != 0; i--) {
|
|
tSpec = *pSpec;
|
|
*pSpec-- = FX_CNCL2FX_DBL(*pCncl);
|
|
*pCncl-- = FX_DBL2FX_CNCL(tSpec);
|
|
}
|
|
#endif
|
|
|
|
/* complete swapping of window infos */
|
|
pIcsInfo->WindowSequence = tWindowSequence;
|
|
pIcsInfo->WindowShape = tWindowShape;
|
|
|
|
/* complete swapping of scale factors */
|
|
FDKmemcpy(pSpecScale, tSpecScale, 8 * sizeof(SHORT));
|
|
}
|
|
}
|
|
|
|
if (pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_LPD) {
|
|
/* Store LSF4 */
|
|
FDKmemcpy(hConcealmentInfo->lsf4, pAacDecoderStaticChannelInfo->lpc4_lsf,
|
|
sizeof(hConcealmentInfo->lsf4));
|
|
/* Store TCX gain */
|
|
hConcealmentInfo->last_tcx_gain =
|
|
pAacDecoderStaticChannelInfo->last_tcx_gain;
|
|
hConcealmentInfo->last_tcx_gain_e =
|
|
pAacDecoderStaticChannelInfo->last_tcx_gain_e;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief Apply concealment
|
|
|
|
Interface function to different concealment strategies
|
|
*/
|
|
int CConcealment_Apply(
|
|
CConcealmentInfo *hConcealmentInfo,
|
|
CAacDecoderChannelInfo *pAacDecoderChannelInfo,
|
|
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
|
|
const SamplingRateInfo *pSamplingRateInfo, const int samplesPerFrame,
|
|
const UCHAR lastLpdMode, const int frameOk, const UINT flags) {
|
|
int appliedProcessing = 0;
|
|
const int mute_release_active =
|
|
frameOk && (hConcealmentInfo->concealState >= ConcealState_Mute) &&
|
|
(hConcealmentInfo->cntValidFrames + 1 <=
|
|
hConcealmentInfo->pConcealParams->numMuteReleaseFrames);
|
|
|
|
if (hConcealmentInfo->windowShape == CONCEAL_NOT_DEFINED) {
|
|
/* Initialize window_shape with same value as in the current (parsed) frame.
|
|
Because section 4.6.11.3.2 (Windowing and block switching) of ISO/IEC
|
|
14496-3:2009 says: For the first raw_data_block() to be decoded the
|
|
window_shape of the left and right half of the window are identical. */
|
|
hConcealmentInfo->windowShape = pAacDecoderChannelInfo->icsInfo.WindowShape;
|
|
}
|
|
|
|
if (frameOk && !mute_release_active) {
|
|
/* Update render mode if frameOk except for ongoing mute release state. */
|
|
hConcealmentInfo->lastRenderMode =
|
|
(SCHAR)pAacDecoderChannelInfo->renderMode;
|
|
|
|
/* Rescue current data for concealment in future frames */
|
|
CConcealment_Store(hConcealmentInfo, pAacDecoderChannelInfo,
|
|
pAacDecoderStaticChannelInfo);
|
|
/* Reset index to random sign vector to make sign calculation frame agnostic
|
|
(only depends on number of subsequently concealed spectral blocks) */
|
|
hConcealmentInfo->iRandomPhase = 0;
|
|
} else {
|
|
if (hConcealmentInfo->lastRenderMode == AACDEC_RENDER_INVALID) {
|
|
hConcealmentInfo->lastRenderMode = AACDEC_RENDER_IMDCT;
|
|
}
|
|
pAacDecoderChannelInfo->renderMode =
|
|
(AACDEC_RENDER_MODE)hConcealmentInfo->lastRenderMode;
|
|
}
|
|
|
|
/* hand current frame status to the state machine */
|
|
CConcealment_UpdateState(hConcealmentInfo, frameOk,
|
|
pAacDecoderStaticChannelInfo, samplesPerFrame,
|
|
pAacDecoderChannelInfo);
|
|
|
|
{
|
|
if (!frameOk && pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_IMDCT) {
|
|
/* LPC extrapolation */
|
|
CLpc_Conceal(pAacDecoderChannelInfo->data.usac.lsp_coeff,
|
|
pAacDecoderStaticChannelInfo->lpc4_lsf,
|
|
pAacDecoderStaticChannelInfo->lsf_adaptive_mean,
|
|
hConcealmentInfo->lastRenderMode == AACDEC_RENDER_IMDCT);
|
|
FDKmemcpy(hConcealmentInfo->lsf4, pAacDecoderStaticChannelInfo->lpc4_lsf,
|
|
sizeof(pAacDecoderStaticChannelInfo->lpc4_lsf));
|
|
}
|
|
|
|
/* Create data for signal rendering according to the selected concealment
|
|
* method and decoder operating mode. */
|
|
|
|
if ((!frameOk || mute_release_active) &&
|
|
(pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_LPD)) {
|
|
/* Restore old LSF4 */
|
|
FDKmemcpy(pAacDecoderStaticChannelInfo->lpc4_lsf, hConcealmentInfo->lsf4,
|
|
sizeof(pAacDecoderStaticChannelInfo->lpc4_lsf));
|
|
/* Restore old TCX gain */
|
|
pAacDecoderStaticChannelInfo->last_tcx_gain =
|
|
hConcealmentInfo->last_tcx_gain;
|
|
pAacDecoderStaticChannelInfo->last_tcx_gain_e =
|
|
hConcealmentInfo->last_tcx_gain_e;
|
|
}
|
|
|
|
if (!(pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_LPD &&
|
|
pAacDecoderStaticChannelInfo->last_lpd_mode == 0)) {
|
|
switch (hConcealmentInfo->pConcealParams->method) {
|
|
default:
|
|
case ConcealMethodMute:
|
|
if (!frameOk) {
|
|
/* Mute spectral data in case of errors */
|
|
FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient,
|
|
samplesPerFrame * sizeof(FIXP_DBL));
|
|
/* Set last window shape */
|
|
pAacDecoderChannelInfo->icsInfo.WindowShape =
|
|
hConcealmentInfo->windowShape;
|
|
appliedProcessing = 1;
|
|
}
|
|
break;
|
|
|
|
case ConcealMethodNoise:
|
|
/* Noise substitution error concealment technique */
|
|
appliedProcessing = CConcealment_ApplyNoise(
|
|
hConcealmentInfo, pAacDecoderChannelInfo,
|
|
pAacDecoderStaticChannelInfo, pSamplingRateInfo, samplesPerFrame,
|
|
flags);
|
|
break;
|
|
|
|
case ConcealMethodInter:
|
|
/* Energy interpolation concealment based on 3GPP */
|
|
appliedProcessing = CConcealment_ApplyInter(
|
|
hConcealmentInfo, pAacDecoderChannelInfo, pSamplingRateInfo,
|
|
samplesPerFrame, 0, /* don't use tonal improvement */
|
|
frameOk, mute_release_active);
|
|
break;
|
|
}
|
|
} else if (!frameOk || mute_release_active) {
|
|
/* simply restore the buffer */
|
|
FIXP_DBL *pSpectralCoefficient =
|
|
SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient);
|
|
SHORT *pSpecScale = pAacDecoderChannelInfo->specScale;
|
|
CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo;
|
|
#if (CNCL_FRACT_BITS != DFRACT_BITS)
|
|
FIXP_CNCL *RESTRICT pCncl =
|
|
&hConcealmentInfo->spectralCoefficient[1024 - 1];
|
|
FIXP_DBL *RESTRICT pSpec = &pSpectralCoefficient[1024 - 1];
|
|
int i;
|
|
#endif
|
|
|
|
/* restore window infos (gri) do we need that? */
|
|
pIcsInfo->WindowSequence = hConcealmentInfo->windowSequence;
|
|
pIcsInfo->WindowShape = hConcealmentInfo->windowShape;
|
|
|
|
if (hConcealmentInfo->concealState != ConcealState_Mute) {
|
|
/* restore scale factors */
|
|
FDKmemcpy(pSpecScale, hConcealmentInfo->specScale, 8 * sizeof(SHORT));
|
|
|
|
/* restore spectral bins */
|
|
#if (CNCL_FRACT_BITS == DFRACT_BITS)
|
|
FDKmemcpy(pSpectralCoefficient, hConcealmentInfo->spectralCoefficient,
|
|
1024 * sizeof(FIXP_DBL));
|
|
#else
|
|
for (i = 1024; i != 0; i--) {
|
|
*pSpec-- = FX_CNCL2FX_DBL(*pCncl--);
|
|
}
|
|
#endif
|
|
} else {
|
|
/* clear scale factors */
|
|
FDKmemclear(pSpecScale, 8 * sizeof(SHORT));
|
|
|
|
/* clear buffer */
|
|
FDKmemclear(pSpectralCoefficient, 1024 * sizeof(FIXP_CNCL));
|
|
}
|
|
}
|
|
}
|
|
/* update history */
|
|
hConcealmentInfo->prevFrameOk[0] = hConcealmentInfo->prevFrameOk[1];
|
|
hConcealmentInfo->prevFrameOk[1] = frameOk;
|
|
|
|
return mute_release_active ? -1 : appliedProcessing;
|
|
}
|
|
|
|
/*!
|
|
\brief Apply concealment noise substitution
|
|
|
|
In case of frame lost this function produces a noisy frame with respect to the
|
|
energies values of past frame.
|
|
*/
|
|
static int CConcealment_ApplyNoise(
|
|
CConcealmentInfo *pConcealmentInfo,
|
|
CAacDecoderChannelInfo *pAacDecoderChannelInfo,
|
|
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
|
|
const SamplingRateInfo *pSamplingRateInfo, const int samplesPerFrame,
|
|
const UINT flags) {
|
|
FIXP_DBL *pSpectralCoefficient =
|
|
SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient);
|
|
CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo;
|
|
|
|
int appliedProcessing = 0;
|
|
|
|
FDK_ASSERT(pConcealmentInfo != NULL);
|
|
FDK_ASSERT((samplesPerFrame >= 120) && (samplesPerFrame <= 1024));
|
|
|
|
switch (pConcealmentInfo->concealState) {
|
|
case ConcealState_Ok:
|
|
/* Nothing to do here! */
|
|
break;
|
|
|
|
case ConcealState_Single:
|
|
case ConcealState_FadeOut:
|
|
appliedProcessing = CConcealment_ApplyFadeOut(
|
|
/*mode =*/1, pConcealmentInfo, pAacDecoderStaticChannelInfo,
|
|
samplesPerFrame, pAacDecoderChannelInfo);
|
|
break;
|
|
|
|
case ConcealState_Mute: {
|
|
/* set dummy window parameters */
|
|
pIcsInfo->Valid = 0; /* Trigger the generation of a consitent IcsInfo */
|
|
pIcsInfo->WindowShape =
|
|
pConcealmentInfo->windowShape; /* Prevent an invalid WindowShape
|
|
(required for F/T transform) */
|
|
pIcsInfo->WindowSequence =
|
|
CConcealment_GetWinSeq(pConcealmentInfo->windowSequence);
|
|
pConcealmentInfo->windowSequence =
|
|
pIcsInfo->WindowSequence; /* Store for next frame
|
|
(spectrum in concealment
|
|
buffer can't be used at
|
|
all) */
|
|
|
|
/* mute spectral data */
|
|
FDKmemclear(pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL));
|
|
FDKmemclear(pConcealmentInfo->spectralCoefficient,
|
|
samplesPerFrame * sizeof(FIXP_DBL));
|
|
|
|
appliedProcessing = 1;
|
|
} break;
|
|
|
|
case ConcealState_FadeIn: {
|
|
/* TimeDomainFading: */
|
|
/* Attenuation of signal is done in CConcealment_TDFading() */
|
|
|
|
appliedProcessing = 1;
|
|
} break;
|
|
|
|
default:
|
|
/* we shouldn't come here anyway */
|
|
FDK_ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
return appliedProcessing;
|
|
}
|
|
|
|
/*!
|
|
\brief Apply concealment interpolation
|
|
|
|
The function swaps the data from the current and the previous frame. If an
|
|
error has occured, frame interpolation is performed to restore the missing
|
|
frame. In case of multiple faulty frames, fade-in and fade-out is applied.
|
|
*/
|
|
static int CConcealment_ApplyInter(
|
|
CConcealmentInfo *pConcealmentInfo,
|
|
CAacDecoderChannelInfo *pAacDecoderChannelInfo,
|
|
const SamplingRateInfo *pSamplingRateInfo, const int samplesPerFrame,
|
|
const int improveTonal, const int frameOk, const int mute_release_active) {
|
|
#if defined(FDK_ASSERT_ENABLE)
|
|
CConcealParams *pConcealCommonData = pConcealmentInfo->pConcealParams;
|
|
#endif
|
|
|
|
FIXP_DBL *pSpectralCoefficient =
|
|
SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient);
|
|
CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo;
|
|
SHORT *pSpecScale = pAacDecoderChannelInfo->specScale;
|
|
|
|
int sfbEnergyPrev[64];
|
|
int sfbEnergyAct[64];
|
|
|
|
int i, appliedProcessing = 0;
|
|
|
|
/* clear/init */
|
|
FDKmemclear(sfbEnergyPrev, 64 * sizeof(int));
|
|
FDKmemclear(sfbEnergyAct, 64 * sizeof(int));
|
|
|
|
if (!frameOk || mute_release_active) {
|
|
/* Restore last frame from concealment buffer */
|
|
pIcsInfo->WindowShape = pConcealmentInfo->windowShape;
|
|
pIcsInfo->WindowSequence = pConcealmentInfo->windowSequence;
|
|
|
|
/* Restore spectral data */
|
|
for (i = 0; i < samplesPerFrame; i++) {
|
|
pSpectralCoefficient[i] =
|
|
FX_CNCL2FX_DBL(pConcealmentInfo->spectralCoefficient[i]);
|
|
}
|
|
|
|
/* Restore scale factors */
|
|
FDKmemcpy(pSpecScale, pConcealmentInfo->specScale, 8 * sizeof(SHORT));
|
|
}
|
|
|
|
/* if previous frame was not ok */
|
|
if (!pConcealmentInfo->prevFrameOk[1] || mute_release_active) {
|
|
/* if current frame (f_n) is ok and the last but one frame (f_(n-2))
|
|
was ok, too, then interpolate both frames in order to generate
|
|
the current output frame (f_(n-1)). Otherwise, use the last stored
|
|
frame (f_(n-2) or f_(n-3) or ...). */
|
|
if (frameOk && pConcealmentInfo->prevFrameOk[0] && !mute_release_active) {
|
|
appliedProcessing = 1;
|
|
|
|
/* Interpolate both frames in order to generate the current output frame
|
|
* (f_(n-1)). */
|
|
if (pIcsInfo->WindowSequence == BLOCK_SHORT) {
|
|
/* f_(n-2) == BLOCK_SHORT */
|
|
/* short--??????--short, short--??????--long interpolation */
|
|
/* short--short---short, short---long---long interpolation */
|
|
|
|
int wnd;
|
|
|
|
if (pConcealmentInfo->windowSequence ==
|
|
BLOCK_SHORT) { /* f_n == BLOCK_SHORT */
|
|
/* short--short---short interpolation */
|
|
|
|
int scaleFactorBandsTotal =
|
|
pSamplingRateInfo->NumberOfScaleFactorBands_Short;
|
|
const SHORT *pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Short;
|
|
pIcsInfo->WindowShape = (samplesPerFrame <= 512) ? 2 : 1;
|
|
pIcsInfo->WindowSequence = BLOCK_SHORT;
|
|
|
|
for (wnd = 0; wnd < 8; wnd++) {
|
|
CConcealment_CalcBandEnergy(
|
|
&pSpectralCoefficient[wnd *
|
|
(samplesPerFrame / 8)], /* spec_(n-2) */
|
|
pSamplingRateInfo, BLOCK_SHORT, CConcealment_NoExpand,
|
|
sfbEnergyPrev);
|
|
|
|
CConcealment_CalcBandEnergy(
|
|
&pConcealmentInfo->spectralCoefficient[wnd * (samplesPerFrame /
|
|
8)], /* spec_n */
|
|
pSamplingRateInfo, BLOCK_SHORT, CConcealment_NoExpand,
|
|
sfbEnergyAct);
|
|
|
|
CConcealment_InterpolateBuffer(
|
|
&pSpectralCoefficient[wnd *
|
|
(samplesPerFrame / 8)], /* spec_(n-1) */
|
|
&pSpecScale[wnd], &pConcealmentInfo->specScale[wnd],
|
|
&pSpecScale[wnd], sfbEnergyPrev, sfbEnergyAct,
|
|
scaleFactorBandsTotal, pSfbOffset);
|
|
}
|
|
} else { /* f_n != BLOCK_SHORT */
|
|
/* short---long---long interpolation */
|
|
|
|
int scaleFactorBandsTotal =
|
|
pSamplingRateInfo->NumberOfScaleFactorBands_Long;
|
|
const SHORT *pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Long;
|
|
SHORT specScaleOut;
|
|
|
|
CConcealment_CalcBandEnergy(
|
|
&pSpectralCoefficient[samplesPerFrame -
|
|
(samplesPerFrame /
|
|
8)], /* [wnd] spec_(n-2) */
|
|
pSamplingRateInfo, BLOCK_SHORT, CConcealment_Expand,
|
|
sfbEnergyAct);
|
|
|
|
CConcealment_CalcBandEnergy(
|
|
pConcealmentInfo->spectralCoefficient, /* spec_n */
|
|
pSamplingRateInfo, BLOCK_LONG, CConcealment_NoExpand,
|
|
sfbEnergyPrev);
|
|
|
|
pIcsInfo->WindowShape = 0;
|
|
pIcsInfo->WindowSequence = BLOCK_STOP;
|
|
|
|
for (i = 0; i < samplesPerFrame; i++) {
|
|
pSpectralCoefficient[i] =
|
|
pConcealmentInfo->spectralCoefficient[i]; /* spec_n */
|
|
}
|
|
|
|
for (i = 0; i < 8; i++) { /* search for max(specScale) */
|
|
if (pSpecScale[i] > pSpecScale[0]) {
|
|
pSpecScale[0] = pSpecScale[i];
|
|
}
|
|
}
|
|
|
|
CConcealment_InterpolateBuffer(
|
|
pSpectralCoefficient, /* spec_(n-1) */
|
|
&pConcealmentInfo->specScale[0], &pSpecScale[0], &specScaleOut,
|
|
sfbEnergyPrev, sfbEnergyAct, scaleFactorBandsTotal, pSfbOffset);
|
|
|
|
pSpecScale[0] = specScaleOut;
|
|
}
|
|
} else {
|
|
/* long--??????--short, long--??????--long interpolation */
|
|
/* long---long---short, long---long---long interpolation */
|
|
|
|
int scaleFactorBandsTotal =
|
|
pSamplingRateInfo->NumberOfScaleFactorBands_Long;
|
|
const SHORT *pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Long;
|
|
SHORT specScaleAct = pConcealmentInfo->specScale[0];
|
|
|
|
CConcealment_CalcBandEnergy(pSpectralCoefficient, /* spec_(n-2) */
|
|
pSamplingRateInfo, BLOCK_LONG,
|
|
CConcealment_NoExpand, sfbEnergyPrev);
|
|
|
|
if (pConcealmentInfo->windowSequence ==
|
|
BLOCK_SHORT) { /* f_n == BLOCK_SHORT */
|
|
/* long---long---short interpolation */
|
|
|
|
pIcsInfo->WindowShape = (samplesPerFrame <= 512) ? 2 : 1;
|
|
pIcsInfo->WindowSequence = BLOCK_START;
|
|
|
|
for (i = 1; i < 8; i++) { /* search for max(specScale) */
|
|
if (pConcealmentInfo->specScale[i] > specScaleAct) {
|
|
specScaleAct = pConcealmentInfo->specScale[i];
|
|
}
|
|
}
|
|
|
|
/* Expand first short spectrum */
|
|
CConcealment_CalcBandEnergy(
|
|
pConcealmentInfo->spectralCoefficient, /* spec_n */
|
|
pSamplingRateInfo, BLOCK_SHORT, CConcealment_Expand, /* !!! */
|
|
sfbEnergyAct);
|
|
} else {
|
|
/* long---long---long interpolation */
|
|
|
|
pIcsInfo->WindowShape = 0;
|
|
pIcsInfo->WindowSequence = BLOCK_LONG;
|
|
|
|
CConcealment_CalcBandEnergy(
|
|
pConcealmentInfo->spectralCoefficient, /* spec_n */
|
|
pSamplingRateInfo, BLOCK_LONG, CConcealment_NoExpand,
|
|
sfbEnergyAct);
|
|
}
|
|
|
|
CConcealment_InterpolateBuffer(
|
|
pSpectralCoefficient, /* spec_(n-1) */
|
|
&pSpecScale[0], &specScaleAct, &pSpecScale[0], sfbEnergyPrev,
|
|
sfbEnergyAct, scaleFactorBandsTotal, pSfbOffset);
|
|
}
|
|
}
|
|
|
|
/* Noise substitution of sign of the output spectral coefficients */
|
|
CConcealment_ApplyRandomSign(pConcealmentInfo->iRandomPhase,
|
|
pSpectralCoefficient, samplesPerFrame);
|
|
/* Increment random phase index to avoid repetition artifacts. */
|
|
pConcealmentInfo->iRandomPhase =
|
|
(pConcealmentInfo->iRandomPhase + 1) & (AAC_NF_NO_RANDOM_VAL - 1);
|
|
}
|
|
|
|
/* scale spectrum according to concealment state */
|
|
switch (pConcealmentInfo->concealState) {
|
|
case ConcealState_Single:
|
|
appliedProcessing = 1;
|
|
break;
|
|
|
|
case ConcealState_FadeOut: {
|
|
FDK_ASSERT(pConcealmentInfo->cntFadeFrames >= 0);
|
|
FDK_ASSERT(pConcealmentInfo->cntFadeFrames <
|
|
CONCEAL_MAX_NUM_FADE_FACTORS);
|
|
FDK_ASSERT(pConcealmentInfo->cntFadeFrames <
|
|
pConcealCommonData->numFadeOutFrames);
|
|
|
|
/* TimeDomainFading: */
|
|
/* Attenuation of signal is done in CConcealment_TDFading() */
|
|
|
|
appliedProcessing = 1;
|
|
} break;
|
|
|
|
case ConcealState_FadeIn: {
|
|
FDK_ASSERT(pConcealmentInfo->cntFadeFrames >= 0);
|
|
FDK_ASSERT(pConcealmentInfo->cntFadeFrames <
|
|
CONCEAL_MAX_NUM_FADE_FACTORS);
|
|
FDK_ASSERT(pConcealmentInfo->cntFadeFrames <
|
|
pConcealCommonData->numFadeInFrames);
|
|
|
|
/* TimeDomainFading: */
|
|
/* Attenuation of signal is done in CConcealment_TDFading() */
|
|
|
|
appliedProcessing = 1;
|
|
} break;
|
|
|
|
case ConcealState_Mute: {
|
|
/* set dummy window parameters */
|
|
pIcsInfo->Valid = 0; /* Trigger the generation of a consitent IcsInfo */
|
|
pIcsInfo->WindowShape =
|
|
pConcealmentInfo->windowShape; /* Prevent an invalid WindowShape
|
|
(required for F/T transform) */
|
|
pIcsInfo->WindowSequence =
|
|
CConcealment_GetWinSeq(pConcealmentInfo->windowSequence);
|
|
pConcealmentInfo->windowSequence =
|
|
pIcsInfo->WindowSequence; /* Store for next frame
|
|
(spectrum in concealment
|
|
buffer can't be used at
|
|
all) */
|
|
|
|
/* mute spectral data */
|
|
FDKmemclear(pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL));
|
|
|
|
appliedProcessing = 1;
|
|
} break;
|
|
|
|
default:
|
|
/* nothing to do here */
|
|
break;
|
|
}
|
|
|
|
return appliedProcessing;
|
|
}
|
|
|
|
/*!
|
|
\brief Calculate the spectral energy
|
|
|
|
The function calculates band-wise the spectral energy. This is used for
|
|
frame interpolation.
|
|
*/
|
|
static void CConcealment_CalcBandEnergy(
|
|
FIXP_DBL *spectrum, const SamplingRateInfo *pSamplingRateInfo,
|
|
const int blockType, CConcealmentExpandType expandType, int *sfbEnergy) {
|
|
const SHORT *pSfbOffset;
|
|
int line, sfb, scaleFactorBandsTotal = 0;
|
|
|
|
/* In the following calculations, enAccu is initialized with LSB-value in
|
|
* order to avoid zero energy-level */
|
|
|
|
line = 0;
|
|
|
|
switch (blockType) {
|
|
case BLOCK_LONG:
|
|
case BLOCK_START:
|
|
case BLOCK_STOP:
|
|
|
|
if (expandType == CConcealment_NoExpand) {
|
|
/* standard long calculation */
|
|
scaleFactorBandsTotal =
|
|
pSamplingRateInfo->NumberOfScaleFactorBands_Long;
|
|
pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Long;
|
|
|
|
for (sfb = 0; sfb < scaleFactorBandsTotal; sfb++) {
|
|
FIXP_DBL enAccu = (FIXP_DBL)(LONG)1;
|
|
int sfbScale =
|
|
(sizeof(LONG) << 3) -
|
|
CntLeadingZeros(pSfbOffset[sfb + 1] - pSfbOffset[sfb]) - 1;
|
|
/* scaling depends on sfb width. */
|
|
for (; line < pSfbOffset[sfb + 1]; line++) {
|
|
enAccu += fPow2Div2(*(spectrum + line)) >> sfbScale;
|
|
}
|
|
*(sfbEnergy + sfb) = CntLeadingZeros(enAccu) - 1;
|
|
}
|
|
} else {
|
|
/* compress long to short */
|
|
scaleFactorBandsTotal =
|
|
pSamplingRateInfo->NumberOfScaleFactorBands_Short;
|
|
pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Short;
|
|
|
|
for (sfb = 0; sfb < scaleFactorBandsTotal; sfb++) {
|
|
FIXP_DBL enAccu = (FIXP_DBL)(LONG)1;
|
|
int sfbScale =
|
|
(sizeof(LONG) << 3) -
|
|
CntLeadingZeros(pSfbOffset[sfb + 1] - pSfbOffset[sfb]) - 1;
|
|
/* scaling depends on sfb width. */
|
|
for (; line < pSfbOffset[sfb + 1] << 3; line++) {
|
|
enAccu +=
|
|
(enAccu + (fPow2Div2(*(spectrum + line)) >> sfbScale)) >> 3;
|
|
}
|
|
*(sfbEnergy + sfb) = CntLeadingZeros(enAccu) - 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BLOCK_SHORT:
|
|
|
|
if (expandType == CConcealment_NoExpand) {
|
|
/* standard short calculation */
|
|
scaleFactorBandsTotal =
|
|
pSamplingRateInfo->NumberOfScaleFactorBands_Short;
|
|
pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Short;
|
|
|
|
for (sfb = 0; sfb < scaleFactorBandsTotal; sfb++) {
|
|
FIXP_DBL enAccu = (FIXP_DBL)(LONG)1;
|
|
int sfbScale =
|
|
(sizeof(LONG) << 3) -
|
|
CntLeadingZeros(pSfbOffset[sfb + 1] - pSfbOffset[sfb]) - 1;
|
|
/* scaling depends on sfb width. */
|
|
for (; line < pSfbOffset[sfb + 1]; line++) {
|
|
enAccu += fPow2Div2(*(spectrum + line)) >> sfbScale;
|
|
}
|
|
*(sfbEnergy + sfb) = CntLeadingZeros(enAccu) - 1;
|
|
}
|
|
} else {
|
|
/* expand short to long spectrum */
|
|
scaleFactorBandsTotal =
|
|
pSamplingRateInfo->NumberOfScaleFactorBands_Long;
|
|
pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Long;
|
|
|
|
for (sfb = 0; sfb < scaleFactorBandsTotal; sfb++) {
|
|
FIXP_DBL enAccu = (FIXP_DBL)(LONG)1;
|
|
int sfbScale =
|
|
(sizeof(LONG) << 3) -
|
|
CntLeadingZeros(pSfbOffset[sfb + 1] - pSfbOffset[sfb]) - 1;
|
|
/* scaling depends on sfb width. */
|
|
for (; line < pSfbOffset[sfb + 1]; line++) {
|
|
enAccu += fPow2Div2(*(spectrum + (line >> 3))) >> sfbScale;
|
|
}
|
|
*(sfbEnergy + sfb) = CntLeadingZeros(enAccu) - 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief Interpolate buffer
|
|
|
|
The function creates the interpolated spectral data according to the
|
|
energy of the last good frame and the current (good) frame.
|
|
*/
|
|
static void CConcealment_InterpolateBuffer(FIXP_DBL *spectrum,
|
|
SHORT *pSpecScalePrv,
|
|
SHORT *pSpecScaleAct,
|
|
SHORT *pSpecScaleOut, int *enPrv,
|
|
int *enAct, int sfbCnt,
|
|
const SHORT *pSfbOffset) {
|
|
int sfb, line = 0;
|
|
int fac_shift;
|
|
int fac_mod;
|
|
FIXP_DBL accu;
|
|
|
|
for (sfb = 0; sfb < sfbCnt; sfb++) {
|
|
fac_shift =
|
|
enPrv[sfb] - enAct[sfb] + ((*pSpecScaleAct - *pSpecScalePrv) << 1);
|
|
fac_mod = fac_shift & 3;
|
|
fac_shift = (fac_shift >> 2) + 1;
|
|
fac_shift += *pSpecScalePrv - fixMax(*pSpecScalePrv, *pSpecScaleAct);
|
|
|
|
for (; line < pSfbOffset[sfb + 1]; line++) {
|
|
accu = fMult(*(spectrum + line), facMod4Table[fac_mod]);
|
|
if (fac_shift < 0) {
|
|
accu >>= -fac_shift;
|
|
} else {
|
|
accu <<= fac_shift;
|
|
}
|
|
*(spectrum + line) = accu;
|
|
}
|
|
}
|
|
*pSpecScaleOut = fixMax(*pSpecScalePrv, *pSpecScaleAct);
|
|
}
|
|
|
|
/*!
|
|
\brief Find next fading frame in case of changing fading direction
|
|
|
|
\param pConcealCommonData Pointer to the concealment common data structure.
|
|
\param actFadeIndex Last index used for fading
|
|
\param direction Direction of change: 0 : change from FADE-OUT to FADE-IN, 1
|
|
: change from FADE-IN to FADE-OUT
|
|
|
|
This function determines the next fading index to be used for the fading
|
|
direction to be changed to.
|
|
*/
|
|
|
|
static INT findEquiFadeFrame(CConcealParams *pConcealCommonData,
|
|
INT actFadeIndex, int direction) {
|
|
FIXP_SGL *pFactor;
|
|
FIXP_SGL referenceVal;
|
|
FIXP_SGL minDiff = (FIXP_SGL)MAXVAL_SGL;
|
|
|
|
INT nextFadeIndex = 0;
|
|
|
|
int i;
|
|
|
|
/* init depending on direction */
|
|
if (direction == 0) { /* FADE-OUT => FADE-IN */
|
|
if (actFadeIndex < 0) {
|
|
referenceVal = (FIXP_SGL)MAXVAL_SGL;
|
|
} else {
|
|
referenceVal = pConcealCommonData->fadeOutFactor[actFadeIndex] >> 1;
|
|
}
|
|
pFactor = pConcealCommonData->fadeInFactor;
|
|
} else { /* FADE-IN => FADE-OUT */
|
|
if (actFadeIndex < 0) {
|
|
referenceVal = (FIXP_SGL)MAXVAL_SGL;
|
|
} else {
|
|
referenceVal = pConcealCommonData->fadeInFactor[actFadeIndex] >> 1;
|
|
}
|
|
pFactor = pConcealCommonData->fadeOutFactor;
|
|
}
|
|
|
|
/* search for minimum difference */
|
|
for (i = 0; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) {
|
|
FIXP_SGL diff = fixp_abs((pFactor[i] >> 1) - referenceVal);
|
|
if (diff < minDiff) {
|
|
minDiff = diff;
|
|
nextFadeIndex = i;
|
|
}
|
|
}
|
|
|
|
/* check and adjust depending on direction */
|
|
if (direction == 0) { /* FADE-OUT => FADE-IN */
|
|
if (nextFadeIndex > pConcealCommonData->numFadeInFrames) {
|
|
nextFadeIndex = fMax(pConcealCommonData->numFadeInFrames - 1, 0);
|
|
}
|
|
if (((pFactor[nextFadeIndex] >> 1) <= referenceVal) &&
|
|
(nextFadeIndex > 0)) {
|
|
nextFadeIndex -= 1;
|
|
}
|
|
} else { /* FADE-IN => FADE-OUT */
|
|
if (((pFactor[nextFadeIndex] >> 1) >= referenceVal) &&
|
|
(nextFadeIndex < CONCEAL_MAX_NUM_FADE_FACTORS - 1)) {
|
|
nextFadeIndex += 1;
|
|
}
|
|
}
|
|
|
|
return (nextFadeIndex);
|
|
}
|
|
|
|
/*!
|
|
\brief Update the concealment state
|
|
|
|
The function updates the state of the concealment state-machine. The
|
|
states are: mute, fade-in, fade-out, interpolate and frame-ok.
|
|
*/
|
|
static void CConcealment_UpdateState(
|
|
CConcealmentInfo *pConcealmentInfo, int frameOk,
|
|
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
|
|
const int samplesPerFrame, CAacDecoderChannelInfo *pAacDecoderChannelInfo) {
|
|
CConcealParams *pConcealCommonData = pConcealmentInfo->pConcealParams;
|
|
|
|
switch (pConcealCommonData->method) {
|
|
case ConcealMethodNoise: {
|
|
if (pConcealmentInfo->concealState != ConcealState_Ok) {
|
|
/* count the valid frames during concealment process */
|
|
if (frameOk) {
|
|
pConcealmentInfo->cntValidFrames += 1;
|
|
} else {
|
|
pConcealmentInfo->cntValidFrames = 0;
|
|
}
|
|
}
|
|
|
|
/* -- STATE MACHINE for Noise Substitution -- */
|
|
switch (pConcealmentInfo->concealState) {
|
|
case ConcealState_Ok:
|
|
if (!frameOk) {
|
|
pConcealmentInfo->cntFadeFrames = 0;
|
|
pConcealmentInfo->cntValidFrames = 0;
|
|
pConcealmentInfo->attGrpOffset[0] = 0;
|
|
pConcealmentInfo->attGrpOffset[1] = 0;
|
|
pConcealmentInfo->winGrpOffset[0] = 0;
|
|
pConcealmentInfo->winGrpOffset[1] = 0;
|
|
if (pConcealCommonData->numFadeOutFrames > 0) {
|
|
/* change to state SINGLE-FRAME-LOSS */
|
|
pConcealmentInfo->concealState = ConcealState_Single;
|
|
/* mode 0 just updates the Fading counter */
|
|
CConcealment_ApplyFadeOut(
|
|
/*mode =*/0, pConcealmentInfo, pAacDecoderStaticChannelInfo,
|
|
samplesPerFrame, pAacDecoderChannelInfo);
|
|
|
|
} else {
|
|
/* change to state MUTE */
|
|
pConcealmentInfo->concealState = ConcealState_Mute;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ConcealState_Single: /* Just a pre-stage before fade-out begins.
|
|
Stay here only one frame! */
|
|
if (frameOk) {
|
|
/* change to state OK */
|
|
pConcealmentInfo->concealState = ConcealState_Ok;
|
|
} else {
|
|
if (pConcealmentInfo->cntFadeFrames >=
|
|
pConcealCommonData->numFadeOutFrames) {
|
|
/* change to state MUTE */
|
|
pConcealmentInfo->concealState = ConcealState_Mute;
|
|
} else {
|
|
/* change to state FADE-OUT */
|
|
pConcealmentInfo->concealState = ConcealState_FadeOut;
|
|
/* mode 0 just updates the Fading counter */
|
|
CConcealment_ApplyFadeOut(
|
|
/*mode =*/0, pConcealmentInfo, pAacDecoderStaticChannelInfo,
|
|
samplesPerFrame, pAacDecoderChannelInfo);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ConcealState_FadeOut:
|
|
if (pConcealmentInfo->cntValidFrames >
|
|
pConcealCommonData->numMuteReleaseFrames) {
|
|
if (pConcealCommonData->numFadeInFrames > 0) {
|
|
/* change to state FADE-IN */
|
|
pConcealmentInfo->concealState = ConcealState_FadeIn;
|
|
pConcealmentInfo->cntFadeFrames = findEquiFadeFrame(
|
|
pConcealCommonData, pConcealmentInfo->cntFadeFrames,
|
|
0 /* FadeOut -> FadeIn */);
|
|
} else {
|
|
/* change to state OK */
|
|
pConcealmentInfo->concealState = ConcealState_Ok;
|
|
}
|
|
} else {
|
|
if (frameOk) {
|
|
/* we have good frame information but stay fully in concealment -
|
|
* reset winGrpOffset/attGrpOffset */
|
|
pConcealmentInfo->winGrpOffset[0] = 0;
|
|
pConcealmentInfo->winGrpOffset[1] = 0;
|
|
pConcealmentInfo->attGrpOffset[0] = 0;
|
|
pConcealmentInfo->attGrpOffset[1] = 0;
|
|
}
|
|
if (pConcealmentInfo->cntFadeFrames >=
|
|
pConcealCommonData->numFadeOutFrames) {
|
|
/* change to state MUTE */
|
|
pConcealmentInfo->concealState = ConcealState_Mute;
|
|
} else /* Stay in FADE-OUT */
|
|
{
|
|
/* mode 0 just updates the Fading counter */
|
|
CConcealment_ApplyFadeOut(
|
|
/*mode =*/0, pConcealmentInfo, pAacDecoderStaticChannelInfo,
|
|
samplesPerFrame, pAacDecoderChannelInfo);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ConcealState_Mute:
|
|
if (pConcealmentInfo->cntValidFrames >
|
|
pConcealCommonData->numMuteReleaseFrames) {
|
|
if (pConcealCommonData->numFadeInFrames > 0) {
|
|
/* change to state FADE-IN */
|
|
pConcealmentInfo->concealState = ConcealState_FadeIn;
|
|
pConcealmentInfo->cntFadeFrames =
|
|
pConcealCommonData->numFadeInFrames - 1;
|
|
} else {
|
|
/* change to state OK */
|
|
pConcealmentInfo->concealState = ConcealState_Ok;
|
|
}
|
|
} else {
|
|
if (frameOk) {
|
|
/* we have good frame information but stay fully in concealment -
|
|
* reset winGrpOffset/attGrpOffset */
|
|
pConcealmentInfo->winGrpOffset[0] = 0;
|
|
pConcealmentInfo->winGrpOffset[1] = 0;
|
|
pConcealmentInfo->attGrpOffset[0] = 0;
|
|
pConcealmentInfo->attGrpOffset[1] = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ConcealState_FadeIn:
|
|
pConcealmentInfo->cntFadeFrames -= 1;
|
|
if (frameOk) {
|
|
if (pConcealmentInfo->cntFadeFrames < 0) {
|
|
/* change to state OK */
|
|
pConcealmentInfo->concealState = ConcealState_Ok;
|
|
}
|
|
} else {
|
|
if (pConcealCommonData->numFadeOutFrames > 0) {
|
|
/* change to state FADE-OUT */
|
|
pConcealmentInfo->concealState = ConcealState_FadeOut;
|
|
pConcealmentInfo->cntFadeFrames = findEquiFadeFrame(
|
|
pConcealCommonData, pConcealmentInfo->cntFadeFrames + 1,
|
|
1 /* FadeIn -> FadeOut */);
|
|
pConcealmentInfo->winGrpOffset[0] = 0;
|
|
pConcealmentInfo->winGrpOffset[1] = 0;
|
|
pConcealmentInfo->attGrpOffset[0] = 0;
|
|
pConcealmentInfo->attGrpOffset[1] = 0;
|
|
|
|
pConcealmentInfo
|
|
->cntFadeFrames--; /* decrease because
|
|
CConcealment_ApplyFadeOut() will
|
|
increase, accordingly */
|
|
/* mode 0 just updates the Fading counter */
|
|
CConcealment_ApplyFadeOut(
|
|
/*mode =*/0, pConcealmentInfo, pAacDecoderStaticChannelInfo,
|
|
samplesPerFrame, pAacDecoderChannelInfo);
|
|
} else {
|
|
/* change to state MUTE */
|
|
pConcealmentInfo->concealState = ConcealState_Mute;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
FDK_ASSERT(0);
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
case ConcealMethodInter:
|
|
case ConcealMethodTonal: {
|
|
if (pConcealmentInfo->concealState != ConcealState_Ok) {
|
|
/* count the valid frames during concealment process */
|
|
if (pConcealmentInfo->prevFrameOk[1] ||
|
|
(pConcealmentInfo->prevFrameOk[0] &&
|
|
!pConcealmentInfo->prevFrameOk[1] && frameOk)) {
|
|
/* The frame is OK even if it can be estimated by the energy
|
|
* interpolation algorithm */
|
|
pConcealmentInfo->cntValidFrames += 1;
|
|
} else {
|
|
pConcealmentInfo->cntValidFrames = 0;
|
|
}
|
|
}
|
|
|
|
/* -- STATE MACHINE for energy interpolation -- */
|
|
switch (pConcealmentInfo->concealState) {
|
|
case ConcealState_Ok:
|
|
if (!(pConcealmentInfo->prevFrameOk[1] ||
|
|
(pConcealmentInfo->prevFrameOk[0] &&
|
|
!pConcealmentInfo->prevFrameOk[1] && frameOk))) {
|
|
if (pConcealCommonData->numFadeOutFrames > 0) {
|
|
/* Fade out only if the energy interpolation algorithm can not be
|
|
* applied! */
|
|
pConcealmentInfo->concealState = ConcealState_FadeOut;
|
|
} else {
|
|
/* change to state MUTE */
|
|
pConcealmentInfo->concealState = ConcealState_Mute;
|
|
}
|
|
pConcealmentInfo->cntFadeFrames = 0;
|
|
pConcealmentInfo->cntValidFrames = 0;
|
|
}
|
|
break;
|
|
|
|
case ConcealState_Single:
|
|
pConcealmentInfo->concealState = ConcealState_Ok;
|
|
break;
|
|
|
|
case ConcealState_FadeOut:
|
|
pConcealmentInfo->cntFadeFrames += 1;
|
|
|
|
if (pConcealmentInfo->cntValidFrames >
|
|
pConcealCommonData->numMuteReleaseFrames) {
|
|
if (pConcealCommonData->numFadeInFrames > 0) {
|
|
/* change to state FADE-IN */
|
|
pConcealmentInfo->concealState = ConcealState_FadeIn;
|
|
pConcealmentInfo->cntFadeFrames = findEquiFadeFrame(
|
|
pConcealCommonData, pConcealmentInfo->cntFadeFrames - 1,
|
|
0 /* FadeOut -> FadeIn */);
|
|
} else {
|
|
/* change to state OK */
|
|
pConcealmentInfo->concealState = ConcealState_Ok;
|
|
}
|
|
} else {
|
|
if (pConcealmentInfo->cntFadeFrames >=
|
|
pConcealCommonData->numFadeOutFrames) {
|
|
/* change to state MUTE */
|
|
pConcealmentInfo->concealState = ConcealState_Mute;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ConcealState_Mute:
|
|
if (pConcealmentInfo->cntValidFrames >
|
|
pConcealCommonData->numMuteReleaseFrames) {
|
|
if (pConcealCommonData->numFadeInFrames > 0) {
|
|
/* change to state FADE-IN */
|
|
pConcealmentInfo->concealState = ConcealState_FadeIn;
|
|
pConcealmentInfo->cntFadeFrames =
|
|
pConcealCommonData->numFadeInFrames - 1;
|
|
} else {
|
|
/* change to state OK */
|
|
pConcealmentInfo->concealState = ConcealState_Ok;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ConcealState_FadeIn:
|
|
pConcealmentInfo->cntFadeFrames -=
|
|
1; /* used to address the fade-in factors */
|
|
|
|
if (frameOk || pConcealmentInfo->prevFrameOk[1]) {
|
|
if (pConcealmentInfo->cntFadeFrames < 0) {
|
|
/* change to state OK */
|
|
pConcealmentInfo->concealState = ConcealState_Ok;
|
|
}
|
|
} else {
|
|
if (pConcealCommonData->numFadeOutFrames > 0) {
|
|
/* change to state FADE-OUT */
|
|
pConcealmentInfo->concealState = ConcealState_FadeOut;
|
|
pConcealmentInfo->cntFadeFrames = findEquiFadeFrame(
|
|
pConcealCommonData, pConcealmentInfo->cntFadeFrames + 1,
|
|
1 /* FadeIn -> FadeOut */);
|
|
} else {
|
|
/* change to state MUTE */
|
|
pConcealmentInfo->concealState = ConcealState_Mute;
|
|
}
|
|
}
|
|
break;
|
|
} /* End switch(pConcealmentInfo->concealState) */
|
|
} break;
|
|
|
|
default:
|
|
/* Don't need a state machine for other concealment methods. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief Randomizes the sign of the spectral data
|
|
|
|
The function toggles the sign of the spectral data randomly. This is
|
|
useful to ensure the quality of the concealed frames.
|
|
*/
|
|
static void CConcealment_ApplyRandomSign(int randomPhase, FIXP_DBL *spec,
|
|
int samplesPerFrame) {
|
|
int i;
|
|
USHORT packedSign = 0;
|
|
|
|
/* random table 512x16bit has been reduced to 512 packed sign bits = 32x16 bit
|
|
*/
|
|
|
|
/* read current packed sign word */
|
|
packedSign = AacDec_randomSign[randomPhase >> 4];
|
|
packedSign >>= (randomPhase & 0xf);
|
|
|
|
for (i = 0; i < samplesPerFrame; i++) {
|
|
if ((randomPhase & 0xf) == 0) {
|
|
packedSign = AacDec_randomSign[randomPhase >> 4];
|
|
}
|
|
|
|
if (packedSign & 0x1) {
|
|
spec[i] = -spec[i];
|
|
}
|
|
packedSign >>= 1;
|
|
|
|
randomPhase = (randomPhase + 1) & (AAC_NF_NO_RANDOM_VAL - 1);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief Get fadeing factor for current concealment state.
|
|
|
|
The function returns the state (ok or not) of the previous frame.
|
|
If called before the function CConcealment_Apply() set the fBeforeApply
|
|
flag to get the correct value.
|
|
|
|
\return Frame OK flag of previous frame.
|
|
*/
|
|
int CConcealment_GetLastFrameOk(CConcealmentInfo *hConcealmentInfo,
|
|
const int fBeforeApply) {
|
|
int prevFrameOk = 1;
|
|
|
|
if (hConcealmentInfo != NULL) {
|
|
prevFrameOk = hConcealmentInfo->prevFrameOk[fBeforeApply & 0x1];
|
|
}
|
|
|
|
return prevFrameOk;
|
|
}
|
|
|
|
/*!
|
|
\brief Get the number of delay frames introduced by concealment technique.
|
|
|
|
\return Number of delay frames.
|
|
*/
|
|
UINT CConcealment_GetDelay(CConcealParams *pConcealCommonData) {
|
|
UINT frameDelay = 0;
|
|
|
|
if (pConcealCommonData != NULL) {
|
|
switch (pConcealCommonData->method) {
|
|
case ConcealMethodTonal:
|
|
case ConcealMethodInter:
|
|
frameDelay = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return frameDelay;
|
|
}
|
|
|
|
static int CConcealment_ApplyFadeOut(
|
|
int mode, CConcealmentInfo *pConcealmentInfo,
|
|
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
|
|
const int samplesPerFrame, CAacDecoderChannelInfo *pAacDecoderChannelInfo) {
|
|
/* mode 1 = apply RandomSign and mute spectral coefficients if necessary, *
|
|
* mode 0 = Update cntFadeFrames */
|
|
|
|
/* restore frequency coefficients from buffer with a specific muting */
|
|
int srcWin, dstWin, numWindows = 1;
|
|
int windowLen = samplesPerFrame;
|
|
int srcGrpStart = 0;
|
|
int winIdxStride = 1;
|
|
int numWinGrpPerFac, attIdx, attIdxStride;
|
|
int i;
|
|
int appliedProcessing = 0;
|
|
|
|
CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo;
|
|
FIXP_DBL *pSpectralCoefficient =
|
|
SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient);
|
|
SHORT *pSpecScale = pAacDecoderChannelInfo->specScale;
|
|
|
|
/* set old window parameters */
|
|
if (pConcealmentInfo->lastRenderMode == AACDEC_RENDER_LPD) {
|
|
switch (pAacDecoderStaticChannelInfo->last_lpd_mode) {
|
|
case 1:
|
|
numWindows = 4;
|
|
srcGrpStart = 3;
|
|
windowLen = samplesPerFrame >> 2;
|
|
break;
|
|
case 2:
|
|
numWindows = 2;
|
|
srcGrpStart = 1;
|
|
windowLen = samplesPerFrame >> 1;
|
|
winIdxStride = 2;
|
|
break;
|
|
case 3:
|
|
numWindows = 1;
|
|
srcGrpStart = 0;
|
|
windowLen = samplesPerFrame;
|
|
winIdxStride = 4;
|
|
break;
|
|
}
|
|
pConcealmentInfo->lastWinGrpLen = 1;
|
|
} else {
|
|
pIcsInfo->WindowShape = pConcealmentInfo->windowShape;
|
|
pIcsInfo->WindowSequence = pConcealmentInfo->windowSequence;
|
|
|
|
if (pConcealmentInfo->windowSequence == BLOCK_SHORT) {
|
|
/* short block handling */
|
|
numWindows = 8;
|
|
windowLen = samplesPerFrame >> 3;
|
|
srcGrpStart = numWindows - pConcealmentInfo->lastWinGrpLen;
|
|
}
|
|
}
|
|
|
|
attIdxStride =
|
|
fMax(1, (int)(numWindows / (pConcealmentInfo->lastWinGrpLen + 1)));
|
|
|
|
/* load last state */
|
|
attIdx = pConcealmentInfo->cntFadeFrames;
|
|
numWinGrpPerFac = pConcealmentInfo->attGrpOffset[mode];
|
|
srcWin = srcGrpStart + pConcealmentInfo->winGrpOffset[mode];
|
|
|
|
FDK_ASSERT((srcGrpStart * windowLen + windowLen) <= samplesPerFrame);
|
|
FDK_ASSERT((srcWin * windowLen + windowLen) <= 1024);
|
|
|
|
for (dstWin = 0; dstWin < numWindows; dstWin += 1) {
|
|
FIXP_CNCL *pCncl =
|
|
pConcealmentInfo->spectralCoefficient + (srcWin * windowLen);
|
|
FIXP_DBL *pOut = pSpectralCoefficient + (dstWin * windowLen);
|
|
|
|
if (mode == 1) {
|
|
/* mute if attIdx gets large enaugh */
|
|
if (attIdx > pConcealmentInfo->pConcealParams->numFadeOutFrames) {
|
|
FDKmemclear(pCncl, sizeof(FIXP_DBL) * windowLen);
|
|
}
|
|
|
|
/* restore frequency coefficients from buffer - attenuation is done later
|
|
*/
|
|
for (i = 0; i < windowLen; i++) {
|
|
pOut[i] = pCncl[i];
|
|
}
|
|
|
|
/* apply random change of sign for spectral coefficients */
|
|
CConcealment_ApplyRandomSign(pConcealmentInfo->iRandomPhase, pOut,
|
|
windowLen);
|
|
|
|
/* Increment random phase index to avoid repetition artifacts. */
|
|
pConcealmentInfo->iRandomPhase =
|
|
(pConcealmentInfo->iRandomPhase + 1) & (AAC_NF_NO_RANDOM_VAL - 1);
|
|
|
|
/* set old scale factors */
|
|
pSpecScale[dstWin * winIdxStride] =
|
|
pConcealmentInfo->specScale[srcWin * winIdxStride];
|
|
}
|
|
|
|
srcWin += 1;
|
|
|
|
if (srcWin >= numWindows) {
|
|
/* end of sequence -> rewind to first window of group */
|
|
srcWin = srcGrpStart;
|
|
numWinGrpPerFac += 1;
|
|
if (numWinGrpPerFac >= attIdxStride) {
|
|
numWinGrpPerFac = 0;
|
|
attIdx += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* store current state */
|
|
|
|
pConcealmentInfo->winGrpOffset[mode] = srcWin - srcGrpStart;
|
|
FDK_ASSERT((pConcealmentInfo->winGrpOffset[mode] >= 0) &&
|
|
(pConcealmentInfo->winGrpOffset[mode] < 8));
|
|
pConcealmentInfo->attGrpOffset[mode] = numWinGrpPerFac;
|
|
FDK_ASSERT((pConcealmentInfo->attGrpOffset[mode] >= 0) &&
|
|
(pConcealmentInfo->attGrpOffset[mode] < attIdxStride));
|
|
|
|
if (mode == 0) {
|
|
pConcealmentInfo->cntFadeFrames = attIdx;
|
|
}
|
|
|
|
appliedProcessing = 1;
|
|
|
|
return appliedProcessing;
|
|
}
|
|
|
|
/*!
|
|
\brief Do Time domain fading (TDFading) in concealment case
|
|
|
|
In case of concealment, this function takes care of the fading, after time
|
|
domain signal has been rendered by the respective signal rendering functions.
|
|
The fading out in case of ACELP decoding is not done by this function but by
|
|
the ACELP decoder for the first concealed frame if CONCEAL_CORE_IGNORANT_FADE is
|
|
not set.
|
|
|
|
TimeDomain fading never creates jumps in energy / discontinuities, it always
|
|
does a continuous fading. To achieve this, fading is always done from a starting
|
|
point to a target point, while the starting point is always determined to be the
|
|
last target point. By varying the target point of a fading, the fading slope can
|
|
be controlled.
|
|
|
|
This principle is applied to the fading within a frame and the fading from
|
|
frame to frame.
|
|
|
|
One frame is divided into 8 subframes to obtain 8 parts of fading slopes
|
|
within a frame, each maybe with its own gradient.
|
|
|
|
Workflow:
|
|
1.) Determine Fading behavior and end-of-frame target fading level, based on
|
|
concealmentState (determined by CConcealment_UpdateState()) and the core mode.
|
|
- By _DEFAULT_,
|
|
The target fading level is determined by fadeOutFactor[cntFadeFrames]
|
|
in case of fadeOut, or fadeInFactor[cntFadeFrames] in case of fadeIn.
|
|
--> fading type is FADE_TIMEDOMAIN in this case. Target fading level
|
|
is determined by fading index cntFadeFrames.
|
|
|
|
- If concealmentState is signalling a _MUTED SIGNAL_,
|
|
TDFading decays to 0 within 1/8th of a frame if numFadeOutFrames == 0.
|
|
--> fading type is FADE_TIMEDOMAIN_TOSPECTRALMUTE in this case.
|
|
|
|
- If concealmentState is signalling the _END OF MUTING_,
|
|
TDFading fades to target fading level within 1/8th of a frame if
|
|
numFadeInFrames == 0.
|
|
--> fading type is FADE_TIMEDOMAIN_FROMSPECTRALMUTE in this case.
|
|
Target fading level is determined by fading index cntFadeFrames.
|
|
|
|
#ifndef CONCEAL_CORE_IGNORANT_FADE
|
|
- In case of an _ACELP FADEOUT_,
|
|
TDFading leaves fading control to ACELP decoder for 1/2 frame.
|
|
--> fading type is FADE_ACELPDOMAIN in this case.
|
|
#endif
|
|
|
|
2.) Render fading levels within current frame and do the final fading:
|
|
Map Fading slopes to fading levels and apply to time domain signal.
|
|
|
|
|
|
*/
|
|
|
|
INT CConcealment_TDFading(
|
|
int len, CAacDecoderStaticChannelInfo **ppAacDecoderStaticChannelInfo,
|
|
FIXP_PCM *pcmdata, FIXP_PCM *pcmdata_1) {
|
|
/*
|
|
Do the fading in Time domain based on concealment states and core mode
|
|
*/
|
|
FIXP_DBL fadeStop, attMute = (FIXP_DBL)0;
|
|
int idx = 0, ii;
|
|
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo =
|
|
*ppAacDecoderStaticChannelInfo;
|
|
CConcealmentInfo *pConcealmentInfo =
|
|
&pAacDecoderStaticChannelInfo->concealmentInfo;
|
|
CConcealParams *pConcealParams = pConcealmentInfo->pConcealParams;
|
|
const CConcealmentState concealState = pConcealmentInfo->concealState;
|
|
TDfadingType fadingType;
|
|
FIXP_DBL fadingStations[9] = {0};
|
|
int fadingSteps[8] = {0};
|
|
const FIXP_DBL fadeStart =
|
|
pConcealmentInfo
|
|
->fade_old; /* start fading at last end-of-frame attenuation */
|
|
FIXP_SGL *fadeFactor = pConcealParams->fadeOutFactor;
|
|
const INT cntFadeFrames = pConcealmentInfo->cntFadeFrames;
|
|
int TDFadeOutStopBeforeMute = 1;
|
|
int TDFadeInStopBeforeFullLevel = 1;
|
|
|
|
/*
|
|
determine Fading behaviour (end-of-frame attenuation and fading type) (1.)
|
|
*/
|
|
|
|
switch (concealState) {
|
|
case ConcealState_Single:
|
|
case ConcealState_Mute:
|
|
case ConcealState_FadeOut:
|
|
idx = (pConcealParams->method == ConcealMethodNoise) ? cntFadeFrames - 1
|
|
: cntFadeFrames;
|
|
fadingType = FADE_TIMEDOMAIN;
|
|
|
|
if (concealState == ConcealState_Mute ||
|
|
(cntFadeFrames + TDFadeOutStopBeforeMute) >
|
|
pConcealmentInfo->pConcealParams->numFadeOutFrames) {
|
|
fadingType = FADE_TIMEDOMAIN_TOSPECTRALMUTE;
|
|
}
|
|
|
|
break;
|
|
case ConcealState_FadeIn:
|
|
idx = cntFadeFrames;
|
|
idx -= TDFadeInStopBeforeFullLevel;
|
|
FDK_FALLTHROUGH;
|
|
case ConcealState_Ok:
|
|
fadeFactor = pConcealParams->fadeInFactor;
|
|
idx = (concealState == ConcealState_Ok) ? -1 : idx;
|
|
fadingType = (pConcealmentInfo->concealState_old == ConcealState_Mute)
|
|
? FADE_TIMEDOMAIN_FROMSPECTRALMUTE
|
|
: FADE_TIMEDOMAIN;
|
|
break;
|
|
default:
|
|
FDK_ASSERT(0);
|
|
fadingType = FADE_TIMEDOMAIN_TOSPECTRALMUTE;
|
|
break;
|
|
}
|
|
|
|
/* determine Target end-of-frame fading level and fading slope */
|
|
switch (fadingType) {
|
|
case FADE_TIMEDOMAIN_FROMSPECTRALMUTE:
|
|
fadeStop =
|
|
(idx < 0) ? (FIXP_DBL)MAXVAL_DBL : FX_SGL2FX_DBL(fadeFactor[idx]);
|
|
if (pConcealmentInfo->pConcealParams->numFadeInFrames == 0) {
|
|
/* do step as fast as possible */
|
|
fadingSteps[0] = 1;
|
|
break;
|
|
}
|
|
CConcealment_TDFading_doLinearFadingSteps(&fadingSteps[0]);
|
|
break;
|
|
case FADE_TIMEDOMAIN:
|
|
fadeStop =
|
|
(idx < 0) ? (FIXP_DBL)MAXVAL_DBL : FX_SGL2FX_DBL(fadeFactor[idx]);
|
|
CConcealment_TDFading_doLinearFadingSteps(&fadingSteps[0]);
|
|
break;
|
|
case FADE_TIMEDOMAIN_TOSPECTRALMUTE:
|
|
fadeStop = attMute;
|
|
if (pConcealmentInfo->pConcealParams->numFadeOutFrames == 0) {
|
|
/* do step as fast as possible */
|
|
fadingSteps[0] = 1;
|
|
break;
|
|
}
|
|
CConcealment_TDFading_doLinearFadingSteps(&fadingSteps[0]);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
Render fading levels within current frame and do the final fading (2.)
|
|
*/
|
|
|
|
len >>= 3;
|
|
CConcealment_TDFadeFillFadingStations(fadingStations, fadingSteps, fadeStop,
|
|
fadeStart, fadingType);
|
|
|
|
if ((fadingStations[8] != (FIXP_DBL)MAXVAL_DBL) ||
|
|
(fadingStations[7] != (FIXP_DBL)MAXVAL_DBL) ||
|
|
(fadingStations[6] != (FIXP_DBL)MAXVAL_DBL) ||
|
|
(fadingStations[5] != (FIXP_DBL)MAXVAL_DBL) ||
|
|
(fadingStations[4] != (FIXP_DBL)MAXVAL_DBL) ||
|
|
(fadingStations[3] != (FIXP_DBL)MAXVAL_DBL) ||
|
|
(fadingStations[2] != (FIXP_DBL)MAXVAL_DBL) ||
|
|
(fadingStations[1] != (FIXP_DBL)MAXVAL_DBL) ||
|
|
(fadingStations[0] !=
|
|
(FIXP_DBL)MAXVAL_DBL)) /* if there's something to fade */
|
|
{
|
|
int start = 0;
|
|
for (ii = 0; ii < 8; ii++) {
|
|
CConcealment_TDFadePcmAtt(start, len, fadingStations[ii],
|
|
fadingStations[ii + 1], pcmdata);
|
|
start += len;
|
|
}
|
|
}
|
|
CConcealment_TDNoise_Apply(pConcealmentInfo, len, pcmdata);
|
|
|
|
/* Save end-of-frame attenuation and fading type */
|
|
pConcealmentInfo->lastFadingType = fadingType;
|
|
pConcealmentInfo->fade_old = fadeStop;
|
|
pConcealmentInfo->concealState_old = concealState;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* attenuate pcmdata in Time Domain Fading process */
|
|
static void CConcealment_TDFadePcmAtt(int start, int len, FIXP_DBL fadeStart,
|
|
FIXP_DBL fadeStop, FIXP_PCM *pcmdata) {
|
|
int i;
|
|
FIXP_DBL dStep;
|
|
FIXP_DBL dGain;
|
|
FIXP_DBL dGain_apply;
|
|
int bitshift = (DFRACT_BITS - SAMPLE_BITS);
|
|
|
|
/* set start energy */
|
|
dGain = fadeStart;
|
|
/* determine energy steps from sample to sample */
|
|
dStep = (FIXP_DBL)((int)((fadeStart >> 1) - (fadeStop >> 1)) / len) << 1;
|
|
|
|
for (i = start; i < (start + len); i++) {
|
|
dGain -= dStep;
|
|
/* prevent gain from getting negative due to possible fixpoint inaccuracies
|
|
*/
|
|
dGain_apply = fMax((FIXP_DBL)0, dGain);
|
|
/* finally, attenuate samples */
|
|
pcmdata[i] = (FIXP_PCM)((fMult(pcmdata[i], (dGain_apply))) >> bitshift);
|
|
}
|
|
}
|
|
|
|
/*
|
|
\brief Fill FadingStations
|
|
|
|
The fadingstations are the attenuation factors, being applied to its dedicated
|
|
portions of pcm data. They are calculated using the fadingsteps. One fadingstep
|
|
is the weighted contribution to the fading slope within its dedicated portion of
|
|
pcm data.
|
|
|
|
*Fadingsteps : 0 0 0 1 0 1 2 0
|
|
|
|
|<- 1 Frame pcm data ->|
|
|
fadeStart-->|__________ |
|
|
^ ^ ^ ^ \____ |
|
|
Attenuation : | | | | ^ ^\__ |
|
|
| | | | | | ^\ |
|
|
| | | | | | | \___|<-- fadeStop
|
|
| | | | | | | ^ ^
|
|
| | | | | | | | |
|
|
Fadingstations: [0][1][2][3][4][5][6][7][8]
|
|
|
|
(Fadingstations "[0]" is "[8] from previous frame", therefore its not meaningful
|
|
to be edited)
|
|
|
|
*/
|
|
static void CConcealment_TDFadeFillFadingStations(FIXP_DBL *fadingStations,
|
|
int *fadingSteps,
|
|
FIXP_DBL fadeStop,
|
|
FIXP_DBL fadeStart,
|
|
TDfadingType fadingType) {
|
|
int i;
|
|
INT fadingSteps_sum = 0;
|
|
INT fadeDiff;
|
|
|
|
fadingSteps_sum = fadingSteps[0] + fadingSteps[1] + fadingSteps[2] +
|
|
fadingSteps[3] + fadingSteps[4] + fadingSteps[5] +
|
|
fadingSteps[6] + fadingSteps[7];
|
|
fadeDiff = ((INT)(fadeStop - fadeStart) / fMax(fadingSteps_sum, (INT)1));
|
|
fadingStations[0] = fadeStart;
|
|
for (i = 1; i < 8; i++) {
|
|
fadingStations[i] =
|
|
fadingStations[i - 1] + (FIXP_DBL)(fadeDiff * fadingSteps[i - 1]);
|
|
}
|
|
fadingStations[8] = fadeStop;
|
|
}
|
|
|
|
static void CConcealment_TDFading_doLinearFadingSteps(int *fadingSteps) {
|
|
fadingSteps[0] = fadingSteps[1] = fadingSteps[2] = fadingSteps[3] =
|
|
fadingSteps[4] = fadingSteps[5] = fadingSteps[6] = fadingSteps[7] = 1;
|
|
}
|
|
|
|
/* end of TimeDomainFading functions */
|
|
|
|
/* derived from int UsacRandomSign() */
|
|
static int CConcealment_TDNoise_Random(ULONG *seed) {
|
|
*seed = (ULONG)(((UINT64)(*seed) * 69069) + 5);
|
|
return (int)(*seed);
|
|
}
|
|
|
|
static void CConcealment_TDNoise_Apply(CConcealmentInfo *const pConcealmentInfo,
|
|
const int len, FIXP_PCM *const pcmdata) {
|
|
FIXP_PCM *states = pConcealmentInfo->TDNoiseStates;
|
|
FIXP_PCM noiseVal;
|
|
FIXP_DBL noiseValLong;
|
|
FIXP_SGL *coef = pConcealmentInfo->TDNoiseCoef;
|
|
FIXP_DBL TDNoiseAtt;
|
|
ULONG seed = pConcealmentInfo->TDNoiseSeed =
|
|
(ULONG)CConcealment_TDNoise_Random(&pConcealmentInfo->TDNoiseSeed) + 1;
|
|
|
|
TDNoiseAtt = pConcealmentInfo->pConcealParams->comfortNoiseLevel;
|
|
|
|
int ii;
|
|
|
|
if ((pConcealmentInfo->concealState != ConcealState_Ok ||
|
|
pConcealmentInfo->concealState_old != ConcealState_Ok) &&
|
|
TDNoiseAtt != (FIXP_DBL)0) {
|
|
for (ii = 0; ii < (len << 3); ii++) {
|
|
/* create filtered noise */
|
|
states[2] = states[1];
|
|
states[1] = states[0];
|
|
states[0] = ((FIXP_PCM)CConcealment_TDNoise_Random(&seed));
|
|
noiseValLong = fMult(states[0], coef[0]) + fMult(states[1], coef[1]) +
|
|
fMult(states[2], coef[2]);
|
|
noiseVal = FX_DBL2FX_PCM(fMult(noiseValLong, TDNoiseAtt));
|
|
|
|
/* add filtered noise - check for clipping, before */
|
|
if (noiseVal > (FIXP_PCM)0 &&
|
|
pcmdata[ii] > (FIXP_PCM)MAXVAL_FIXP_PCM - noiseVal) {
|
|
noiseVal = noiseVal * (FIXP_PCM)-1;
|
|
} else if (noiseVal < (FIXP_PCM)0 &&
|
|
pcmdata[ii] < (FIXP_PCM)MINVAL_FIXP_PCM - noiseVal) {
|
|
noiseVal = noiseVal * (FIXP_PCM)-1;
|
|
}
|
|
|
|
pcmdata[ii] += noiseVal;
|
|
}
|
|
}
|
|
}
|