aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libAACdec/src/conceal.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
commit0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch)
treed07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libAACdec/src/conceal.cpp
parentefe406d9724f959c8bc2a31802559ca6d41fd897 (diff)
downloadODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since that follows the android source releases, there is no place for a custom DAB+ patch there. So instead of having to maintain a patched fdk-aac that has to have the same .so version as the distribution package on which it is installed, we prefer having a separate fdk-aac-dab library to avoid collision. At that point, there's no reason to keep fdk-aac in a separate repository, as odr-audioenc is the only tool that needs DAB+ encoding support. Including it here simplifies installation, and makes it consistent with toolame-dab, also shipped in this repository. DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop, welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libAACdec/src/conceal.cpp')
-rw-r--r--fdk-aac/libAACdec/src/conceal.cpp2095
1 files changed, 2095 insertions, 0 deletions
diff --git a/fdk-aac/libAACdec/src/conceal.cpp b/fdk-aac/libAACdec/src/conceal.cpp
new file mode 100644
index 0000000..5895cb8
--- /dev/null
+++ b/fdk-aac/libAACdec/src/conceal.cpp
@@ -0,0 +1,2095 @@
+/* -----------------------------------------------------------------------------
+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;
+ }
+ }
+}