| /* ----------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten |
| Forschung e.V. All rights reserved. |
| |
| 1. INTRODUCTION |
| The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software |
| that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding |
| scheme for digital audio. This FDK AAC Codec software is intended to be used on |
| a wide variety of Android devices. |
| |
| AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient |
| general perceptual audio codecs. AAC-ELD is considered the best-performing |
| full-bandwidth communications codec by independent studies and is widely |
| deployed. AAC has been standardized by ISO and IEC as part of the MPEG |
| specifications. |
| |
| Patent licenses for necessary patent claims for the FDK AAC Codec (including |
| those of Fraunhofer) may be obtained through Via Licensing |
| (www.vialicensing.com) or through the respective patent owners individually for |
| the purpose of encoding or decoding bit streams in products that are compliant |
| with the ISO/IEC MPEG audio standards. Please note that most manufacturers of |
| Android devices already license these patent claims through Via Licensing or |
| directly from the patent owners, and therefore FDK AAC Codec software may |
| already be covered under those patent licenses when it is used for those |
| licensed purposes only. |
| |
| Commercially-licensed AAC software libraries, including floating-point versions |
| with enhanced sound quality, are also available from Fraunhofer. Users are |
| encouraged to check the Fraunhofer website for additional applications |
| information and documentation. |
| |
| 2. COPYRIGHT LICENSE |
| |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted without payment of copyright license fees provided that you |
| satisfy the following conditions: |
| |
| You must retain the complete text of this software license in redistributions of |
| the FDK AAC Codec or your modifications thereto in source code form. |
| |
| You must retain the complete text of this software license in the documentation |
| and/or other materials provided with redistributions of the FDK AAC Codec or |
| your modifications thereto in binary form. You must make available free of |
| charge copies of the complete source code of the FDK AAC Codec and your |
| modifications thereto to recipients of copies in binary form. |
| |
| The name of Fraunhofer may not be used to endorse or promote products derived |
| from this library without prior written permission. |
| |
| You may not charge copyright license fees for anyone to use, copy or distribute |
| the FDK AAC Codec software or your modifications thereto. |
| |
| Your modified versions of the FDK AAC Codec must carry prominent notices stating |
| that you changed the software and the date of any change. For modified versions |
| of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" |
| must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK |
| AAC Codec Library for Android." |
| |
| 3. NO PATENT LICENSE |
| |
| NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without |
| limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. |
| Fraunhofer provides no warranty of patent non-infringement with respect to this |
| software. |
| |
| You may use this FDK AAC Codec software or modifications thereto only for |
| purposes that are authorized by appropriate patent licenses. |
| |
| 4. DISCLAIMER |
| |
| This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright |
| holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, |
| including but not limited to the implied warranties of merchantability and |
| fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, |
| or consequential damages, including but not limited to procurement of substitute |
| goods or services; loss of use, data, or profits, or business interruption, |
| however caused and on any theory of liability, whether in contract, strict |
| liability, or tort (including negligence), arising in any way out of the use of |
| this software, even if advised of the possibility of such damage. |
| |
| 5. CONTACT INFORMATION |
| |
| Fraunhofer Institute for Integrated Circuits IIS |
| Attention: Audio and Multimedia Departments - FDK AAC LL |
| Am Wolfsmantel 33 |
| 91058 Erlangen, Germany |
| |
| www.iis.fraunhofer.de/amm |
| amm-info@iis.fraunhofer.de |
| ----------------------------------------------------------------------------- */ |
| |
| /******************* 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 = IMDCT_SCALE_DBL(x + 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] += 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; |
| } |