android / platform / external / aac / ffff95538e9994d312ffdfbba94d88ed226ef7bf / . / libFDK / src / mdct.cpp

/* ----------------------------------------------------------------------------- | |

Software License for The Fraunhofer FDK AAC Codec Library for Android | |

© Copyright 1995 - 2019 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 | |

----------------------------------------------------------------------------- */ | |

/******************* Library for basic calculation routines ******************** | |

Author(s): Josef Hoepfl, Manuel Jander, Youliy Ninov, Daniel Hagel | |

Description: MDCT/MDST routines | |

*******************************************************************************/ | |

#include "mdct.h" | |

#include "FDK_tools_rom.h" | |

#include "dct.h" | |

#include "fixpoint_math.h" | |

void mdct_init(H_MDCT hMdct, FIXP_DBL *overlap, INT overlapBufferSize) { | |

hMdct->overlap.freq = overlap; | |

// FDKmemclear(overlap, overlapBufferSize*sizeof(FIXP_DBL)); | |

hMdct->prev_fr = 0; | |

hMdct->prev_nr = 0; | |

hMdct->prev_tl = 0; | |

hMdct->ov_size = overlapBufferSize; | |

hMdct->prevAliasSymmetry = 0; | |

hMdct->prevPrevAliasSymmetry = 0; | |

hMdct->pFacZir = NULL; | |

hMdct->pAsymOvlp = NULL; | |

} | |

/* | |

This program implements the forward MDCT transform on an input block of data. | |

The input block is in a form (A,B,C,D) where A,B,C and D are the respective | |

1/4th segments of the block. The program takes the input block and folds it in | |

the form: | |

(-D-Cr,A-Br). This block is twice shorter and here the 'r' suffix denotes | |

flipping of the sequence (reversing the order of the samples). While folding the | |

input block in the above mentioned shorter block the program windows the data. | |

Because the two operations (windowing and folding) are not implemented | |

sequentially, but together the program's structure is not easy to understand. | |

Once the output (already windowed) block (-D-Cr,A-Br) is ready it is passed to | |

the DCT IV for processing. | |

*/ | |

INT mdct_block(H_MDCT hMdct, const INT_PCM *RESTRICT timeData, | |

const INT noInSamples, FIXP_DBL *RESTRICT mdctData, | |

const INT nSpec, const INT tl, const FIXP_WTP *pRightWindowPart, | |

const INT fr, SHORT *pMdctData_e) { | |

int i, n; | |

/* tl: transform length | |

fl: left window slope length | |

nl: left window slope offset | |

fr: right window slope length | |

nr: right window slope offset | |

See FDK_tools/doc/intern/mdct.tex for more detail. */ | |

int fl, nl, nr; | |

const FIXP_WTP *wls, *wrs; | |

wrs = pRightWindowPart; | |

/* Detect FRprevious / FL mismatches and override parameters accordingly */ | |

if (hMdct->prev_fr == | |

0) { /* At start just initialize and pass parameters as they are */ | |

hMdct->prev_fr = fr; | |

hMdct->prev_wrs = wrs; | |

hMdct->prev_tl = tl; | |

} | |

/* Derive NR */ | |

nr = (tl - fr) >> 1; | |

/* Skip input samples if tl is smaller than block size */ | |

timeData += (noInSamples - tl) >> 1; | |

/* windowing */ | |

for (n = 0; n < nSpec; n++) { | |

/* | |

* MDCT scale: | |

* + 1: fMultDiv2() in windowing. | |

* + 1: Because of factor 1/2 in Princen-Bradley compliant windowed TDAC. | |

*/ | |

INT mdctData_e = 1 + 1; | |

/* Derive left parameters */ | |

wls = hMdct->prev_wrs; | |

fl = hMdct->prev_fr; | |

nl = (tl - fl) >> 1; | |

/* Here we implement a simplified version of what happens after the this | |

piece of code (see the comments below). We implement the folding of A and B | |

segments to (A-Br) but A is zero, because in this part of the MDCT sequence | |

the window coefficients with which A must be multiplied are zero. */ | |

for (i = 0; i < nl; i++) { | |

#if SAMPLE_BITS == DFRACT_BITS /* SPC_BITS and DFRACT_BITS should be equal. */ | |

mdctData[(tl / 2) + i] = -((FIXP_DBL)timeData[tl - i - 1] >> (1)); | |

#else | |

mdctData[(tl / 2) + i] = -(FIXP_DBL)timeData[tl - i - 1] | |

<< (DFRACT_BITS - SAMPLE_BITS - 1); /* 0(A)-Br */ | |

#endif | |

} | |

/* Implements the folding and windowing of the left part of the sequence, | |

that is segments A and B. The A segment is multiplied by the respective left | |

window coefficient and placed in a temporary variable. | |

tmp0 = fMultDiv2((FIXP_PCM)timeData[i+nl], pLeftWindowPart[i].v.im); | |

After this the B segment taken in reverse order is multiplied by the left | |

window and subtracted from the previously derived temporary variable, so | |

that finally we implement the A-Br operation. This output is written to the | |

right part of the MDCT output : (-D-Cr,A-Br). | |

mdctData[(tl/2)+i+nl] = fMultSubDiv2(tmp0, (FIXP_PCM)timeData[tl-nl-i-1], | |

pLeftWindowPart[i].v.re);//A*window-Br*window | |

The (A-Br) data is written to the output buffer (mdctData) without being | |

flipped. */ | |

for (i = 0; i < fl / 2; i++) { | |

FIXP_DBL tmp0; | |

tmp0 = fMultDiv2((FIXP_PCM)timeData[i + nl], wls[i].v.im); /* a*window */ | |

mdctData[(tl / 2) + i + nl] = | |

fMultSubDiv2(tmp0, (FIXP_PCM)timeData[tl - nl - i - 1], | |

wls[i].v.re); /* A*window-Br*window */ | |

} | |

/* Right window slope offset */ | |

/* Here we implement a simplified version of what happens after the this | |

piece of code (see the comments below). We implement the folding of C and D | |

segments to (-D-Cr) but D is zero, because in this part of the MDCT sequence | |

the window coefficients with which D must be multiplied are zero. */ | |

for (i = 0; i < nr; i++) { | |

#if SAMPLE_BITS == \ | |

DFRACT_BITS /* This should be SPC_BITS instead of DFRACT_BITS. */ | |

mdctData[(tl / 2) - 1 - i] = -((FIXP_DBL)timeData[tl + i] >> (1)); | |

#else | |

mdctData[(tl / 2) - 1 - i] = | |

-(FIXP_DBL)timeData[tl + i] | |

<< (DFRACT_BITS - SAMPLE_BITS - 1); /* -C flipped at placing */ | |

#endif | |

} | |

/* Implements the folding and windowing of the right part of the sequence, | |

that is, segments C and D. The C segment is multiplied by the respective | |

right window coefficient and placed in a temporary variable. | |

tmp1 = fMultDiv2((FIXP_PCM)timeData[tl+nr+i], pRightWindowPart[i].v.re); | |

After this the D segment taken in reverse order is multiplied by the right | |

window and added from the previously derived temporary variable, so that we | |

get (C+Dr) operation. This output is negated to get (-C-Dr) and written to | |

the left part of the MDCT output while being reversed (flipped) at the same | |

time, so that from (-C-Dr) we get (-D-Cr)=> (-D-Cr,A-Br). | |

mdctData[(tl/2)-nr-i-1] = -fMultAddDiv2(tmp1, | |

(FIXP_PCM)timeData[(tl*2)-nr-i-1], pRightWindowPart[i].v.im);*/ | |

for (i = 0; i < fr / 2; i++) { | |

FIXP_DBL tmp1; | |

tmp1 = fMultDiv2((FIXP_PCM)timeData[tl + nr + i], | |

wrs[i].v.re); /* C*window */ | |

mdctData[(tl / 2) - nr - i - 1] = | |

-fMultAddDiv2(tmp1, (FIXP_PCM)timeData[(tl * 2) - nr - i - 1], | |

wrs[i].v.im); /* -(C*window+Dr*window) and flip before | |

placing -> -Cr - D */ | |

} | |

/* We pass the shortened folded data (-D-Cr,A-Br) to the MDCT function */ | |

dct_IV(mdctData, tl, &mdctData_e); | |

pMdctData_e[n] = (SHORT)mdctData_e; | |

timeData += tl; | |

mdctData += tl; | |

hMdct->prev_wrs = wrs; | |

hMdct->prev_fr = fr; | |

hMdct->prev_tl = tl; | |

} | |

return nSpec * tl; | |

} | |

void imdct_gain(FIXP_DBL *pGain_m, int *pGain_e, int tl) { | |

FIXP_DBL gain_m = *pGain_m; | |

int gain_e = *pGain_e; | |

int log2_tl; | |

gain_e += -MDCT_OUTPUT_GAIN - MDCT_OUT_HEADROOM + 1; | |

if (tl == 0) { | |

/* Dont regard the 2/N factor from the IDCT. It is compensated for somewhere | |

* else. */ | |

*pGain_e = gain_e; | |

return; | |

} | |

log2_tl = DFRACT_BITS - 1 - fNormz((FIXP_DBL)tl); | |

gain_e += -log2_tl; | |

/* Detect non-radix 2 transform length and add amplitude compensation factor | |

which cannot be included into the exponent above */ | |

switch ((tl) >> (log2_tl - 2)) { | |

case 0x7: /* 10 ms, 1/tl = 1.0/(FDKpow(2.0, -log2_tl) * | |

0.53333333333333333333) */ | |

if (gain_m == (FIXP_DBL)0) { | |

gain_m = FL2FXCONST_DBL(0.53333333333333333333f); | |

} else { | |

gain_m = fMult(gain_m, FL2FXCONST_DBL(0.53333333333333333333f)); | |

} | |

break; | |

case 0x6: /* 3/4 of radix 2, 1/tl = 1.0/(FDKpow(2.0, -log2_tl) * 2.0/3.0) */ | |

if (gain_m == (FIXP_DBL)0) { | |

gain_m = FL2FXCONST_DBL(2.0 / 3.0f); | |

} else { | |

gain_m = fMult(gain_m, FL2FXCONST_DBL(2.0 / 3.0f)); | |

} | |

break; | |

case 0x5: /* 0.8 of radix 2 (e.g. tl 160), 1/tl = 1.0/(FDKpow(2.0, -log2_tl) | |

* 0.8/1.5) */ | |

if (gain_m == (FIXP_DBL)0) { | |

gain_m = FL2FXCONST_DBL(0.53333333333333333333f); | |

} else { | |

gain_m = fMult(gain_m, FL2FXCONST_DBL(0.53333333333333333333f)); | |

} | |

break; | |

case 0x4: | |

/* radix 2, nothing to do. */ | |

break; | |

default: | |

/* unsupported */ | |

FDK_ASSERT(0); | |

break; | |

} | |

*pGain_m = gain_m; | |

*pGain_e = gain_e; | |

} | |

INT imdct_drain(H_MDCT hMdct, FIXP_DBL *output, INT nrSamplesRoom) { | |

int buffered_samples = 0; | |

if (nrSamplesRoom > 0) { | |

buffered_samples = hMdct->ov_offset; | |

FDK_ASSERT(buffered_samples <= nrSamplesRoom); | |

if (buffered_samples > 0) { | |

FDKmemcpy(output, hMdct->overlap.time, | |

buffered_samples * sizeof(FIXP_DBL)); | |

hMdct->ov_offset = 0; | |

} | |

} | |

return buffered_samples; | |

} | |

INT imdct_copy_ov_and_nr(H_MDCT hMdct, FIXP_DBL *pTimeData, INT nrSamples) { | |

FIXP_DBL *pOvl; | |

int nt, nf, i; | |

nt = fMin(hMdct->ov_offset, nrSamples); | |

nrSamples -= nt; | |

nf = fMin(hMdct->prev_nr, nrSamples); | |

FDKmemcpy(pTimeData, hMdct->overlap.time, nt * sizeof(FIXP_DBL)); | |

pTimeData += nt; | |

pOvl = hMdct->overlap.freq + hMdct->ov_size - 1; | |

if (hMdct->prevPrevAliasSymmetry == 0) { | |

for (i = 0; i < nf; i++) { | |

FIXP_DBL x = -(*pOvl--); | |

*pTimeData = IMDCT_SCALE_DBL(x); | |

pTimeData++; | |

} | |

} else { | |

for (i = 0; i < nf; i++) { | |

FIXP_DBL x = (*pOvl--); | |

*pTimeData = IMDCT_SCALE_DBL(x); | |

pTimeData++; | |

} | |

} | |

return (nt + nf); | |

} | |

void imdct_adapt_parameters(H_MDCT hMdct, int *pfl, int *pnl, int tl, | |

const FIXP_WTP *wls, int noOutSamples) { | |

int fl = *pfl, nl = *pnl; | |

int window_diff, use_current = 0, use_previous = 0; | |

if (hMdct->prev_tl == 0) { | |

hMdct->prev_wrs = wls; | |

hMdct->prev_fr = fl; | |

hMdct->prev_nr = (noOutSamples - fl) >> 1; | |

hMdct->prev_tl = noOutSamples; | |

hMdct->ov_offset = 0; | |

use_current = 1; | |

} | |

window_diff = (hMdct->prev_fr - fl) >> 1; | |

/* check if the previous window slope can be adjusted to match the current | |

* window slope */ | |

if (hMdct->prev_nr + window_diff > 0) { | |

use_current = 1; | |

} | |

/* check if the current window slope can be adjusted to match the previous | |

* window slope */ | |

if (nl - window_diff > 0) { | |

use_previous = 1; | |

} | |

/* if both is possible choose the larger of both window slope lengths */ | |

if (use_current && use_previous) { | |

if (fl < hMdct->prev_fr) { | |

use_current = 0; | |

} | |

} | |

/* | |

* If the previous transform block is big enough, enlarge previous window | |

* overlap, if not, then shrink current window overlap. | |

*/ | |

if (use_current) { | |

hMdct->prev_nr += window_diff; | |

hMdct->prev_fr = fl; | |

hMdct->prev_wrs = wls; | |

} else { | |

nl -= window_diff; | |

fl = hMdct->prev_fr; | |

} | |

*pfl = fl; | |

*pnl = nl; | |

} | |

/* | |

This program implements the inverse modulated lapped transform, a generalized | |

version of the inverse MDCT transform. Setting none of the MLT_*_ALIAS_FLAG | |

flags computes the IMDCT, setting all of them computes the IMDST. Other | |

combinations of these flags compute type III transforms used by the RSVD60 | |

multichannel tool for transitions between MDCT/MDST. The following description | |

relates to the IMDCT only. | |

If we pass the data block (A,B,C,D,E,F) to the FORWARD MDCT it will produce two | |

outputs. The first one will be over the (A,B,C,D) part =>(-D-Cr,A-Br) and the | |

second one will be over the (C,D,E,F) part => (-F-Er,C-Dr), since there is a | |

overlap between consequtive passes of the algorithm. This overlap is over the | |

(C,D) segments. The two outputs will be given sequentially to the DCT IV | |

algorithm. At the INVERSE MDCT side we get two consecutive outputs from the IDCT | |

IV algorithm, namely the same blocks: (-D-Cr,A-Br) and (-F-Er,C-Dr). The first | |

of them lands in the Overlap buffer and the second is in the working one, which, | |

one algorithm pass later will substitute the one residing in the overlap | |

register. The IMDCT algorithm has to produce the C and D segments from the two | |

buffers. In order to do this we take the left part of the overlap | |

buffer(-D-Cr,A-Br), namely (-D-Cr) and add it appropriately to the right part of | |

the working buffer (-F-Er,C-Dr), namely (C-Dr), so that we get first the C | |

segment and later the D segment. We do this in the following way: From the right | |

part of the working buffer(C-Dr) we subtract the flipped left part of the | |

overlap buffer(-D-Cr): | |

Result = (C-Dr) - flipped(-D-Cr) = C -Dr + Dr + C = 2C | |

We divide by two and get the C segment. What we did is adding the right part of | |

the first frame to the left part of the second one. While applying these | |

operation we multiply the respective segments with the appropriate window | |

functions. | |

In order to get the D segment we do the following: | |

From the negated second part of the working buffer(C-Dr) we subtract the flipped | |

first part of the overlap buffer (-D-Cr): | |

Result= - (C -Dr) - flipped(-D-Cr)= -C +Dr +Dr +C = 2Dr. | |

After dividing by two and flipping we get the D segment.What we did is adding | |

the right part of the first frame to the left part of the second one. While | |

applying these operation we multiply the respective segments with the | |

appropriate window functions. | |

Once we have obtained the C and D segments the overlap buffer is emptied and the | |

current buffer is sent in it, so that the E and F segments are available for | |

decoding in the next algorithm pass.*/ | |

INT imlt_block(H_MDCT hMdct, FIXP_DBL *output, FIXP_DBL *spectrum, | |

const SHORT scalefactor[], const INT nSpec, | |

const INT noOutSamples, const INT tl, const FIXP_WTP *wls, | |

INT fl, const FIXP_WTP *wrs, const INT fr, FIXP_DBL gain, | |

int flags) { | |

FIXP_DBL *pOvl; | |

FIXP_DBL *pOut0 = output, *pOut1; | |

INT nl, nr; | |

int w, i, nrSamples = 0, specShiftScale, transform_gain_e = 0; | |

int currAliasSymmetry = (flags & MLT_FLAG_CURR_ALIAS_SYMMETRY); | |

/* Derive NR and NL */ | |

nr = (tl - fr) >> 1; | |

nl = (tl - fl) >> 1; | |

/* Include 2/N IMDCT gain into gain factor and exponent. */ | |

imdct_gain(&gain, &transform_gain_e, tl); | |

/* Detect FRprevious / FL mismatches and override parameters accordingly */ | |

if (hMdct->prev_fr != fl) { | |

imdct_adapt_parameters(hMdct, &fl, &nl, tl, wls, noOutSamples); | |

} | |

pOvl = hMdct->overlap.freq + hMdct->ov_size - 1; | |

if (noOutSamples > nrSamples) { | |

/* Purge buffered output. */ | |

for (i = 0; i < hMdct->ov_offset; i++) { | |

*pOut0 = hMdct->overlap.time[i]; | |

pOut0++; | |

} | |

nrSamples = hMdct->ov_offset; | |

hMdct->ov_offset = 0; | |

} | |

for (w = 0; w < nSpec; w++) { | |

FIXP_DBL *pSpec, *pCurr; | |

const FIXP_WTP *pWindow; | |

/* Detect FRprevious / FL mismatches and override parameters accordingly */ | |

if (hMdct->prev_fr != fl) { | |

imdct_adapt_parameters(hMdct, &fl, &nl, tl, wls, noOutSamples); | |

} | |

specShiftScale = transform_gain_e; | |

/* Setup window pointers */ | |

pWindow = hMdct->prev_wrs; | |

/* Current spectrum */ | |

pSpec = spectrum + w * tl; | |

/* DCT IV of current spectrum. */ | |

if (currAliasSymmetry == 0) { | |

if (hMdct->prevAliasSymmetry == 0) { | |

dct_IV(pSpec, tl, &specShiftScale); | |

} else { | |

FIXP_DBL _tmp[1024 + ALIGNMENT_DEFAULT / sizeof(FIXP_DBL)]; | |

FIXP_DBL *tmp = (FIXP_DBL *)ALIGN_PTR(_tmp); | |

C_ALLOC_ALIGNED_REGISTER(tmp, sizeof(_tmp)); | |

dct_III(pSpec, tmp, tl, &specShiftScale); | |

C_ALLOC_ALIGNED_UNREGISTER(tmp); | |

} | |

} else { | |

if (hMdct->prevAliasSymmetry == 0) { | |

FIXP_DBL _tmp[1024 + ALIGNMENT_DEFAULT / sizeof(FIXP_DBL)]; | |

FIXP_DBL *tmp = (FIXP_DBL *)ALIGN_PTR(_tmp); | |

C_ALLOC_ALIGNED_REGISTER(tmp, sizeof(_tmp)); | |

dst_III(pSpec, tmp, tl, &specShiftScale); | |

C_ALLOC_ALIGNED_UNREGISTER(tmp); | |

} else { | |

dst_IV(pSpec, tl, &specShiftScale); | |

} | |

} | |

/* Optional scaling of time domain - no yet windowed - of current spectrum | |

*/ | |

/* and de-scale current spectrum signal (time domain, no yet windowed) */ | |

if (gain != (FIXP_DBL)0) { | |

for (i = 0; i < tl; i++) { | |

pSpec[i] = fMult(pSpec[i], gain); | |

} | |

} | |

{ | |

int loc_scale = | |

fixmin_I(scalefactor[w] + specShiftScale, (INT)DFRACT_BITS - 1); | |

DWORD_ALIGNED(pSpec); | |

scaleValuesSaturate(pSpec, tl, loc_scale); | |

} | |

if (noOutSamples <= nrSamples) { | |

/* Divert output first half to overlap buffer if we already got enough | |

* output samples. */ | |

pOut0 = hMdct->overlap.time + hMdct->ov_offset; | |

hMdct->ov_offset += hMdct->prev_nr + fl / 2; | |

} else { | |

/* Account output samples */ | |

nrSamples += hMdct->prev_nr + fl / 2; | |

} | |

/* NR output samples 0 .. NR. -overlap[TL/2..TL/2-NR] */ | |

if ((hMdct->pFacZir != 0) && (hMdct->prev_nr == fl / 2)) { | |

/* In the case of ACELP -> TCX20 -> FD short add FAC ZIR on nr signal part | |

*/ | |

for (i = 0; i < hMdct->prev_nr; i++) { | |

FIXP_DBL x = -(*pOvl--); | |

*pOut0 = fAddSaturate(x, IMDCT_SCALE_DBL(hMdct->pFacZir[i])); | |

pOut0++; | |

} | |

hMdct->pFacZir = NULL; | |

} else { | |

/* Here we implement a simplified version of what happens after the this | |

piece of code (see the comments below). We implement the folding of C and | |

D segments from (-D-Cr) but D is zero, because in this part of the MDCT | |

sequence the window coefficients with which D must be multiplied are zero. | |

"pOut0" writes sequentially the C block from left to right. */ | |

if (hMdct->prevPrevAliasSymmetry == 0) { | |

for (i = 0; i < hMdct->prev_nr; i++) { | |

FIXP_DBL x = -(*pOvl--); | |

*pOut0 = IMDCT_SCALE_DBL(x); | |

pOut0++; | |

} | |

} else { | |

for (i = 0; i < hMdct->prev_nr; i++) { | |

FIXP_DBL x = *pOvl--; | |

*pOut0 = IMDCT_SCALE_DBL(x); | |

pOut0++; | |

} | |

} | |

} | |

if (noOutSamples <= nrSamples) { | |

/* Divert output second half to overlap buffer if we already got enough | |

* output samples. */ | |

pOut1 = hMdct->overlap.time + hMdct->ov_offset + fl / 2 - 1; | |

hMdct->ov_offset += fl / 2 + nl; | |

} else { | |

pOut1 = pOut0 + (fl - 1); | |

nrSamples += fl / 2 + nl; | |

} | |

/* output samples before window crossing point NR .. TL/2. | |

* -overlap[TL/2-NR..TL/2-NR-FL/2] + current[NR..TL/2] */ | |

/* output samples after window crossing point TL/2 .. TL/2+FL/2. | |

* -overlap[0..FL/2] - current[TL/2..FL/2] */ | |

pCurr = pSpec + tl - fl / 2; | |

DWORD_ALIGNED(pCurr); | |

C_ALLOC_ALIGNED_REGISTER(pWindow, fl); | |

DWORD_ALIGNED(pWindow); | |

C_ALLOC_ALIGNED_UNREGISTER(pWindow); | |

if (hMdct->prevPrevAliasSymmetry == 0) { | |

if (hMdct->prevAliasSymmetry == 0) { | |

if (!hMdct->pAsymOvlp) { | |

for (i = 0; i < fl / 2; i++) { | |

FIXP_DBL x0, x1; | |

cplxMultDiv2(&x1, &x0, *pCurr++, -*pOvl--, pWindow[i]); | |

*pOut0 = IMDCT_SCALE_DBL_LSH1(x0); | |

*pOut1 = IMDCT_SCALE_DBL_LSH1(-x1); | |

pOut0++; | |

pOut1--; | |

} | |

} else { | |

FIXP_DBL *pAsymOvl = hMdct->pAsymOvlp + fl / 2 - 1; | |

for (i = 0; i < fl / 2; i++) { | |

FIXP_DBL x0, x1; | |

x1 = -fMultDiv2(*pCurr, pWindow[i].v.re) + | |

fMultDiv2(*pAsymOvl, pWindow[i].v.im); | |

x0 = fMultDiv2(*pCurr, pWindow[i].v.im) - | |

fMultDiv2(*pOvl, pWindow[i].v.re); | |

pCurr++; | |

pOvl--; | |

pAsymOvl--; | |

*pOut0++ = IMDCT_SCALE_DBL_LSH1(x0); | |

*pOut1-- = IMDCT_SCALE_DBL_LSH1(x1); | |

} | |

hMdct->pAsymOvlp = NULL; | |

} | |

} else { /* prevAliasingSymmetry == 1 */ | |

for (i = 0; i < fl / 2; i++) { | |

FIXP_DBL x0, x1; | |

cplxMultDiv2(&x1, &x0, *pCurr++, -*pOvl--, pWindow[i]); | |

*pOut0 = IMDCT_SCALE_DBL_LSH1(x0); | |

*pOut1 = IMDCT_SCALE_DBL_LSH1(x1); | |

pOut0++; | |

pOut1--; | |

} | |

} | |

} else { /* prevPrevAliasingSymmetry == 1 */ | |

if (hMdct->prevAliasSymmetry == 0) { | |

for (i = 0; i < fl / 2; i++) { | |

FIXP_DBL x0, x1; | |

cplxMultDiv2(&x1, &x0, *pCurr++, *pOvl--, pWindow[i]); | |

*pOut0 = IMDCT_SCALE_DBL_LSH1(x0); | |

*pOut1 = IMDCT_SCALE_DBL_LSH1(-x1); | |

pOut0++; | |

pOut1--; | |

} | |

} else { /* prevAliasingSymmetry == 1 */ | |

for (i = 0; i < fl / 2; i++) { | |

FIXP_DBL x0, x1; | |

cplxMultDiv2(&x1, &x0, *pCurr++, *pOvl--, pWindow[i]); | |

*pOut0 = IMDCT_SCALE_DBL_LSH1(x0); | |

*pOut1 = IMDCT_SCALE_DBL_LSH1(x1); | |

pOut0++; | |

pOut1--; | |

} | |

} | |

} | |

if (hMdct->pFacZir != 0) { | |

/* add FAC ZIR of previous ACELP -> mdct transition */ | |

FIXP_DBL *pOut = pOut0 - fl / 2; | |

FDK_ASSERT(fl / 2 <= 128); | |

for (i = 0; i < fl / 2; i++) { | |

pOut[i] = fAddSaturate(pOut[i], IMDCT_SCALE_DBL(hMdct->pFacZir[i])); | |

} | |

hMdct->pFacZir = NULL; | |

} | |

pOut0 += (fl / 2) + nl; | |

/* NL output samples TL/2+FL/2..TL. - current[FL/2..0] */ | |

pOut1 += (fl / 2) + 1; | |

pCurr = pSpec + tl - fl / 2 - 1; | |

/* Here we implement a simplified version of what happens above the this | |

piece of code (see the comments above). We implement the folding of C and D | |

segments from (C-Dr) but C is zero, because in this part of the MDCT | |

sequence the window coefficients with which C must be multiplied are zero. | |

"pOut1" writes sequentially the D block from left to right. */ | |

if (hMdct->prevAliasSymmetry == 0) { | |

for (i = 0; i < nl; i++) { | |

FIXP_DBL x = -(*pCurr--); | |

*pOut1++ = IMDCT_SCALE_DBL(x); | |

} | |

} else { | |

for (i = 0; i < nl; i++) { | |

FIXP_DBL x = *pCurr--; | |

*pOut1++ = IMDCT_SCALE_DBL(x); | |

} | |

} | |

/* Set overlap source pointer for next window pOvl = pSpec + tl/2 - 1; */ | |

pOvl = pSpec + tl / 2 - 1; | |

/* Previous window values. */ | |

hMdct->prev_nr = nr; | |

hMdct->prev_fr = fr; | |

hMdct->prev_tl = tl; | |

hMdct->prev_wrs = wrs; | |

/* Previous aliasing symmetry */ | |

hMdct->prevPrevAliasSymmetry = hMdct->prevAliasSymmetry; | |

hMdct->prevAliasSymmetry = currAliasSymmetry; | |

} | |

/* Save overlap */ | |

pOvl = hMdct->overlap.freq + hMdct->ov_size - tl / 2; | |

FDKmemcpy(pOvl, &spectrum[(nSpec - 1) * tl], (tl / 2) * sizeof(FIXP_DBL)); | |

return nrSamples; | |

} |