
/* -----------------------------------------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android

© Copyright  1995 - 2015 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
  All rights reserved.

 1.    INTRODUCTION
The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
This FDK AAC Codec software is intended to be used on a wide variety of Android devices.

AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
of the MPEG specifications.

Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
individually for the purpose of encoding or decoding bit streams in products that are compliant with
the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
software may already be covered under those patent licenses when it is used for those licensed purposes only.

Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
applications information and documentation.

2.    COPYRIGHT LICENSE

Redistribution and use in source and binary forms, with or without modification, are permitted without
payment of copyright license fees provided that you satisfy the following conditions:

You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
your modifications thereto in source code form.

You must retain the complete text of this software license in the documentation and/or other materials
provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
modifications thereto to recipients of copies in binary form.

The name of Fraunhofer may not be used to endorse or promote products derived from this library without
prior written permission.

You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
software or your modifications thereto.

Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
and the date of any change. For modified versions of the FDK AAC Codec, the term
"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."

3.    NO PATENT LICENSE

NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
respect to this software.

You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
by appropriate patent licenses.

4.    DISCLAIMER

This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
or business interruption, however caused and on any theory of liability, whether in contract, strict
liability, or tort (including negligence), arising in any way out of the use of this software, even if
advised of the possibility of such damage.

5.    CONTACT INFORMATION

Fraunhofer Institute for Integrated Circuits IIS
Attention: Audio and Multimedia Departments - FDK AAC LL
Am Wolfsmantel 33
91058 Erlangen, Germany

www.iis.fraunhofer.de/amm
amm-info@iis.fraunhofer.de
----------------------------------------------------------------------------------------------------------- */

/*****************************  MPEG-4 AAC Decoder  **************************

   Author(s):   Josef Hoepfl
   Description: long/short-block decoding

******************************************************************************/

#include "block.h"

#include "aac_rom.h"
#include "FDK_bitstream.h"
#include "FDK_tools_rom.h"






#if defined(__arm__)
#include "arm/block_arm.cpp"
#endif

/*!
  \brief Read escape sequence of codeword

  The function reads the escape sequence from the bitstream,
  if the absolute value of the quantized coefficient has the
  value 16.

  \return  quantized coefficient
*/
LONG CBlock_GetEscape(HANDLE_FDK_BITSTREAM bs, /*!< pointer to bitstream */
                     const LONG q)        /*!< quantized coefficient */
{
  LONG i, off, neg ;

  if (q < 0)
  {
    if (q != -16) return q;
    neg = 1;
  }
  else
  {
    if (q != +16) return q;
    neg = 0;
  }

  for (i=4; ; i++)
  {
    if (FDKreadBits(bs,1) == 0)
      break;
  }

  if (i > 16)
  {
    if (i - 16 > CACHE_BITS) { /* cannot read more than "CACHE_BITS" bits at once in the function FDKreadBits() */
      return (MAX_QUANTIZED_VALUE + 1); /* returning invalid value that will be captured later */
    }

    off = FDKreadBits(bs,i-16) << 16;
    off |= FDKreadBits(bs,16);
  }
  else
  {
    off = FDKreadBits(bs,i);
  }

  i = off + (1 << i);

  if (neg) i = -i;

  return i;
}

AAC_DECODER_ERROR CBlock_ReadScaleFactorData(
        CAacDecoderChannelInfo *pAacDecoderChannelInfo,
        HANDLE_FDK_BITSTREAM bs,
        UINT flags
        )
{
  int temp;
  int band;
  int group;
  int position = 0; /* accu for intensity delta coding */
  int factor = pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain; /* accu for scale factor delta coding */
  UCHAR *pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook;
  SHORT *pScaleFactor = pAacDecoderChannelInfo->pDynData->aScaleFactor;
  const CodeBookDescription *hcb =&AACcodeBookDescriptionTable[BOOKSCL];

  int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo);
  for (group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++)
  {
    for (band=0; band < ScaleFactorBandsTransmitted; band++)
    {
      switch (pCodeBook[group*16+band]) {

      case ZERO_HCB: /* zero book */
        pScaleFactor[group*16+band] = 0;
        break;

      default: /* decode scale factor */
        {
          temp = CBlock_DecodeHuffmanWord(bs,hcb);
          factor += temp - 60; /* MIDFAC 1.5 dB */
        }
        pScaleFactor[group*16+band] = factor - 100;
        break;

      case INTENSITY_HCB: /* intensity steering */
      case INTENSITY_HCB2:
        temp = CBlock_DecodeHuffmanWord(bs,hcb);
        position += temp - 60;
        pScaleFactor[group*16+band] = position - 100;
        break;

      case NOISE_HCB: /* PNS */
        if (flags & (AC_MPS_RES|AC_USAC|AC_RSVD50)) {
          return AAC_DEC_PARSE_ERROR;
        }
        CPns_Read( &pAacDecoderChannelInfo->data.aac.PnsData, bs, hcb, pAacDecoderChannelInfo->pDynData->aScaleFactor, pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain, band, group);
        break;
      }
    }
  }

  return AAC_DEC_OK;
}

void CBlock_ScaleSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, SamplingRateInfo *pSamplingRateInfo)
{
  int band;
  int window;
  const SHORT * RESTRICT pSfbScale  = pAacDecoderChannelInfo->pDynData->aSfbScale;
  SHORT * RESTRICT pSpecScale = pAacDecoderChannelInfo->specScale;
  int groupwin,group;
  const SHORT * RESTRICT BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo);
  SPECTRAL_PTR RESTRICT pSpectralCoefficient = pAacDecoderChannelInfo->pSpectralCoefficient;


  FDKmemclear(pSpecScale, 8*sizeof(SHORT));

  int max_band = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo);
  for (window=0, group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++)
  {
    for (groupwin=0; groupwin < GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); groupwin++, window++)
    {
      int SpecScale_window = pSpecScale[window];
      FIXP_DBL *pSpectrum = SPEC(pSpectralCoefficient, window,  pAacDecoderChannelInfo->granuleLength);

      /* find scaling for current window */
      for (band=0; band < max_band; band++)
      {
        SpecScale_window = fMax(SpecScale_window, (int)pSfbScale[window*16+band]);
      }

      if (pAacDecoderChannelInfo->pDynData->TnsData.Active) {
        SpecScale_window += TNS_SCALE;
      }

      /* store scaling of current window */
      pSpecScale[window] = SpecScale_window;

#ifdef FUNCTION_CBlock_ScaleSpectralData_func1

      CBlock_ScaleSpectralData_func1(pSpectrum, max_band, BandOffsets, SpecScale_window, pSfbScale, window);

#else /* FUNCTION_CBlock_ScaleSpectralData_func1 */
      for (band=0; band < max_band; band++)
      {
        int scale = SpecScale_window - pSfbScale[window*16+band];
        if (scale)
        {
          /* following relation can be used for optimizations: (BandOffsets[i]%4) == 0 for all i */
          int max_index = BandOffsets[band+1];
          for (int index = BandOffsets[band]; index < max_index; index++)
          {
            pSpectrum[index] >>= scale;
          }
        }
      }
#endif  /* FUNCTION_CBlock_ScaleSpectralData_func1 */
    }
  }

}

AAC_DECODER_ERROR CBlock_ReadSectionData(HANDLE_FDK_BITSTREAM bs,
                                         CAacDecoderChannelInfo *pAacDecoderChannelInfo,
                                         const SamplingRateInfo *pSamplingRateInfo,
                                         const UINT  flags)
{
  int top, band;
  int sect_len, sect_len_incr;
  int group;
  UCHAR sect_cb;
  UCHAR *pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook;
  /* HCR input (long) */
  int    numLinesInSecIdx  = 0;
  const SHORT *BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo);
  pAacDecoderChannelInfo->pDynData->specificTo.aac.numberSection = 0;
  AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK;

  FDKmemclear(pCodeBook, sizeof(UCHAR)*(8*16));

  const int nbits = (IsLongBlock(&pAacDecoderChannelInfo->icsInfo) == 1) ? 5 : 3;

  int sect_esc_val = (1 << nbits) - 1 ;

  UCHAR ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo);
  for (group=0; group<GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++)
  {
    for (band=0; band < ScaleFactorBandsTransmitted; )
    {
      sect_len = 0;
      if ( flags & AC_ER_VCB11 )  {
        sect_cb = (UCHAR) FDKreadBits(bs,5);
      }
      else
        sect_cb = (UCHAR) FDKreadBits(bs,4);

      if ( ((flags & AC_ER_VCB11) == 0) || ( sect_cb < 11 ) || ((sect_cb > 11) && (sect_cb < 16)) ) {
        sect_len_incr = FDKreadBits(bs, nbits);
        while (sect_len_incr == sect_esc_val)
        {
          sect_len += sect_esc_val;
          sect_len_incr = FDKreadBits(bs, nbits);
        }
      }
      else {
        sect_len_incr = 1;
      }

      sect_len += sect_len_incr;
      if (sect_len <= 0) {
         return AAC_DEC_PARSE_ERROR;
      }


      top = band + sect_len;

      if (flags & AC_ER_HCR) {
        /* HCR disabled */
        return AAC_DEC_PARSE_ERROR;
      }

      /* Check spectral line limits */
      if (IsLongBlock( &(pAacDecoderChannelInfo->icsInfo) ))
      {
        if (top > 64) {
          return AAC_DEC_DECODE_FRAME_ERROR;
        }
      } else { /* short block */
        if (top + group*16 > (8 * 16)) {
          return AAC_DEC_DECODE_FRAME_ERROR;
        }
      }

      /* Check if decoded codebook index is feasible */
      if ( (sect_cb == BOOKSCL)
       || ( (sect_cb == INTENSITY_HCB || sect_cb == INTENSITY_HCB2) && pAacDecoderChannelInfo->pDynData->RawDataInfo.CommonWindow == 0)
         )
      {
        return AAC_DEC_INVALID_CODE_BOOK;
      }

      /* Store codebook index */
      for (; band < top; band++)
      {
        pCodeBook[group*16+band] = sect_cb;
      }
    }
  }


  return ErrorStatus;
}

/* mso: provides a faster way to i-quantize a whole band in one go */

/**
 * \brief inverse quantize one sfb. Each value of the sfb is processed according to the
 *        formula: spectrum[i] = Sign(spectrum[i]) * Matissa(spectrum[i])^(4/3) * 2^(lsb/4).
 * \param spectrum pointer to first line of the sfb to be inverse quantized.
 * \param noLines number of lines belonging to the sfb.
 * \param lsb last 2 bits of the scale factor of the sfb.
 * \param scale max allowed shift scale for the sfb.
 */
static
void InverseQuantizeBand( FIXP_DBL * RESTRICT spectrum,
                              INT noLines,
                              INT lsb,
                              INT scale )
{
    const FIXP_DBL * RESTRICT InverseQuantTabler=(FIXP_DBL *)InverseQuantTable;
    const FIXP_DBL * RESTRICT MantissaTabler=(FIXP_DBL *)MantissaTable[lsb];
    const SCHAR* RESTRICT ExponentTabler=(SCHAR*)ExponentTable[lsb];

    FIXP_DBL *ptr = spectrum;
    FIXP_DBL signedValue;

    FDK_ASSERT(noLines>2);
    for (INT i=noLines; i--; )
    {
        if ((signedValue = *ptr++) != FL2FXCONST_DBL(0))
        {
          FIXP_DBL value = fAbs(signedValue);
          UINT freeBits = CntLeadingZeros(value);
          UINT exponent = 32 - freeBits;

          UINT x = (UINT) (LONG)value << (INT) freeBits;
          x <<= 1;                                  /* shift out sign bit to avoid masking later on */
          UINT tableIndex = x >> 24;
          x = (x >> 20) &  0x0F;

          UINT r0=(UINT)(LONG)InverseQuantTabler[tableIndex+0];
          UINT r1=(UINT)(LONG)InverseQuantTabler[tableIndex+1];
          UINT temp= (r1 - r0)*x + (r0 << 4);

          value = fMultDiv2((FIXP_DBL)temp, MantissaTabler[exponent]);

          /* + 1 compensates fMultDiv2() */
          scaleValueInPlace(&value, scale + ExponentTabler[exponent] + 1);

          signedValue = (signedValue < (FIXP_DBL)0) ? -value : value;
          ptr[-1] = signedValue;
        }
    }
}

AAC_DECODER_ERROR CBlock_InverseQuantizeSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, SamplingRateInfo *pSamplingRateInfo)
{
  int window, group, groupwin, band;
  int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo);
  UCHAR *RESTRICT pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook;
  SHORT *RESTRICT pSfbScale = pAacDecoderChannelInfo->pDynData->aSfbScale;
  SHORT *RESTRICT pScaleFactor = pAacDecoderChannelInfo->pDynData->aScaleFactor;
  const SHORT *RESTRICT BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo);

  FDKmemclear(pAacDecoderChannelInfo->pDynData->aSfbScale, (8*16)*sizeof(SHORT));

  for (window=0, group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++)
  {
    for (groupwin=0; groupwin < GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); groupwin++, window++)
    {
      /* inverse quantization */
      for (band=0; band < ScaleFactorBandsTransmitted; band++)
      {
        FIXP_DBL *pSpectralCoefficient = SPEC(pAacDecoderChannelInfo->pSpectralCoefficient, window, pAacDecoderChannelInfo->granuleLength) + BandOffsets[band];

        int noLines = BandOffsets[band+1] - BandOffsets[band];
        int bnds = group*16+band;
        int i;

        if ((pCodeBook[bnds] == ZERO_HCB)
         || (pCodeBook[bnds] == INTENSITY_HCB)
         || (pCodeBook[bnds] == INTENSITY_HCB2)
           )
          continue;

        if (pCodeBook[bnds] == NOISE_HCB)
        {
          /* Leave headroom for PNS values. + 1 because ceil(log2(2^(0.25*3))) = 1,
             worst case of additional headroom required because of the scalefactor. */
          pSfbScale[window*16+band] = (pScaleFactor [bnds] >> 2) + 1 ;
          continue;
        }

        /* Find max spectral line value of the current sfb */
        FIXP_DBL locMax = (FIXP_DBL)0;

        for (i = noLines; i-- ; ) {
          /* Expensive memory access */
          locMax = fMax(fixp_abs(pSpectralCoefficient[i]), locMax);
        }

        /* Cheap robustness improvement - Do not remove!!! */
        if (fixp_abs(locMax) > (FIXP_DBL)MAX_QUANTIZED_VALUE) {
          return AAC_DEC_DECODE_FRAME_ERROR;
        }

        /*
           The inverse quantized spectral lines are defined by:
        pSpectralCoefficient[i] = Sign(pSpectralCoefficient[i]) * 2^(0.25*pScaleFactor[bnds]) * pSpectralCoefficient[i]^(4/3)
           This is equivalent to:
        pSpectralCoefficient[i]    = Sign(pSpectralCoefficient[i]) * (2^(pScaleFactor[bnds] % 4) * pSpectralCoefficient[i]^(4/3))
        pSpectralCoefficient_e[i] += pScaleFactor[bnds]/4
        */
        {
          int msb = pScaleFactor [bnds] >> 2 ;
          int lsb = pScaleFactor [bnds] & 0x03 ;

          int scale = GetScaleFromValue(locMax, lsb);

          pSfbScale[window*16+band] = msb - scale;
          InverseQuantizeBand(pSpectralCoefficient, noLines, lsb, scale);
        }
      }
    }
  }


  return AAC_DEC_OK;
}


AAC_DECODER_ERROR  CBlock_ReadSpectralData(HANDLE_FDK_BITSTREAM bs,
                                           CAacDecoderChannelInfo *pAacDecoderChannelInfo,
                                           const SamplingRateInfo *pSamplingRateInfo,
                                           const UINT  flags)
{
  int i,index;
  int window,group,groupwin,groupoffset,band;
  UCHAR *RESTRICT pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook;
  const SHORT *RESTRICT BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo);

  SPECTRAL_PTR pSpectralCoefficient = pAacDecoderChannelInfo->pSpectralCoefficient;
  FIXP_DBL locMax;

  int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo);

  FDK_ASSERT(BandOffsets != NULL);

  FDKmemclear(pSpectralCoefficient, sizeof(SPECTRUM));

  if ( (flags & AC_ER_HCR) == 0 )
  {
    groupoffset = 0;

    /* plain huffman decoder  short */
    for (group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++)
    {
      for (band=0; band < ScaleFactorBandsTransmitted; band++)
      {
        int bnds = group*16+band;
        UCHAR currentCB = pCodeBook[bnds];

        /* patch to run plain-huffman-decoder with vcb11 input codebooks (LAV-checking might be possible below using the virtual cb and a LAV-table) */
        if ((currentCB >= 16) && (currentCB <= 31)) {
          pCodeBook[bnds] = currentCB = 11;
        }
        if ( !((currentCB == ZERO_HCB)
            || (currentCB == NOISE_HCB)
            || (currentCB == INTENSITY_HCB)
            || (currentCB == INTENSITY_HCB2)) )
        {
          const CodeBookDescription *hcb = &AACcodeBookDescriptionTable[currentCB];
          int step = hcb->Dimension;
          int offset = hcb->Offset;
          int bits = hcb->numBits;
          int mask = (1<<bits)-1;

          for (groupwin=0; groupwin < GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); groupwin++)
          {
            window = groupoffset + groupwin;

            FIXP_DBL *mdctSpectrum = SPEC(pSpectralCoefficient, window, pAacDecoderChannelInfo->granuleLength);

            locMax = (FIXP_DBL)0 ;

            for (index=BandOffsets[band]; index < BandOffsets[band+1]; index+=step)
            {
              int idx = CBlock_DecodeHuffmanWord(bs,hcb);

              for (i=0; i<step; i++) {
                FIXP_DBL tmp;

                tmp = (FIXP_DBL)((idx & mask)-offset);
                idx >>= bits;

                if (offset == 0) {
                  if (tmp != FIXP_DBL(0))
                    tmp = (FDKreadBits(bs,1))? -tmp : tmp;
                }
                mdctSpectrum[index+i] = tmp;
              }

              if (currentCB == ESCBOOK)
              {
                mdctSpectrum[index+0] = (FIXP_DBL)CBlock_GetEscape(bs, (LONG)mdctSpectrum[index+0]);
                mdctSpectrum[index+1] = (FIXP_DBL)CBlock_GetEscape(bs, (LONG)mdctSpectrum[index+1]);

              }
            }
          }
        }
      }
      groupoffset += GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group);
    }
    /* plain huffman decoding (short) finished */
  }
  else  /* if ( flags & AC_ER_HCR ) */
  {
    /* HCR - Huffman Codeword Reordering disabled */
    return AAC_DEC_DECODE_FRAME_ERROR;
  }

  if ( IsLongBlock(&pAacDecoderChannelInfo->icsInfo) && !(flags & (AC_ELD|AC_SCALABLE)) )
  {
    /* apply pulse data */
    CPulseData_Apply(&pAacDecoderChannelInfo->pDynData->specificTo.aac.PulseData,
                      GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo),
                      SPEC_LONG(pSpectralCoefficient));
  }


  return AAC_DEC_OK;
}



void ApplyTools ( CAacDecoderChannelInfo *pAacDecoderChannelInfo[],
                  const SamplingRateInfo *pSamplingRateInfo,
                  const UINT flags,
                  const int channel )
{
  CTns_Apply (
         &pAacDecoderChannelInfo[channel]->pDynData->TnsData,
         &pAacDecoderChannelInfo[channel]->icsInfo,
          pAacDecoderChannelInfo[channel]->pSpectralCoefficient,
          pSamplingRateInfo,
          pAacDecoderChannelInfo[channel]->granuleLength
          );
}

static
int getWindow2Nr(int length, int shape)
{
  int nr = 0;

  if (shape == 2) {
    /* Low Overlap, 3/4 zeroed */
    nr = (length * 3)>>2;
  }

  return nr;
}

void CBlock_FrequencyToTime(CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
                            CAacDecoderChannelInfo *pAacDecoderChannelInfo,
                            INT_PCM outSamples[],
                            const SHORT frameLen,
                            const int stride,
                            const int frameOk,
                            FIXP_DBL *pWorkBuffer1 )
{
  int fr, fl, tl, nSamples, nSpec;

  /* Determine left slope length (fl), right slope length (fr) and transform length (tl).
     USAC: The slope length may mismatch with the previous frame in case of LPD / FD
           transitions. The adjustment is handled by the imdct implementation.
  */
  tl = frameLen;
  nSpec = 1;

  switch( pAacDecoderChannelInfo->icsInfo.WindowSequence ) {
    default:
    case OnlyLongSequence:
      fl = frameLen;
      fr = frameLen - getWindow2Nr(frameLen, GetWindowShape(&pAacDecoderChannelInfo->icsInfo));
      break;
    case LongStopSequence:
      fl = frameLen >> 3;
      fr = frameLen;
      break;
    case LongStartSequence: /* or StopStartSequence */
      fl = frameLen;
      fr = frameLen >> 3;
      break;
    case EightShortSequence:
      fl = fr = frameLen >> 3;
      tl >>= 3;
      nSpec = 8;
      break;
  }

  {
    int i;

    {
      FIXP_DBL *tmp = pAacDecoderChannelInfo->pComData->workBufferCore1->mdctOutTemp;

      nSamples = imdct_block(
             &pAacDecoderStaticChannelInfo->IMdct,
              tmp,
              SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient),
              pAacDecoderChannelInfo->specScale,
              nSpec,
              frameLen,
              tl,
              FDKgetWindowSlope(fl, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)),
              fl,
              FDKgetWindowSlope(fr, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)),
              fr,
              (FIXP_DBL)0 );

      for (i=0; i<frameLen; i++) {
        outSamples[i*stride] = IMDCT_SCALE(tmp[i]);
      }
    }
  }

  FDK_ASSERT(nSamples == frameLen);

}

#include "ldfiltbank.h"
void CBlock_FrequencyToTimeLowDelay( CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo,
                                     CAacDecoderChannelInfo *pAacDecoderChannelInfo,
                                     INT_PCM outSamples[],
                                     const short frameLen,
                                     const char stride )
{
  InvMdctTransformLowDelay_fdk (
          SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient),
          pAacDecoderChannelInfo->specScale[0],
          outSamples,
          pAacDecoderStaticChannelInfo->pOverlapBuffer,
          stride,
          frameLen
          );
}
