summaryrefslogtreecommitdiffstats
path: root/libAACdec/src/conceal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libAACdec/src/conceal.cpp')
-rw-r--r--libAACdec/src/conceal.cpp1825
1 files changed, 1825 insertions, 0 deletions
diff --git a/libAACdec/src/conceal.cpp b/libAACdec/src/conceal.cpp
new file mode 100644
index 0000000..dc5d99f
--- /dev/null
+++ b/libAACdec/src/conceal.cpp
@@ -0,0 +1,1825 @@
+
+/* -----------------------------------------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© Copyright 1995 - 2012 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
+----------------------------------------------------------------------------------------------------------- */
+
+/***************************** MPEG-4 AAC Decoder **************************
+
+ 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"
+
+#include "FDK_tools_rom.h"
+
+#define CONCEAL_DFLT_COMF_NOISE_LEVEL ( 46 ) /* ~= -70 dB */
+
+
+/* default settings */
+#define CONCEAL_DFLT_FADEOUT_FRAMES ( 5 )
+#define CONCEAL_DFLT_FADEIN_FRAMES ( 5 )
+#define CONCEAL_DFLT_MUTE_RELEASE_FRAMES ( 3 )
+
+#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
+ );
+
+
+
+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
+ );
+
+static void
+ CConcealment_ApplyRandomSign (
+ int iRandomPhase,
+ FIXP_DBL *spec,
+ int samplesPerFrame
+ );
+
+
+static int CConcealment_GetWinSeq(int prevWinSeq)
+{
+ int newWinSeq = OnlyLongSequence;
+
+ /* Try to have only long blocks */
+ if ( prevWinSeq == LongStartSequence
+ || prevWinSeq == EightShortSequence )
+ {
+ newWinSeq = LongStopSequence;
+ }
+
+ return (newWinSeq);
+}
+
+
+/*!
+ \brief Init common concealment information data
+
+ \pConcealCommonData Pointer to the concealment common data structure.
+
+ \return none
+*/
+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 = 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.
+
+ \pConcealCommonData Pointer to common concealment data (for all channels)
+
+ \return Concealment method.
+*/
+CConcealmentMethod
+ CConcealment_GetMethod( CConcealParams *pConcealCommonData )
+{
+ CConcealmentMethod method = ConcealMethodNone;
+
+ if (pConcealCommonData != NULL) {
+ method = pConcealCommonData->method;
+ }
+
+ return (method);
+}
+
+
+/*!
+ \brief Init concealment information for each channel
+
+ The function initializes the concealment information. Two methods can be chosen:
+ 0 = interpolation method (adds delay)
+ 1 = noise substitution (no delay, low complexity)
+
+ \return none
+*/
+void
+ CConcealment_InitChannelData (
+ CConcealmentInfo *pConcealChannelInfo,
+ CConcealParams *pConcealCommonData,
+ int samplesPerFrame )
+{
+ int i;
+
+ pConcealChannelInfo->pConcealParams = pConcealCommonData;
+
+ FDKmemclear(pConcealChannelInfo->spectralCoefficient, 1024 * sizeof(FIXP_CNCL));
+
+ for (i = 0; i < 8; i++) {
+ pConcealChannelInfo->specScale[i] = 0;
+ }
+
+ pConcealChannelInfo->iRandomPhase = 0;
+
+ pConcealChannelInfo->windowSequence = 0;
+ pConcealChannelInfo->windowShape = 0;
+
+ pConcealChannelInfo->prevFrameOk[0] = 1;
+ pConcealChannelInfo->prevFrameOk[1] = 1;
+
+ pConcealChannelInfo->cntFadeFrames = 0;
+ pConcealChannelInfo->cntValidFrames = 0;
+
+ pConcealChannelInfo->concealState = ConcealState_Ok;
+
+}
+
+
+/*!
+ \brief Set error concealment parameters
+
+ \concealParams
+ \method
+ \fadeOutSlope
+ \fadeInSlope
+ \muteRelease
+ \comfNoiseLevel
+
+ \return none
+*/
+AAC_DECODER_ERROR
+ CConcealment_SetParams (
+ CConcealParams *concealParams,
+ int method,
+ int fadeOutSlope,
+ int fadeInSlope,
+ int muteRelease,
+ int 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 >= 1) )
+ {
+ 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 != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) {
+ if ( (comfNoiseLevel < 0)
+ || (comfNoiseLevel > 127) ) {
+ return AAC_DEC_SET_PARAM_FAIL;
+ }
+ if (concealParams == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ } else {
+ concealParams->comfortNoiseLevel = comfNoiseLevel;
+ }
+ }
+
+ return (AAC_DEC_OK);
+}
+
+
+/*!
+ \brief Set fade-out/in attenuation factor vectors
+
+ \concealParams
+ \fadeOutAttenuationVector
+ \fadeInAttenuationVector
+
+ \return 0 if OK all other values indicate errors
+*/
+AAC_DECODER_ERROR
+ CConcealment_SetAttenuation (
+ CConcealParams *concealParams,
+ SHORT *fadeOutAttenuationVector,
+ 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.
+
+ \pConcealChannelInfo
+
+ \return Concealment state.
+*/
+CConcealmentState
+ CConcealment_GetState (
+ CConcealmentInfo *pConcealChannelInfo
+ )
+{
+ CConcealmentState state = ConcealState_Ok;
+
+ if (pConcealChannelInfo != NULL) {
+ state = pConcealChannelInfo->concealState;
+ }
+
+ return (state);
+}
+
+
+static void CConcealment_fakePnsData (
+ CPnsData *pPnsData,
+ CIcsInfo *pIcsInfo,
+ const SamplingRateInfo *pSamplingRateInfo,
+ SHORT *pSpecScale,
+ SHORT *pScaleFactor,
+ const int level )
+{
+ CPnsInterChannelData *pInterChannelData = pPnsData->pPnsInterChannelData;
+
+ int pnsBand, band, group, win;
+ //int delta = 0;
+ int windowsPerFrame = GetWindowsPerFrame(pIcsInfo);
+ int refLevel = (windowsPerFrame > 1) ? 82 : 91;
+
+ FDK_ASSERT(level >= 0 && level <= 127);
+
+ for (win = 0; win < windowsPerFrame; win++) {
+ pSpecScale[win] = 31;
+ }
+
+ /* fake ICS info if necessary */
+ if (!IsValid(pIcsInfo)) {
+ pIcsInfo->WindowGroups = 1;
+ if (IsLongBlock(pIcsInfo)) {
+ pIcsInfo->TotalSfBands = pSamplingRateInfo->NumberOfScaleFactorBands_Long;
+ pIcsInfo->WindowGroupLength[0] = 1;
+ }
+ else {
+ pIcsInfo->TotalSfBands = pSamplingRateInfo->NumberOfScaleFactorBands_Short;
+ pIcsInfo->WindowGroupLength[0] = 8;
+ }
+ pIcsInfo->MaxSfBands = pIcsInfo->TotalSfBands;
+ }
+
+ /* global activate PNS */
+ pPnsData->PnsActive = 1;
+ /* set energy level */
+ pPnsData->CurrentEnergy = fixMax( 0, refLevel - level );
+
+ /*
+ value: | Avg. RMS power | Avg. RMS power |
+ | specScale = 22 | specScale = 31 |
+ -------+----------------+----------------+
+ 5 | | -99.0 dB
+ 15 | | -90.0 dB
+ 25 | | -89.7 dB
+ 35 | | -85.3 dB
+ ... | ... | ...
+ 45 | -69.9 dB | -70.0 dB
+ 50 | -62.2 dB |
+ 55 | -55.6 dB | -54.6 dB
+ 60 | -47.0 dB |
+ 65 | -39.5 dB | -39.5 dB
+ 70 | -31.9 dB |
+ 75 | -24.4 dB | -24.4 dB
+ 80 | -16.9 dB |
+ 85 | -9.4 dB (c) | -9.4 dB
+ 90 | -3.9 dB (c) |
+ 95 | | -2.1 dB
+ 100 | | -1.6 dB
+ 105 | | -1.4 dB
+ */
+
+ for (group=0; group < GetWindowGroups(pIcsInfo); group++)
+ {
+ for (band=0; band < GetScaleFactorBandsTransmitted(pIcsInfo); band++)
+ {
+ pnsBand = group * 16 + band;
+
+ if (pnsBand >= NO_OFBANDS) {
+ return;
+ }
+ //pPnsData->CurrentEnergy += delta ;
+ pScaleFactor[pnsBand] = pPnsData->CurrentEnergy;
+ pInterChannelData->correlated[pnsBand] = 0;
+ pPnsData->pnsUsed[pnsBand] = 1;
+ }
+ }
+}
+
+
+/*!
+ \brief Store data for concealment techniques applied later
+
+ Interface function to store data for different concealment strategies
+
+ \return none
+ */
+void
+ CConcealment_Store (
+ CConcealmentInfo *hConcealmentInfo,
+ CAacDecoderChannelInfo *pAacDecoderChannelInfo,
+ CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo )
+{
+ if ( !(pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_LPD
+ ) )
+ {
+ FIXP_DBL *pSpectralCoefficient = SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient);
+ SHORT *pSpecScale = pAacDecoderChannelInfo->specScale;
+ CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo;
+
+ SHORT tSpecScale[8];
+ UCHAR tWindowShape, 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 (CConcealment_GetDelay(hConcealmentInfo->pConcealParams) == 0)
+ {
+ /* 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
+ {
+ FIXP_CNCL *RESTRICT pCncl = &hConcealmentInfo->spectralCoefficient[1024-1];
+ FIXP_DBL *RESTRICT pSpec = &pSpectralCoefficient[1024-1];
+ int i;
+
+ /* swap spectral data */
+ for (i = 1024; i != 0; i--) {
+ FIXP_DBL tSpec = *pSpec;
+ *pSpec-- = FX_CNCL2FX_DBL(*pCncl);
+ *pCncl-- = FX_DBL2FX_CNCL( tSpec);
+ }
+
+ /* complete swapping of window infos */
+ pIcsInfo->WindowSequence = tWindowSequence;
+ pIcsInfo->WindowShape = tWindowShape;
+
+ /* complete swapping of scale factors */
+ FDKmemcpy(pSpecScale, tSpecScale, 8*sizeof(SHORT));
+ }
+ }
+
+}
+
+
+/*!
+ \brief Apply concealment
+
+ Interface function to different concealment strategies
+
+ \return none
+ */
+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;
+
+ if ( (frameOk == 0)
+ && (pAacDecoderChannelInfo->renderMode != (AACDEC_RENDER_MODE)hConcealmentInfo->lastRenderMode) ) {
+ /* restore the last render mode to stay in the same domain which allows to do a proper concealment */
+ pAacDecoderChannelInfo->renderMode = (AACDEC_RENDER_MODE)hConcealmentInfo->lastRenderMode;
+ } else {
+ /* otherwise store the current mode */
+ hConcealmentInfo->lastRenderMode = (SCHAR)pAacDecoderChannelInfo->renderMode;
+ }
+
+ if ( frameOk )
+ {
+ /* 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;
+ }
+
+ /* hand current frame status to the state machine */
+ CConcealment_UpdateState( hConcealmentInfo,
+ frameOk );
+
+ if ( !frameOk )
+ {
+ /* Create data for signal rendering according to the selected concealment method and decoder operating mode. */
+
+
+ if ( !(pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_LPD
+ )
+ )
+ {
+ switch (hConcealmentInfo->pConcealParams->method)
+ {
+ default:
+ case ConcealMethodMute:
+ /* 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 */
+ 0);
+ break;
+
+ }
+ }
+ }
+ /* update history */
+ hConcealmentInfo->prevFrameOk[0] = hConcealmentInfo->prevFrameOk[1];
+ hConcealmentInfo->prevFrameOk[1] = frameOk;
+
+ return 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.
+
+\return none
+ */
+static int
+ CConcealment_ApplyNoise (CConcealmentInfo *pConcealmentInfo,
+ CAacDecoderChannelInfo *pAacDecoderChannelInfo,
+ CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
+ const SamplingRateInfo *pSamplingRateInfo,
+ const int samplesPerFrame,
+ const UINT flags)
+{
+ CConcealParams *pConcealCommonData = pConcealmentInfo->pConcealParams;
+
+ FIXP_DBL *pSpectralCoefficient = SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient);
+ SHORT *pSpecScale = pAacDecoderChannelInfo->specScale;
+ CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo;
+
+ int appliedProcessing = 0;
+
+ FDK_ASSERT((samplesPerFrame>=480) && (samplesPerFrame<=1024));
+ FDK_ASSERT((samplesPerFrame&0x1F) == 0);
+
+ switch (pConcealmentInfo->concealState)
+ {
+ case ConcealState_Ok:
+ /* Nothing to do here! */
+ break;
+
+ case ConcealState_Single:
+ case ConcealState_FadeOut:
+ {
+ /* restore frequency coefficients from buffer with a specific muting */
+ FIXP_SGL fac;
+ int win, numWindows = 1;
+ int windowLen = samplesPerFrame;
+ int tFadeFrames, lastWindow = 0;
+ int win_idx_stride = 1;
+
+ FDK_ASSERT(pConcealmentInfo != NULL);
+ FDK_ASSERT(pConcealmentInfo->cntFadeFrames >= 0);
+ FDK_ASSERT(pConcealmentInfo->cntFadeFrames < CONCEAL_MAX_NUM_FADE_FACTORS);
+ FDK_ASSERT(pConcealmentInfo->cntFadeFrames <= pConcealCommonData->numFadeOutFrames);
+
+ /* get attenuation factor */
+ tFadeFrames = pConcealmentInfo->cntFadeFrames;
+ fac = pConcealCommonData->fadeOutFactor[tFadeFrames];
+
+ /* set old window parameters */
+ {
+ pIcsInfo->WindowShape = pConcealmentInfo->windowShape;
+ pIcsInfo->WindowSequence = pConcealmentInfo->windowSequence;
+
+ if (pConcealmentInfo->windowSequence == 2) {
+ /* short block handling */
+ numWindows = 8;
+ windowLen = samplesPerFrame >> 3;
+ lastWindow = numWindows - pConcealmentInfo->lastWinGrpLen;
+ }
+ }
+
+ for (win = 0; win < numWindows; win++) {
+ FIXP_CNCL *pCncl = pConcealmentInfo->spectralCoefficient + (lastWindow * windowLen);
+ FIXP_DBL *pOut = pSpectralCoefficient + (win * windowLen);
+ int i;
+
+ FDK_ASSERT((lastWindow * windowLen + windowLen) <= samplesPerFrame);
+
+ /* restore frequency coefficients from buffer with a specific attenuation */
+ for (i = 0; i < windowLen; i++) {
+ pOut[i] = fMult(pCncl[i], fac);
+ }
+
+ /* 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[win*win_idx_stride] = pConcealmentInfo->specScale[win_idx_stride*lastWindow++];
+
+ if ( (lastWindow >= numWindows)
+ && (numWindows > 1) )
+ {
+ /* end of sequence -> rewind */
+ lastWindow = numWindows - pConcealmentInfo->lastWinGrpLen;
+ /* update the attenuation factor to get a faster fade-out */
+ tFadeFrames += 1;
+ if (tFadeFrames < pConcealCommonData->numFadeOutFrames) {
+ fac = pConcealCommonData->fadeOutFactor[tFadeFrames];
+ } else {
+ fac = (FIXP_SGL)0;
+ }
+ }
+ }
+
+ /* store temp vars */
+ pConcealmentInfo->cntFadeFrames = tFadeFrames;
+ 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));
+
+ if ( !(flags & (AC_USAC|AC_RSVD50))
+ && pConcealCommonData->comfortNoiseLevel >= 0
+ && pConcealCommonData->comfortNoiseLevel <= 61 /* -90dB */)
+ {
+ /* insert comfort noise using PNS */
+ CConcealment_fakePnsData (
+ &pAacDecoderChannelInfo->data.aac.PnsData,
+ pIcsInfo,
+ pSamplingRateInfo,
+ pAacDecoderChannelInfo->pDynData->aSfbScale,
+ pAacDecoderChannelInfo->pDynData->aScaleFactor,
+ pConcealCommonData->comfortNoiseLevel
+ );
+
+ CPns_Apply (
+ &pAacDecoderChannelInfo->data.aac.PnsData,
+ pIcsInfo,
+ pAacDecoderChannelInfo->pSpectralCoefficient,
+ pAacDecoderChannelInfo->specScale,
+ pAacDecoderChannelInfo->pDynData->aScaleFactor,
+ pSamplingRateInfo,
+ pAacDecoderChannelInfo->granuleLength,
+ 0 /* always apply to first channel */
+ );
+ }
+ 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);
+
+ /* attenuate signal to get a smooth fade-in */
+ FIXP_DBL *RESTRICT pOut = &pSpectralCoefficient[samplesPerFrame-1];
+ FIXP_SGL fac = pConcealCommonData->fadeInFactor[pConcealmentInfo->cntFadeFrames];
+ int i;
+
+ for (i = samplesPerFrame; i != 0; i--) {
+ *pOut = fMult(*pOut, fac);
+ pOut--;
+ }
+ 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.
+
+ \return none
+*/
+static int
+ CConcealment_ApplyInter (
+ CConcealmentInfo *pConcealmentInfo,
+ CAacDecoderChannelInfo *pAacDecoderChannelInfo,
+ const SamplingRateInfo *pSamplingRateInfo,
+ const int samplesPerFrame,
+ const int improveTonal,
+ const int frameOk )
+{
+ CConcealParams *pConcealCommonData = pConcealmentInfo->pConcealParams;
+
+ 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)
+ {
+ /* 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]) {
+
+ /* 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])
+ {
+ appliedProcessing = 1;
+
+
+ /* Interpolate both frames in order to generate the current output frame (f_(n-1)). */
+ if (pIcsInfo->WindowSequence == EightShortSequence) {
+ /* f_(n-2) == EightShortSequence */
+ /* short--??????--short, short--??????--long interpolation */
+ /* short--short---short, short---long---long interpolation */
+
+ int wnd;
+
+ if (pConcealmentInfo->windowSequence == EightShortSequence) { /* f_n == EightShortSequence */
+ /* short--short---short interpolation */
+
+ int scaleFactorBandsTotal = pSamplingRateInfo->NumberOfScaleFactorBands_Short;
+ const SHORT *pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Short;
+ pIcsInfo->WindowShape = 1;
+ pIcsInfo->WindowSequence = EightShortSequence;
+
+ for (wnd = 0; wnd < 8; wnd++)
+ {
+ CConcealment_CalcBandEnergy(
+ &pSpectralCoefficient[wnd * (samplesPerFrame / 8)], /* spec_(n-2) */
+ pSamplingRateInfo,
+ EightShortSequence,
+ CConcealment_NoExpand,
+ sfbEnergyPrev);
+
+ CConcealment_CalcBandEnergy(
+ &pConcealmentInfo->spectralCoefficient[wnd * (samplesPerFrame / 8)], /* spec_n */
+ pSamplingRateInfo,
+ EightShortSequence,
+ 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 != EightShortSequence */
+ /* 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,
+ EightShortSequence,
+ CConcealment_Expand,
+ sfbEnergyAct);
+
+ CConcealment_CalcBandEnergy(pConcealmentInfo->spectralCoefficient, /* spec_n */
+ pSamplingRateInfo,
+ OnlyLongSequence,
+ CConcealment_NoExpand,
+ sfbEnergyPrev);
+
+ pIcsInfo->WindowShape = 0;
+ pIcsInfo->WindowSequence = LongStopSequence;
+
+ 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,
+ OnlyLongSequence,
+ CConcealment_NoExpand,
+ sfbEnergyPrev);
+
+ if (pConcealmentInfo->windowSequence == EightShortSequence) { /* f_n == EightShortSequence */
+ /* long---long---short interpolation */
+
+ pIcsInfo->WindowShape = 1;
+ pIcsInfo->WindowSequence = LongStartSequence;
+
+ 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,
+ EightShortSequence,
+ CConcealment_Expand, /* !!! */
+ sfbEnergyAct);
+ } else {
+ /* long---long---long interpolation */
+
+ pIcsInfo->WindowShape = 0;
+ pIcsInfo->WindowSequence = OnlyLongSequence;
+
+ CConcealment_CalcBandEnergy(pConcealmentInfo->spectralCoefficient, /* spec_n */
+ pSamplingRateInfo,
+ OnlyLongSequence,
+ 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);
+
+ /* restore frequency coefficients from buffer with a specific muting */
+ FIXP_DBL *RESTRICT pOut = &pSpectralCoefficient[samplesPerFrame-1];
+ FIXP_SGL fac = pConcealCommonData->fadeOutFactor[pConcealmentInfo->cntFadeFrames];
+
+ for (i = samplesPerFrame; i != 0; i--) {
+ *pOut = fMult(*pOut, fac);
+ pOut--;
+ }
+ 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);
+
+ /* attenuate signal to get a smooth fade-in */
+ FIXP_DBL *RESTRICT pOut = &pSpectralCoefficient[samplesPerFrame-1];
+ FIXP_SGL fac = pConcealCommonData->fadeInFactor[pConcealmentInfo->cntFadeFrames];
+
+ for (i = samplesPerFrame; i != 0; i--) {
+ *pOut = fMult(*pOut, fac);
+ pOut--;
+ }
+ appliedProcessing = 1;
+ }
+ break;
+
+ case ConcealState_Mute:
+ {
+ int fac = pConcealCommonData->comfortNoiseLevel;
+
+ /* 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));
+
+ if (fac >= 0 && fac <= 61) {
+ /* insert comfort noise using PNS */
+ CConcealment_fakePnsData (
+ &pAacDecoderChannelInfo->data.aac.PnsData,
+ pIcsInfo,
+ pSamplingRateInfo,
+ pAacDecoderChannelInfo->specScale,
+ pAacDecoderChannelInfo->pDynData->aScaleFactor,
+ fac
+ );
+
+ CPns_Apply (
+ &pAacDecoderChannelInfo->data.aac.PnsData,
+ pIcsInfo,
+ pAacDecoderChannelInfo->pSpectralCoefficient,
+ pAacDecoderChannelInfo->specScale,
+ pAacDecoderChannelInfo->pDynData->aScaleFactor,
+ pSamplingRateInfo,
+ pAacDecoderChannelInfo->granuleLength,
+ 0 /* always apply to first channel */
+ );
+ }
+ 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.
+
+ \return none
+*/
+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 OnlyLongSequence:
+ case LongStartSequence:
+ case LongStopSequence:
+
+ 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 EightShortSequence:
+
+ 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.
+
+ \return none
+*/
+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);
+}
+
+
+
+
+static INT findEquiFadeFrame (
+ CConcealParams *pConcealCommonData,
+ INT actFadeIndex,
+ int direction )
+{
+ FIXP_SGL *pFactor;
+ FIXP_SGL referenceVal;
+ FIXP_SGL minDiff = (FIXP_SGL)MAXVAL_SGL;
+
+ INT numFrames = 0;
+ INT nextFadeIndex = 0;
+
+ int i;
+
+ /* init depending on direction */
+ if (direction == 0) { /* FADE-OUT => FADE-IN */
+ numFrames = pConcealCommonData->numFadeInFrames;
+ referenceVal = pConcealCommonData->fadeOutFactor[actFadeIndex] >> 1;
+ pFactor = pConcealCommonData->fadeInFactor;
+ }
+ else { /* FADE-IN => FADE-OUT */
+ numFrames = pConcealCommonData->numFadeOutFrames;
+ referenceVal = pConcealCommonData->fadeInFactor[actFadeIndex] >> 1;
+ pFactor = pConcealCommonData->fadeOutFactor;
+ }
+
+ /* search for minimum difference */
+ for (i = 0; i < numFrames; 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 (((pFactor[nextFadeIndex]>>1) <= referenceVal) && (nextFadeIndex > 0)) {
+ nextFadeIndex -= 1;
+ }
+ }
+ else { /* FADE-IN => FADE-OUT */
+ if (((pFactor[nextFadeIndex]>>1) >= referenceVal) && (nextFadeIndex < numFrames-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.
+
+ \return none
+*/
+static void
+ CConcealment_UpdateState (
+ CConcealmentInfo *pConcealmentInfo,
+ int frameOk )
+{
+ 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) {
+ /* change to state SINGLE-FRAME-LOSS */
+ pConcealmentInfo->concealState = ConcealState_Single;
+ pConcealmentInfo->cntFadeFrames = 0;
+ pConcealmentInfo->cntValidFrames = 0;
+ }
+ break;
+
+ case ConcealState_Single: /* Just a pre-stage before fade-out begins. Stay here only one frame! */
+ pConcealmentInfo->cntFadeFrames += 1;
+ if (frameOk) {
+ if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) {
+ /* 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;
+ } else {
+ /* change to state FADE-OUT */
+ pConcealmentInfo->concealState = ConcealState_FadeOut;
+ }
+ }
+ break;
+
+ case ConcealState_FadeOut:
+ pConcealmentInfo->cntFadeFrames += 1; /* used to address the fade-out factors */
+ if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) {
+ /* change to state FADE-IN */
+ pConcealmentInfo->concealState = ConcealState_FadeIn;
+ pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData,
+ pConcealmentInfo->cntFadeFrames-1,
+ 0 /* FadeOut -> FadeIn */);
+ } else {
+ if (pConcealmentInfo->cntFadeFrames >= pConcealCommonData->numFadeOutFrames) {
+ /* change to state MUTE */
+ pConcealmentInfo->concealState = ConcealState_Mute;
+ }
+ }
+ break;
+
+ case ConcealState_Mute:
+ if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) {
+ /* change to state FADE-IN */
+ pConcealmentInfo->concealState = ConcealState_FadeIn;
+ pConcealmentInfo->cntFadeFrames = pConcealCommonData->numFadeInFrames - 1;
+ }
+ break;
+
+ case ConcealState_FadeIn:
+ pConcealmentInfo->cntFadeFrames -= 1; /* used to address the fade-in factors */
+ if (frameOk) {
+ if (pConcealmentInfo->cntFadeFrames < 0) {
+ /* change to state OK */
+ pConcealmentInfo->concealState = ConcealState_Ok;
+ }
+ } else {
+ /* change to state FADE-OUT */
+ pConcealmentInfo->concealState = ConcealState_FadeOut;
+ pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData,
+ pConcealmentInfo->cntFadeFrames+1,
+ 1 /* FadeIn -> FadeOut */);
+ }
+ 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))) {
+ /* Fade out only if the energy interpolation algorithm can not be applied! */
+ pConcealmentInfo->concealState = ConcealState_FadeOut;
+ 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) {
+ /* change to state FADE-IN */
+ pConcealmentInfo->concealState = ConcealState_FadeIn;
+ pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData,
+ pConcealmentInfo->cntFadeFrames-1,
+ 0 /* FadeOut -> FadeIn */);
+ } else {
+ if (pConcealmentInfo->cntFadeFrames >= pConcealCommonData->numFadeOutFrames) {
+ /* change to state MUTE */
+ pConcealmentInfo->concealState = ConcealState_Mute;
+ }
+ }
+ break;
+
+ case ConcealState_Mute:
+ if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) {
+ /* change to state FADE-IN */
+ pConcealmentInfo->concealState = ConcealState_FadeIn;
+ pConcealmentInfo->cntFadeFrames = pConcealCommonData->numFadeInFrames - 1;
+ }
+ 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 {
+ /* change to state FADE-OUT */
+ pConcealmentInfo->concealState = ConcealState_FadeOut;
+ pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData,
+ pConcealmentInfo->cntFadeFrames+1,
+ 1 /* FadeIn -> FadeOut */);
+ }
+ 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.
+
+\return none
+ */
+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 = randomSign[randomPhase>>4];
+ packedSign >>= (randomPhase&0xf);
+
+ for (i = 0; i < samplesPerFrame ; i++) {
+ if ((randomPhase & 0xf) == 0) {
+ packedSign = 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 factor used for fading that belongs to the current internal state.
+
+ \return Fade factor
+ */
+FIXP_DBL
+ CConcealment_GetFadeFactor (
+ CConcealmentInfo *hConcealmentInfo,
+ const int fPreviousFactor
+ )
+{
+ FIXP_DBL fac = (FIXP_DBL)0;
+
+ CConcealParams *pConcealCommonData = hConcealmentInfo->pConcealParams;
+
+ if (hConcealmentInfo->pConcealParams->method > ConcealMethodMute) {
+ switch (hConcealmentInfo->concealState) {
+ default:
+ case ConcealState_Mute:
+ /* Nothing to do here */
+ break;
+ case ConcealState_Ok:
+ fac = (FIXP_DBL)MAXVAL_DBL;
+ break;
+ case ConcealState_Single:
+ case ConcealState_FadeOut:
+ {
+ int idx = hConcealmentInfo->cntFadeFrames - ((fPreviousFactor != 0) ? 1 : 0);
+ fac = (idx < 0) ? (FIXP_DBL)MAXVAL_DBL : FX_SGL2FX_DBL(pConcealCommonData->fadeOutFactor[idx]);
+ }
+ break;
+ case ConcealState_FadeIn:
+ {
+ int idx = hConcealmentInfo->cntFadeFrames + ((fPreviousFactor != 0) ? 1 : 0);
+ fac = (idx >= hConcealmentInfo->pConcealParams->numFadeInFrames) ? (FIXP_DBL)0 : FX_SGL2FX_DBL(pConcealCommonData->fadeInFactor[idx]);
+ }
+ break;
+ }
+ }
+
+ return (fac);
+}
+
+
+/*!
+ \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;
+}
+