xref: /aosp_15_r20/external/aac/libSBRdec/src/sbr_dec.cpp (revision e54365361535b070c2db7374cec45c159c7d0e7a)
1*e5436536SAndroid Build Coastguard Worker /* -----------------------------------------------------------------------------
2*e5436536SAndroid Build Coastguard Worker Software License for The Fraunhofer FDK AAC Codec Library for Android
3*e5436536SAndroid Build Coastguard Worker 
4*e5436536SAndroid Build Coastguard Worker © Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
5*e5436536SAndroid Build Coastguard Worker Forschung e.V. All rights reserved.
6*e5436536SAndroid Build Coastguard Worker 
7*e5436536SAndroid Build Coastguard Worker  1.    INTRODUCTION
8*e5436536SAndroid Build Coastguard Worker The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9*e5436536SAndroid Build Coastguard Worker that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10*e5436536SAndroid Build Coastguard Worker scheme for digital audio. This FDK AAC Codec software is intended to be used on
11*e5436536SAndroid Build Coastguard Worker a wide variety of Android devices.
12*e5436536SAndroid Build Coastguard Worker 
13*e5436536SAndroid Build Coastguard Worker AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14*e5436536SAndroid Build Coastguard Worker general perceptual audio codecs. AAC-ELD is considered the best-performing
15*e5436536SAndroid Build Coastguard Worker full-bandwidth communications codec by independent studies and is widely
16*e5436536SAndroid Build Coastguard Worker deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17*e5436536SAndroid Build Coastguard Worker specifications.
18*e5436536SAndroid Build Coastguard Worker 
19*e5436536SAndroid Build Coastguard Worker Patent licenses for necessary patent claims for the FDK AAC Codec (including
20*e5436536SAndroid Build Coastguard Worker those of Fraunhofer) may be obtained through Via Licensing
21*e5436536SAndroid Build Coastguard Worker (www.vialicensing.com) or through the respective patent owners individually for
22*e5436536SAndroid Build Coastguard Worker the purpose of encoding or decoding bit streams in products that are compliant
23*e5436536SAndroid Build Coastguard Worker with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24*e5436536SAndroid Build Coastguard Worker Android devices already license these patent claims through Via Licensing or
25*e5436536SAndroid Build Coastguard Worker directly from the patent owners, and therefore FDK AAC Codec software may
26*e5436536SAndroid Build Coastguard Worker already be covered under those patent licenses when it is used for those
27*e5436536SAndroid Build Coastguard Worker licensed purposes only.
28*e5436536SAndroid Build Coastguard Worker 
29*e5436536SAndroid Build Coastguard Worker Commercially-licensed AAC software libraries, including floating-point versions
30*e5436536SAndroid Build Coastguard Worker with enhanced sound quality, are also available from Fraunhofer. Users are
31*e5436536SAndroid Build Coastguard Worker encouraged to check the Fraunhofer website for additional applications
32*e5436536SAndroid Build Coastguard Worker information and documentation.
33*e5436536SAndroid Build Coastguard Worker 
34*e5436536SAndroid Build Coastguard Worker 2.    COPYRIGHT LICENSE
35*e5436536SAndroid Build Coastguard Worker 
36*e5436536SAndroid Build Coastguard Worker Redistribution and use in source and binary forms, with or without modification,
37*e5436536SAndroid Build Coastguard Worker are permitted without payment of copyright license fees provided that you
38*e5436536SAndroid Build Coastguard Worker satisfy the following conditions:
39*e5436536SAndroid Build Coastguard Worker 
40*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in redistributions of
41*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec or your modifications thereto in source code form.
42*e5436536SAndroid Build Coastguard Worker 
43*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in the documentation
44*e5436536SAndroid Build Coastguard Worker and/or other materials provided with redistributions of the FDK AAC Codec or
45*e5436536SAndroid Build Coastguard Worker your modifications thereto in binary form. You must make available free of
46*e5436536SAndroid Build Coastguard Worker charge copies of the complete source code of the FDK AAC Codec and your
47*e5436536SAndroid Build Coastguard Worker modifications thereto to recipients of copies in binary form.
48*e5436536SAndroid Build Coastguard Worker 
49*e5436536SAndroid Build Coastguard Worker The name of Fraunhofer may not be used to endorse or promote products derived
50*e5436536SAndroid Build Coastguard Worker from this library without prior written permission.
51*e5436536SAndroid Build Coastguard Worker 
52*e5436536SAndroid Build Coastguard Worker You may not charge copyright license fees for anyone to use, copy or distribute
53*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec software or your modifications thereto.
54*e5436536SAndroid Build Coastguard Worker 
55*e5436536SAndroid Build Coastguard Worker Your modified versions of the FDK AAC Codec must carry prominent notices stating
56*e5436536SAndroid Build Coastguard Worker that you changed the software and the date of any change. For modified versions
57*e5436536SAndroid Build Coastguard Worker of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58*e5436536SAndroid Build Coastguard Worker must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59*e5436536SAndroid Build Coastguard Worker AAC Codec Library for Android."
60*e5436536SAndroid Build Coastguard Worker 
61*e5436536SAndroid Build Coastguard Worker 3.    NO PATENT LICENSE
62*e5436536SAndroid Build Coastguard Worker 
63*e5436536SAndroid Build Coastguard Worker NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64*e5436536SAndroid Build Coastguard Worker limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65*e5436536SAndroid Build Coastguard Worker Fraunhofer provides no warranty of patent non-infringement with respect to this
66*e5436536SAndroid Build Coastguard Worker software.
67*e5436536SAndroid Build Coastguard Worker 
68*e5436536SAndroid Build Coastguard Worker You may use this FDK AAC Codec software or modifications thereto only for
69*e5436536SAndroid Build Coastguard Worker purposes that are authorized by appropriate patent licenses.
70*e5436536SAndroid Build Coastguard Worker 
71*e5436536SAndroid Build Coastguard Worker 4.    DISCLAIMER
72*e5436536SAndroid Build Coastguard Worker 
73*e5436536SAndroid Build Coastguard Worker This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74*e5436536SAndroid Build Coastguard Worker holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75*e5436536SAndroid Build Coastguard Worker including but not limited to the implied warranties of merchantability and
76*e5436536SAndroid Build Coastguard Worker fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77*e5436536SAndroid Build Coastguard Worker CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78*e5436536SAndroid Build Coastguard Worker or consequential damages, including but not limited to procurement of substitute
79*e5436536SAndroid Build Coastguard Worker goods or services; loss of use, data, or profits, or business interruption,
80*e5436536SAndroid Build Coastguard Worker however caused and on any theory of liability, whether in contract, strict
81*e5436536SAndroid Build Coastguard Worker liability, or tort (including negligence), arising in any way out of the use of
82*e5436536SAndroid Build Coastguard Worker this software, even if advised of the possibility of such damage.
83*e5436536SAndroid Build Coastguard Worker 
84*e5436536SAndroid Build Coastguard Worker 5.    CONTACT INFORMATION
85*e5436536SAndroid Build Coastguard Worker 
86*e5436536SAndroid Build Coastguard Worker Fraunhofer Institute for Integrated Circuits IIS
87*e5436536SAndroid Build Coastguard Worker Attention: Audio and Multimedia Departments - FDK AAC LL
88*e5436536SAndroid Build Coastguard Worker Am Wolfsmantel 33
89*e5436536SAndroid Build Coastguard Worker 91058 Erlangen, Germany
90*e5436536SAndroid Build Coastguard Worker 
91*e5436536SAndroid Build Coastguard Worker www.iis.fraunhofer.de/amm
92*e5436536SAndroid Build Coastguard Worker [email protected]
93*e5436536SAndroid Build Coastguard Worker ----------------------------------------------------------------------------- */
94*e5436536SAndroid Build Coastguard Worker 
95*e5436536SAndroid Build Coastguard Worker /**************************** SBR decoder library ******************************
96*e5436536SAndroid Build Coastguard Worker 
97*e5436536SAndroid Build Coastguard Worker    Author(s):
98*e5436536SAndroid Build Coastguard Worker 
99*e5436536SAndroid Build Coastguard Worker    Description:
100*e5436536SAndroid Build Coastguard Worker 
101*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
102*e5436536SAndroid Build Coastguard Worker 
103*e5436536SAndroid Build Coastguard Worker /*!
104*e5436536SAndroid Build Coastguard Worker   \file
105*e5436536SAndroid Build Coastguard Worker   \brief  Sbr decoder
106*e5436536SAndroid Build Coastguard Worker   This module provides the actual decoder implementation. The SBR data (side
107*e5436536SAndroid Build Coastguard Worker   information) is already decoded. Only three functions are provided:
108*e5436536SAndroid Build Coastguard Worker 
109*e5436536SAndroid Build Coastguard Worker   \li 1.) createSbrDec(): One time initialization
110*e5436536SAndroid Build Coastguard Worker   \li 2.) resetSbrDec(): Called by sbr_Apply() when the information contained in
111*e5436536SAndroid Build Coastguard Worker   an SBR_HEADER_ELEMENT requires a reset and recalculation of important SBR
112*e5436536SAndroid Build Coastguard Worker   structures. \li 3.) sbr_dec(): The actual decoder. Calls the different tools
113*e5436536SAndroid Build Coastguard Worker   such as filterbanks, lppTransposer(), and calculateSbrEnvelope() [the envelope
114*e5436536SAndroid Build Coastguard Worker   adjuster].
115*e5436536SAndroid Build Coastguard Worker 
116*e5436536SAndroid Build Coastguard Worker   \sa sbr_dec(), \ref documentationOverview
117*e5436536SAndroid Build Coastguard Worker */
118*e5436536SAndroid Build Coastguard Worker 
119*e5436536SAndroid Build Coastguard Worker #include "sbr_dec.h"
120*e5436536SAndroid Build Coastguard Worker 
121*e5436536SAndroid Build Coastguard Worker #include "sbr_ram.h"
122*e5436536SAndroid Build Coastguard Worker #include "env_extr.h"
123*e5436536SAndroid Build Coastguard Worker #include "env_calc.h"
124*e5436536SAndroid Build Coastguard Worker #include "scale.h"
125*e5436536SAndroid Build Coastguard Worker #include "FDK_matrixCalloc.h"
126*e5436536SAndroid Build Coastguard Worker #include "hbe.h"
127*e5436536SAndroid Build Coastguard Worker 
128*e5436536SAndroid Build Coastguard Worker #include "genericStds.h"
129*e5436536SAndroid Build Coastguard Worker 
130*e5436536SAndroid Build Coastguard Worker #include "sbrdec_drc.h"
131*e5436536SAndroid Build Coastguard Worker 
copyHarmonicSpectrum(int * xOverQmf,FIXP_DBL ** qmfReal,FIXP_DBL ** qmfImag,int noCols,int overlap,KEEP_STATES_SYNCED_MODE keepStatesSynced)132*e5436536SAndroid Build Coastguard Worker static void copyHarmonicSpectrum(int *xOverQmf, FIXP_DBL **qmfReal,
133*e5436536SAndroid Build Coastguard Worker                                  FIXP_DBL **qmfImag, int noCols, int overlap,
134*e5436536SAndroid Build Coastguard Worker                                  KEEP_STATES_SYNCED_MODE keepStatesSynced) {
135*e5436536SAndroid Build Coastguard Worker   int patchBands;
136*e5436536SAndroid Build Coastguard Worker   int patch, band, col, target, sourceBands, i;
137*e5436536SAndroid Build Coastguard Worker   int numPatches = 0;
138*e5436536SAndroid Build Coastguard Worker   int slotOffset = 0;
139*e5436536SAndroid Build Coastguard Worker 
140*e5436536SAndroid Build Coastguard Worker   FIXP_DBL **ppqmfReal = qmfReal + overlap;
141*e5436536SAndroid Build Coastguard Worker   FIXP_DBL **ppqmfImag = qmfImag + overlap;
142*e5436536SAndroid Build Coastguard Worker 
143*e5436536SAndroid Build Coastguard Worker   if (keepStatesSynced == KEEP_STATES_SYNCED_NORMAL) {
144*e5436536SAndroid Build Coastguard Worker     slotOffset = noCols - overlap - LPC_ORDER;
145*e5436536SAndroid Build Coastguard Worker   }
146*e5436536SAndroid Build Coastguard Worker 
147*e5436536SAndroid Build Coastguard Worker   if (keepStatesSynced == KEEP_STATES_SYNCED_OUTDIFF) {
148*e5436536SAndroid Build Coastguard Worker     ppqmfReal = qmfReal;
149*e5436536SAndroid Build Coastguard Worker     ppqmfImag = qmfImag;
150*e5436536SAndroid Build Coastguard Worker   }
151*e5436536SAndroid Build Coastguard Worker 
152*e5436536SAndroid Build Coastguard Worker   for (i = 1; i < MAX_NUM_PATCHES; i++) {
153*e5436536SAndroid Build Coastguard Worker     if (xOverQmf[i] != 0) {
154*e5436536SAndroid Build Coastguard Worker       numPatches++;
155*e5436536SAndroid Build Coastguard Worker     }
156*e5436536SAndroid Build Coastguard Worker   }
157*e5436536SAndroid Build Coastguard Worker 
158*e5436536SAndroid Build Coastguard Worker   for (patch = (MAX_STRETCH_HBE - 1); patch < numPatches; patch++) {
159*e5436536SAndroid Build Coastguard Worker     patchBands = xOverQmf[patch + 1] - xOverQmf[patch];
160*e5436536SAndroid Build Coastguard Worker     target = xOverQmf[patch];
161*e5436536SAndroid Build Coastguard Worker     sourceBands = xOverQmf[MAX_STRETCH_HBE - 1] - xOverQmf[MAX_STRETCH_HBE - 2];
162*e5436536SAndroid Build Coastguard Worker 
163*e5436536SAndroid Build Coastguard Worker     while (patchBands > 0) {
164*e5436536SAndroid Build Coastguard Worker       int numBands = sourceBands;
165*e5436536SAndroid Build Coastguard Worker       int startBand = xOverQmf[MAX_STRETCH_HBE - 1] - 1;
166*e5436536SAndroid Build Coastguard Worker       if (target + numBands >= xOverQmf[patch + 1]) {
167*e5436536SAndroid Build Coastguard Worker         numBands = xOverQmf[patch + 1] - target;
168*e5436536SAndroid Build Coastguard Worker       }
169*e5436536SAndroid Build Coastguard Worker       if ((((target + numBands - 1) % 2) +
170*e5436536SAndroid Build Coastguard Worker            ((xOverQmf[MAX_STRETCH_HBE - 1] - 1) % 2)) %
171*e5436536SAndroid Build Coastguard Worker           2) {
172*e5436536SAndroid Build Coastguard Worker         if (numBands == sourceBands) {
173*e5436536SAndroid Build Coastguard Worker           numBands--;
174*e5436536SAndroid Build Coastguard Worker         } else {
175*e5436536SAndroid Build Coastguard Worker           startBand--;
176*e5436536SAndroid Build Coastguard Worker         }
177*e5436536SAndroid Build Coastguard Worker       }
178*e5436536SAndroid Build Coastguard Worker       if (keepStatesSynced == KEEP_STATES_SYNCED_OUTDIFF) {
179*e5436536SAndroid Build Coastguard Worker         for (col = slotOffset; col < overlap + LPC_ORDER; col++) {
180*e5436536SAndroid Build Coastguard Worker           i = 0;
181*e5436536SAndroid Build Coastguard Worker           for (band = numBands; band > 0; band--) {
182*e5436536SAndroid Build Coastguard Worker             if ((target + band - 1 < 64) &&
183*e5436536SAndroid Build Coastguard Worker                 (target + band - 1 < xOverQmf[patch + 1])) {
184*e5436536SAndroid Build Coastguard Worker               ppqmfReal[col][target + band - 1] = ppqmfReal[col][startBand - i];
185*e5436536SAndroid Build Coastguard Worker               ppqmfImag[col][target + band - 1] = ppqmfImag[col][startBand - i];
186*e5436536SAndroid Build Coastguard Worker               i++;
187*e5436536SAndroid Build Coastguard Worker             }
188*e5436536SAndroid Build Coastguard Worker           }
189*e5436536SAndroid Build Coastguard Worker         }
190*e5436536SAndroid Build Coastguard Worker       } else {
191*e5436536SAndroid Build Coastguard Worker         for (col = slotOffset; col < noCols; col++) {
192*e5436536SAndroid Build Coastguard Worker           i = 0;
193*e5436536SAndroid Build Coastguard Worker           for (band = numBands; band > 0; band--) {
194*e5436536SAndroid Build Coastguard Worker             if ((target + band - 1 < 64) &&
195*e5436536SAndroid Build Coastguard Worker                 (target + band - 1 < xOverQmf[patch + 1])) {
196*e5436536SAndroid Build Coastguard Worker               ppqmfReal[col][target + band - 1] = ppqmfReal[col][startBand - i];
197*e5436536SAndroid Build Coastguard Worker               ppqmfImag[col][target + band - 1] = ppqmfImag[col][startBand - i];
198*e5436536SAndroid Build Coastguard Worker               i++;
199*e5436536SAndroid Build Coastguard Worker             }
200*e5436536SAndroid Build Coastguard Worker           }
201*e5436536SAndroid Build Coastguard Worker         }
202*e5436536SAndroid Build Coastguard Worker       }
203*e5436536SAndroid Build Coastguard Worker       target += numBands;
204*e5436536SAndroid Build Coastguard Worker       patchBands -= numBands;
205*e5436536SAndroid Build Coastguard Worker     }
206*e5436536SAndroid Build Coastguard Worker   }
207*e5436536SAndroid Build Coastguard Worker }
208*e5436536SAndroid Build Coastguard Worker 
209*e5436536SAndroid Build Coastguard Worker /*!
210*e5436536SAndroid Build Coastguard Worker   \brief      SBR decoder core function for one channel
211*e5436536SAndroid Build Coastguard Worker 
212*e5436536SAndroid Build Coastguard Worker   \image html  BufferMgmtDetailed-1632.png
213*e5436536SAndroid Build Coastguard Worker 
214*e5436536SAndroid Build Coastguard Worker   Besides the filter states of the QMF filter bank and the LPC-states of
215*e5436536SAndroid Build Coastguard Worker   the LPP-Transposer, processing is mainly based on four buffers:
216*e5436536SAndroid Build Coastguard Worker   #timeIn, #timeOut, #WorkBuffer2 and #OverlapBuffer. The #WorkBuffer2
217*e5436536SAndroid Build Coastguard Worker   is reused for all channels and might be used by the core decoder, a
218*e5436536SAndroid Build Coastguard Worker   static overlap buffer is required for each channel. Due to in-place
219*e5436536SAndroid Build Coastguard Worker   processing, #timeIn and #timeOut point to identical locations.
220*e5436536SAndroid Build Coastguard Worker 
221*e5436536SAndroid Build Coastguard Worker   The spectral data is organized in so-called slots. Each slot
222*e5436536SAndroid Build Coastguard Worker   contains 64 bands of complex data. The number of slots per frame
223*e5436536SAndroid Build Coastguard Worker   depends on the frame size. For mp3PRO, there are 18 slots per frame
224*e5436536SAndroid Build Coastguard Worker   and 6 slots per #OverlapBuffer. It is not necessary to have the slots
225*e5436536SAndroid Build Coastguard Worker   in located consecutive address ranges.
226*e5436536SAndroid Build Coastguard Worker 
227*e5436536SAndroid Build Coastguard Worker   To optimize memory usage and to minimize the number of memory
228*e5436536SAndroid Build Coastguard Worker   accesses, the memory management is organized as follows (slot numbers
229*e5436536SAndroid Build Coastguard Worker   based on mp3PRO):
230*e5436536SAndroid Build Coastguard Worker 
231*e5436536SAndroid Build Coastguard Worker   1.) Input time domain signal is located in #timeIn. The last slots
232*e5436536SAndroid Build Coastguard Worker   (0..5) of the spectral data of the previous frame are located in the
233*e5436536SAndroid Build Coastguard Worker   #OverlapBuffer. In addition, #frameData of the current frame resides
234*e5436536SAndroid Build Coastguard Worker   in the upper part of #timeIn.
235*e5436536SAndroid Build Coastguard Worker 
236*e5436536SAndroid Build Coastguard Worker   2.) During the cplxAnalysisQmfFiltering(), 32 samples from #timeIn are
237*e5436536SAndroid Build Coastguard Worker   transformed into a slot of up to 32 complex spectral low band values at a
238*e5436536SAndroid Build Coastguard Worker   time. The first spectral slot -- nr. 6 -- is written at slot number
239*e5436536SAndroid Build Coastguard Worker   zero of #WorkBuffer2. #WorkBuffer2 will be completely filled with
240*e5436536SAndroid Build Coastguard Worker   spectral data.
241*e5436536SAndroid Build Coastguard Worker 
242*e5436536SAndroid Build Coastguard Worker   3.) LPP-Transposition in lppTransposer() is processed on 24 slots. During the
243*e5436536SAndroid Build Coastguard Worker   transposition, the high band part of the spectral data is replicated
244*e5436536SAndroid Build Coastguard Worker   based on the low band data.
245*e5436536SAndroid Build Coastguard Worker 
246*e5436536SAndroid Build Coastguard Worker   Envelope Adjustment is processed on the high band part of the spectral
247*e5436536SAndroid Build Coastguard Worker   data only by calculateSbrEnvelope().
248*e5436536SAndroid Build Coastguard Worker 
249*e5436536SAndroid Build Coastguard Worker   4.) The cplxSynthesisQmfFiltering() creates 64 time domain samples out
250*e5436536SAndroid Build Coastguard Worker   of a slot of 64 complex spectral values at a time. The first 6 slots
251*e5436536SAndroid Build Coastguard Worker   in #timeOut are filled from the results of spectral slots 0..5 in the
252*e5436536SAndroid Build Coastguard Worker   #OverlapBuffer. The consecutive slots in timeOut are now filled with
253*e5436536SAndroid Build Coastguard Worker   the results of spectral slots 6..17.
254*e5436536SAndroid Build Coastguard Worker 
255*e5436536SAndroid Build Coastguard Worker   5.) The preprocessed slots 18..23 have to be stored in the
256*e5436536SAndroid Build Coastguard Worker   #OverlapBuffer.
257*e5436536SAndroid Build Coastguard Worker 
258*e5436536SAndroid Build Coastguard Worker */
259*e5436536SAndroid Build Coastguard Worker 
sbr_dec(HANDLE_SBR_DEC hSbrDec,LONG * timeIn,LONG * timeOut,HANDLE_SBR_DEC hSbrDecRight,LONG * timeOutRight,const int strideOut,HANDLE_SBR_HEADER_DATA hHeaderData,HANDLE_SBR_FRAME_DATA hFrameData,HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData,const int applyProcessing,HANDLE_PS_DEC h_ps_d,const UINT flags,const int codecFrameSize,const INT sbrInDataHeadroom)260*e5436536SAndroid Build Coastguard Worker void sbr_dec(
261*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_DEC hSbrDec,             /*!< handle to Decoder channel */
262*e5436536SAndroid Build Coastguard Worker     LONG *timeIn,                       /*!< pointer to input time signal */
263*e5436536SAndroid Build Coastguard Worker     LONG *timeOut,                      /*!< pointer to output time signal */
264*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_DEC hSbrDecRight,        /*!< handle to Decoder channel right */
265*e5436536SAndroid Build Coastguard Worker     LONG *timeOutRight,                 /*!< pointer to output time signal */
266*e5436536SAndroid Build Coastguard Worker     const int strideOut,                /*!< Time data traversal strideOut */
267*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
268*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_FRAME_DATA hFrameData,   /*!< Control data of current frame */
269*e5436536SAndroid Build Coastguard Worker     HANDLE_SBR_PREV_FRAME_DATA
270*e5436536SAndroid Build Coastguard Worker         hPrevFrameData,        /*!< Some control data of last frame */
271*e5436536SAndroid Build Coastguard Worker     const int applyProcessing, /*!< Flag for SBR operation */
272*e5436536SAndroid Build Coastguard Worker     HANDLE_PS_DEC h_ps_d, const UINT flags, const int codecFrameSize,
273*e5436536SAndroid Build Coastguard Worker     const INT sbrInDataHeadroom) {
274*e5436536SAndroid Build Coastguard Worker   int i, slot, reserve;
275*e5436536SAndroid Build Coastguard Worker   int saveLbScale;
276*e5436536SAndroid Build Coastguard Worker   int lastSlotOffs;
277*e5436536SAndroid Build Coastguard Worker   FIXP_DBL maxVal;
278*e5436536SAndroid Build Coastguard Worker 
279*e5436536SAndroid Build Coastguard Worker   /* temporary pointer / variable for QMF;
280*e5436536SAndroid Build Coastguard Worker      required as we want to use temporary buffer
281*e5436536SAndroid Build Coastguard Worker      creating one frame delay for HBE in LP mode */
282*e5436536SAndroid Build Coastguard Worker   LONG *pTimeInQmf = timeIn;
283*e5436536SAndroid Build Coastguard Worker 
284*e5436536SAndroid Build Coastguard Worker   /* Number of QMF timeslots in the overlap buffer: */
285*e5436536SAndroid Build Coastguard Worker   int ov_len = hSbrDec->LppTrans.pSettings->overlap;
286*e5436536SAndroid Build Coastguard Worker 
287*e5436536SAndroid Build Coastguard Worker   /* Number of QMF slots per frame */
288*e5436536SAndroid Build Coastguard Worker   int noCols = hHeaderData->numberTimeSlots * hHeaderData->timeStep;
289*e5436536SAndroid Build Coastguard Worker 
290*e5436536SAndroid Build Coastguard Worker   /* create pointer array for data to use for HBE and legacy sbr */
291*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *pLowBandReal[(3 * 4) + 2 * ((1024) / (32) * (4) / 2)];
292*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *pLowBandImag[(3 * 4) + 2 * ((1024) / (32) * (4) / 2)];
293*e5436536SAndroid Build Coastguard Worker 
294*e5436536SAndroid Build Coastguard Worker   /* set pReal to where QMF analysis writes in case of legacy SBR */
295*e5436536SAndroid Build Coastguard Worker   FIXP_DBL **pReal = pLowBandReal + ov_len;
296*e5436536SAndroid Build Coastguard Worker   FIXP_DBL **pImag = pLowBandImag + ov_len;
297*e5436536SAndroid Build Coastguard Worker 
298*e5436536SAndroid Build Coastguard Worker   /* map QMF buffer to pointer array (Overlap + Frame)*/
299*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < noCols + ov_len; i++) {
300*e5436536SAndroid Build Coastguard Worker     pLowBandReal[i] = hSbrDec->qmfDomainInCh->hQmfSlotsReal[i];
301*e5436536SAndroid Build Coastguard Worker     pLowBandImag[i] = hSbrDec->qmfDomainInCh->hQmfSlotsImag[i];
302*e5436536SAndroid Build Coastguard Worker   }
303*e5436536SAndroid Build Coastguard Worker 
304*e5436536SAndroid Build Coastguard Worker   if ((flags & SBRDEC_USAC_HARMONICSBR)) {
305*e5436536SAndroid Build Coastguard Worker     /* in case of harmonic SBR and no HBE_LP map additional buffer for
306*e5436536SAndroid Build Coastguard Worker        one more frame to pointer arry */
307*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < noCols; i++) {
308*e5436536SAndroid Build Coastguard Worker       pLowBandReal[i + noCols + ov_len] = hSbrDec->hQmfHBESlotsReal[i];
309*e5436536SAndroid Build Coastguard Worker       pLowBandImag[i + noCols + ov_len] = hSbrDec->hQmfHBESlotsImag[i];
310*e5436536SAndroid Build Coastguard Worker     }
311*e5436536SAndroid Build Coastguard Worker 
312*e5436536SAndroid Build Coastguard Worker     /* shift scale values according to buffer */
313*e5436536SAndroid Build Coastguard Worker     hSbrDec->scale_ov = hSbrDec->scale_lb;
314*e5436536SAndroid Build Coastguard Worker     hSbrDec->scale_lb = hSbrDec->scale_hbe;
315*e5436536SAndroid Build Coastguard Worker 
316*e5436536SAndroid Build Coastguard Worker     /* set pReal to where QMF analysis writes in case of HBE */
317*e5436536SAndroid Build Coastguard Worker     pReal += noCols;
318*e5436536SAndroid Build Coastguard Worker     pImag += noCols;
319*e5436536SAndroid Build Coastguard Worker     if (flags & SBRDEC_SKIP_QMF_ANA) {
320*e5436536SAndroid Build Coastguard Worker       /* stereoCfgIndex3 with HBE */
321*e5436536SAndroid Build Coastguard Worker       FDK_QmfDomain_QmfData2HBE(hSbrDec->qmfDomainInCh,
322*e5436536SAndroid Build Coastguard Worker                                 hSbrDec->hQmfHBESlotsReal,
323*e5436536SAndroid Build Coastguard Worker                                 hSbrDec->hQmfHBESlotsImag);
324*e5436536SAndroid Build Coastguard Worker     } else {
325*e5436536SAndroid Build Coastguard Worker       /* We have to move old hbe frame data to lb area of buffer */
326*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < noCols; i++) {
327*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(pLowBandReal[ov_len + i], hSbrDec->hQmfHBESlotsReal[i],
328*e5436536SAndroid Build Coastguard Worker                   hHeaderData->numberOfAnalysisBands * sizeof(FIXP_DBL));
329*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(pLowBandImag[ov_len + i], hSbrDec->hQmfHBESlotsImag[i],
330*e5436536SAndroid Build Coastguard Worker                   hHeaderData->numberOfAnalysisBands * sizeof(FIXP_DBL));
331*e5436536SAndroid Build Coastguard Worker       }
332*e5436536SAndroid Build Coastguard Worker     }
333*e5436536SAndroid Build Coastguard Worker   }
334*e5436536SAndroid Build Coastguard Worker 
335*e5436536SAndroid Build Coastguard Worker   /*
336*e5436536SAndroid Build Coastguard Worker     low band codec signal subband filtering
337*e5436536SAndroid Build Coastguard Worker    */
338*e5436536SAndroid Build Coastguard Worker 
339*e5436536SAndroid Build Coastguard Worker   if (flags & SBRDEC_SKIP_QMF_ANA) {
340*e5436536SAndroid Build Coastguard Worker     if (!(flags & SBRDEC_USAC_HARMONICSBR)) /* stereoCfgIndex3 w/o HBE */
341*e5436536SAndroid Build Coastguard Worker       FDK_QmfDomain_WorkBuffer2ProcChannel(hSbrDec->qmfDomainInCh);
342*e5436536SAndroid Build Coastguard Worker   } else {
343*e5436536SAndroid Build Coastguard Worker     C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2 * (64));
344*e5436536SAndroid Build Coastguard Worker     qmfAnalysisFiltering(&hSbrDec->qmfDomainInCh->fb, pReal, pImag,
345*e5436536SAndroid Build Coastguard Worker                          &hSbrDec->qmfDomainInCh->scaling, pTimeInQmf,
346*e5436536SAndroid Build Coastguard Worker                          0 + sbrInDataHeadroom, 1, qmfTemp);
347*e5436536SAndroid Build Coastguard Worker 
348*e5436536SAndroid Build Coastguard Worker     C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2 * (64));
349*e5436536SAndroid Build Coastguard Worker   }
350*e5436536SAndroid Build Coastguard Worker 
351*e5436536SAndroid Build Coastguard Worker   /*
352*e5436536SAndroid Build Coastguard Worker     Clear upper half of spectrum
353*e5436536SAndroid Build Coastguard Worker   */
354*e5436536SAndroid Build Coastguard Worker   if (!((flags & SBRDEC_USAC_HARMONICSBR) &&
355*e5436536SAndroid Build Coastguard Worker         (hFrameData->sbrPatchingMode == 0))) {
356*e5436536SAndroid Build Coastguard Worker     int nAnalysisBands = hHeaderData->numberOfAnalysisBands;
357*e5436536SAndroid Build Coastguard Worker 
358*e5436536SAndroid Build Coastguard Worker     if (!(flags & SBRDEC_LOW_POWER)) {
359*e5436536SAndroid Build Coastguard Worker       for (slot = ov_len; slot < noCols + ov_len; slot++) {
360*e5436536SAndroid Build Coastguard Worker         FDKmemclear(&pLowBandReal[slot][nAnalysisBands],
361*e5436536SAndroid Build Coastguard Worker                     ((64) - nAnalysisBands) * sizeof(FIXP_DBL));
362*e5436536SAndroid Build Coastguard Worker         FDKmemclear(&pLowBandImag[slot][nAnalysisBands],
363*e5436536SAndroid Build Coastguard Worker                     ((64) - nAnalysisBands) * sizeof(FIXP_DBL));
364*e5436536SAndroid Build Coastguard Worker       }
365*e5436536SAndroid Build Coastguard Worker     } else {
366*e5436536SAndroid Build Coastguard Worker       for (slot = ov_len; slot < noCols + ov_len; slot++) {
367*e5436536SAndroid Build Coastguard Worker         FDKmemclear(&pLowBandReal[slot][nAnalysisBands],
368*e5436536SAndroid Build Coastguard Worker                     ((64) - nAnalysisBands) * sizeof(FIXP_DBL));
369*e5436536SAndroid Build Coastguard Worker       }
370*e5436536SAndroid Build Coastguard Worker     }
371*e5436536SAndroid Build Coastguard Worker   }
372*e5436536SAndroid Build Coastguard Worker 
373*e5436536SAndroid Build Coastguard Worker   /*
374*e5436536SAndroid Build Coastguard Worker     Shift spectral data left to gain accuracy in transposer and adjustor
375*e5436536SAndroid Build Coastguard Worker   */
376*e5436536SAndroid Build Coastguard Worker   /* Range was increased from lsb to no_channels because in some cases (e.g.
377*e5436536SAndroid Build Coastguard Worker      USAC conf eSbr_4_Pvc.mp4 and some HBE cases) it could be observed that the
378*e5436536SAndroid Build Coastguard Worker      signal between lsb and no_channels is used for the patching process.
379*e5436536SAndroid Build Coastguard Worker   */
380*e5436536SAndroid Build Coastguard Worker   maxVal = maxSubbandSample(pReal, (flags & SBRDEC_LOW_POWER) ? NULL : pImag, 0,
381*e5436536SAndroid Build Coastguard Worker                             hSbrDec->qmfDomainInCh->fb.no_channels, 0, noCols);
382*e5436536SAndroid Build Coastguard Worker 
383*e5436536SAndroid Build Coastguard Worker   reserve = fixMax(0, CntLeadingZeros(maxVal) - 1);
384*e5436536SAndroid Build Coastguard Worker   reserve = fixMin(reserve,
385*e5436536SAndroid Build Coastguard Worker                    DFRACT_BITS - 1 - hSbrDec->qmfDomainInCh->scaling.lb_scale);
386*e5436536SAndroid Build Coastguard Worker 
387*e5436536SAndroid Build Coastguard Worker   /* If all data is zero, lb_scale could become too large */
388*e5436536SAndroid Build Coastguard Worker   rescaleSubbandSamples(pReal, (flags & SBRDEC_LOW_POWER) ? NULL : pImag, 0,
389*e5436536SAndroid Build Coastguard Worker                         hSbrDec->qmfDomainInCh->fb.no_channels, 0, noCols,
390*e5436536SAndroid Build Coastguard Worker                         reserve);
391*e5436536SAndroid Build Coastguard Worker 
392*e5436536SAndroid Build Coastguard Worker   hSbrDec->qmfDomainInCh->scaling.lb_scale += reserve;
393*e5436536SAndroid Build Coastguard Worker 
394*e5436536SAndroid Build Coastguard Worker   if ((flags & SBRDEC_USAC_HARMONICSBR)) {
395*e5436536SAndroid Build Coastguard Worker     /* actually this is our hbe_scale */
396*e5436536SAndroid Build Coastguard Worker     hSbrDec->scale_hbe = hSbrDec->qmfDomainInCh->scaling.lb_scale;
397*e5436536SAndroid Build Coastguard Worker     /* the real lb_scale is stored in scale_lb from sbr */
398*e5436536SAndroid Build Coastguard Worker     hSbrDec->qmfDomainInCh->scaling.lb_scale = hSbrDec->scale_lb;
399*e5436536SAndroid Build Coastguard Worker   }
400*e5436536SAndroid Build Coastguard Worker   /*
401*e5436536SAndroid Build Coastguard Worker     save low band scale, wavecoding or parametric stereo may modify it
402*e5436536SAndroid Build Coastguard Worker   */
403*e5436536SAndroid Build Coastguard Worker   saveLbScale = hSbrDec->qmfDomainInCh->scaling.lb_scale;
404*e5436536SAndroid Build Coastguard Worker 
405*e5436536SAndroid Build Coastguard Worker   if (applyProcessing) {
406*e5436536SAndroid Build Coastguard Worker     UCHAR *borders = hFrameData->frameInfo.borders;
407*e5436536SAndroid Build Coastguard Worker     lastSlotOffs = borders[hFrameData->frameInfo.nEnvelopes] -
408*e5436536SAndroid Build Coastguard Worker                    hHeaderData->numberTimeSlots;
409*e5436536SAndroid Build Coastguard Worker 
410*e5436536SAndroid Build Coastguard Worker     FIXP_DBL degreeAlias[(64)];
411*e5436536SAndroid Build Coastguard Worker     PVC_DYNAMIC_DATA pvcDynamicData;
412*e5436536SAndroid Build Coastguard Worker     pvcInitFrame(
413*e5436536SAndroid Build Coastguard Worker         &hSbrDec->PvcStaticData, &pvcDynamicData,
414*e5436536SAndroid Build Coastguard Worker         (hHeaderData->frameErrorFlag ? 0 : hHeaderData->bs_info.pvc_mode),
415*e5436536SAndroid Build Coastguard Worker         hFrameData->ns, hHeaderData->timeStep,
416*e5436536SAndroid Build Coastguard Worker         hHeaderData->freqBandData.lowSubband,
417*e5436536SAndroid Build Coastguard Worker         hFrameData->frameInfo.pvcBorders[0], hFrameData->pvcID);
418*e5436536SAndroid Build Coastguard Worker 
419*e5436536SAndroid Build Coastguard Worker     if (!hHeaderData->frameErrorFlag && (hHeaderData->bs_info.pvc_mode > 0)) {
420*e5436536SAndroid Build Coastguard Worker       pvcDecodeFrame(&hSbrDec->PvcStaticData, &pvcDynamicData, pLowBandReal,
421*e5436536SAndroid Build Coastguard Worker                      pLowBandImag, ov_len,
422*e5436536SAndroid Build Coastguard Worker                      SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale),
423*e5436536SAndroid Build Coastguard Worker                      SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.lb_scale));
424*e5436536SAndroid Build Coastguard Worker     }
425*e5436536SAndroid Build Coastguard Worker     pvcEndFrame(&hSbrDec->PvcStaticData, &pvcDynamicData);
426*e5436536SAndroid Build Coastguard Worker 
427*e5436536SAndroid Build Coastguard Worker     /* The transposer will override most values in degreeAlias[].
428*e5436536SAndroid Build Coastguard Worker        The array needs to be cleared at least from lowSubband to highSubband
429*e5436536SAndroid Build Coastguard Worker        before. */
430*e5436536SAndroid Build Coastguard Worker     if (flags & SBRDEC_LOW_POWER)
431*e5436536SAndroid Build Coastguard Worker       FDKmemclear(&degreeAlias[hHeaderData->freqBandData.lowSubband],
432*e5436536SAndroid Build Coastguard Worker                   (hHeaderData->freqBandData.highSubband -
433*e5436536SAndroid Build Coastguard Worker                    hHeaderData->freqBandData.lowSubband) *
434*e5436536SAndroid Build Coastguard Worker                       sizeof(FIXP_DBL));
435*e5436536SAndroid Build Coastguard Worker 
436*e5436536SAndroid Build Coastguard Worker     /*
437*e5436536SAndroid Build Coastguard Worker       Inverse filtering of lowband and transposition into the SBR-frequency
438*e5436536SAndroid Build Coastguard Worker       range
439*e5436536SAndroid Build Coastguard Worker     */
440*e5436536SAndroid Build Coastguard Worker 
441*e5436536SAndroid Build Coastguard Worker     {
442*e5436536SAndroid Build Coastguard Worker       KEEP_STATES_SYNCED_MODE keepStatesSyncedMode =
443*e5436536SAndroid Build Coastguard Worker           ((flags & SBRDEC_USAC_HARMONICSBR) &&
444*e5436536SAndroid Build Coastguard Worker            (hFrameData->sbrPatchingMode != 0))
445*e5436536SAndroid Build Coastguard Worker               ? KEEP_STATES_SYNCED_NORMAL
446*e5436536SAndroid Build Coastguard Worker               : KEEP_STATES_SYNCED_OFF;
447*e5436536SAndroid Build Coastguard Worker 
448*e5436536SAndroid Build Coastguard Worker       if (flags & SBRDEC_USAC_HARMONICSBR) {
449*e5436536SAndroid Build Coastguard Worker         if (flags & SBRDEC_QUAD_RATE) {
450*e5436536SAndroid Build Coastguard Worker           pReal -= 32;
451*e5436536SAndroid Build Coastguard Worker           pImag -= 32;
452*e5436536SAndroid Build Coastguard Worker         }
453*e5436536SAndroid Build Coastguard Worker 
454*e5436536SAndroid Build Coastguard Worker         if ((hSbrDec->savedStates == 0) && (hFrameData->sbrPatchingMode == 1)) {
455*e5436536SAndroid Build Coastguard Worker           /* copy saved states from previous frame to legacy SBR lpc filterstate
456*e5436536SAndroid Build Coastguard Worker            * buffer   */
457*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < LPC_ORDER + ov_len; i++) {
458*e5436536SAndroid Build Coastguard Worker             FDKmemcpy(
459*e5436536SAndroid Build Coastguard Worker                 hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
460*e5436536SAndroid Build Coastguard Worker                 hSbrDec->codecQMFBufferReal[noCols - LPC_ORDER - ov_len + i],
461*e5436536SAndroid Build Coastguard Worker                 hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
462*e5436536SAndroid Build Coastguard Worker             FDKmemcpy(
463*e5436536SAndroid Build Coastguard Worker                 hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i],
464*e5436536SAndroid Build Coastguard Worker                 hSbrDec->codecQMFBufferImag[noCols - LPC_ORDER - ov_len + i],
465*e5436536SAndroid Build Coastguard Worker                 hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
466*e5436536SAndroid Build Coastguard Worker           }
467*e5436536SAndroid Build Coastguard Worker         }
468*e5436536SAndroid Build Coastguard Worker 
469*e5436536SAndroid Build Coastguard Worker         /* saving unmodified QMF states in case we are switching from legacy SBR
470*e5436536SAndroid Build Coastguard Worker          * to HBE */
471*e5436536SAndroid Build Coastguard Worker         for (i = 0; i < hSbrDec->hHBE->noCols; i++) {
472*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(hSbrDec->codecQMFBufferReal[i], pLowBandReal[ov_len + i],
473*e5436536SAndroid Build Coastguard Worker                     hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
474*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(hSbrDec->codecQMFBufferImag[i], pLowBandImag[ov_len + i],
475*e5436536SAndroid Build Coastguard Worker                     hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
476*e5436536SAndroid Build Coastguard Worker         }
477*e5436536SAndroid Build Coastguard Worker 
478*e5436536SAndroid Build Coastguard Worker         QmfTransposerApply(
479*e5436536SAndroid Build Coastguard Worker             hSbrDec->hHBE, pReal, pImag, noCols, pLowBandReal, pLowBandImag,
480*e5436536SAndroid Build Coastguard Worker             hSbrDec->LppTrans.lpcFilterStatesRealHBE,
481*e5436536SAndroid Build Coastguard Worker             hSbrDec->LppTrans.lpcFilterStatesImagHBE,
482*e5436536SAndroid Build Coastguard Worker             hFrameData->sbrPitchInBins, hSbrDec->scale_lb, hSbrDec->scale_hbe,
483*e5436536SAndroid Build Coastguard Worker             &hSbrDec->qmfDomainInCh->scaling.hb_scale, hHeaderData->timeStep,
484*e5436536SAndroid Build Coastguard Worker             borders[0], ov_len, keepStatesSyncedMode);
485*e5436536SAndroid Build Coastguard Worker 
486*e5436536SAndroid Build Coastguard Worker         if (flags & SBRDEC_QUAD_RATE) {
487*e5436536SAndroid Build Coastguard Worker           int *xOverQmf = GetxOverBandQmfTransposer(hSbrDec->hHBE);
488*e5436536SAndroid Build Coastguard Worker 
489*e5436536SAndroid Build Coastguard Worker           copyHarmonicSpectrum(xOverQmf, pLowBandReal, pLowBandImag, noCols,
490*e5436536SAndroid Build Coastguard Worker                                ov_len, keepStatesSyncedMode);
491*e5436536SAndroid Build Coastguard Worker         }
492*e5436536SAndroid Build Coastguard Worker       }
493*e5436536SAndroid Build Coastguard Worker     }
494*e5436536SAndroid Build Coastguard Worker 
495*e5436536SAndroid Build Coastguard Worker     if ((flags & SBRDEC_USAC_HARMONICSBR) &&
496*e5436536SAndroid Build Coastguard Worker         (hFrameData->sbrPatchingMode == 0)) {
497*e5436536SAndroid Build Coastguard Worker       hSbrDec->prev_frame_lSbr = 0;
498*e5436536SAndroid Build Coastguard Worker       hSbrDec->prev_frame_hbeSbr = 1;
499*e5436536SAndroid Build Coastguard Worker 
500*e5436536SAndroid Build Coastguard Worker       lppTransposerHBE(
501*e5436536SAndroid Build Coastguard Worker           &hSbrDec->LppTrans, hSbrDec->hHBE, &hSbrDec->qmfDomainInCh->scaling,
502*e5436536SAndroid Build Coastguard Worker           pLowBandReal, pLowBandImag, hHeaderData->timeStep, borders[0],
503*e5436536SAndroid Build Coastguard Worker           lastSlotOffs, hHeaderData->freqBandData.nInvfBands,
504*e5436536SAndroid Build Coastguard Worker           hFrameData->sbr_invf_mode, hPrevFrameData->sbr_invf_mode);
505*e5436536SAndroid Build Coastguard Worker 
506*e5436536SAndroid Build Coastguard Worker     } else {
507*e5436536SAndroid Build Coastguard Worker       if (flags & SBRDEC_USAC_HARMONICSBR) {
508*e5436536SAndroid Build Coastguard Worker         for (i = 0; i < LPC_ORDER + hSbrDec->LppTrans.pSettings->overlap; i++) {
509*e5436536SAndroid Build Coastguard Worker           /*
510*e5436536SAndroid Build Coastguard Worker           Store the unmodified qmf Slots values for upper part of spectrum
511*e5436536SAndroid Build Coastguard Worker           (required for LPC filtering) required if next frame is a HBE frame
512*e5436536SAndroid Build Coastguard Worker           */
513*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesRealHBE[i],
514*e5436536SAndroid Build Coastguard Worker                     hSbrDec->qmfDomainInCh
515*e5436536SAndroid Build Coastguard Worker                         ->hQmfSlotsReal[hSbrDec->hHBE->noCols - LPC_ORDER + i],
516*e5436536SAndroid Build Coastguard Worker                     (64) * sizeof(FIXP_DBL));
517*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesImagHBE[i],
518*e5436536SAndroid Build Coastguard Worker                     hSbrDec->qmfDomainInCh
519*e5436536SAndroid Build Coastguard Worker                         ->hQmfSlotsImag[hSbrDec->hHBE->noCols - LPC_ORDER + i],
520*e5436536SAndroid Build Coastguard Worker                     (64) * sizeof(FIXP_DBL));
521*e5436536SAndroid Build Coastguard Worker         }
522*e5436536SAndroid Build Coastguard Worker       }
523*e5436536SAndroid Build Coastguard Worker       {
524*e5436536SAndroid Build Coastguard Worker         hSbrDec->prev_frame_lSbr = 1;
525*e5436536SAndroid Build Coastguard Worker         hSbrDec->prev_frame_hbeSbr = 0;
526*e5436536SAndroid Build Coastguard Worker       }
527*e5436536SAndroid Build Coastguard Worker 
528*e5436536SAndroid Build Coastguard Worker       lppTransposer(
529*e5436536SAndroid Build Coastguard Worker           &hSbrDec->LppTrans, &hSbrDec->qmfDomainInCh->scaling, pLowBandReal,
530*e5436536SAndroid Build Coastguard Worker           degreeAlias,  // only used if useLP = 1
531*e5436536SAndroid Build Coastguard Worker           pLowBandImag, flags & SBRDEC_LOW_POWER,
532*e5436536SAndroid Build Coastguard Worker           hHeaderData->bs_info.sbr_preprocessing,
533*e5436536SAndroid Build Coastguard Worker           hHeaderData->freqBandData.v_k_master[0], hHeaderData->timeStep,
534*e5436536SAndroid Build Coastguard Worker           borders[0], lastSlotOffs, hHeaderData->freqBandData.nInvfBands,
535*e5436536SAndroid Build Coastguard Worker           hFrameData->sbr_invf_mode, hPrevFrameData->sbr_invf_mode);
536*e5436536SAndroid Build Coastguard Worker     }
537*e5436536SAndroid Build Coastguard Worker 
538*e5436536SAndroid Build Coastguard Worker     /*
539*e5436536SAndroid Build Coastguard Worker       Adjust envelope of current frame.
540*e5436536SAndroid Build Coastguard Worker     */
541*e5436536SAndroid Build Coastguard Worker 
542*e5436536SAndroid Build Coastguard Worker     if ((hFrameData->sbrPatchingMode !=
543*e5436536SAndroid Build Coastguard Worker          hSbrDec->SbrCalculateEnvelope.sbrPatchingMode)) {
544*e5436536SAndroid Build Coastguard Worker       ResetLimiterBands(hHeaderData->freqBandData.limiterBandTable,
545*e5436536SAndroid Build Coastguard Worker                         &hHeaderData->freqBandData.noLimiterBands,
546*e5436536SAndroid Build Coastguard Worker                         hHeaderData->freqBandData.freqBandTable[0],
547*e5436536SAndroid Build Coastguard Worker                         hHeaderData->freqBandData.nSfb[0],
548*e5436536SAndroid Build Coastguard Worker                         hSbrDec->LppTrans.pSettings->patchParam,
549*e5436536SAndroid Build Coastguard Worker                         hSbrDec->LppTrans.pSettings->noOfPatches,
550*e5436536SAndroid Build Coastguard Worker                         hHeaderData->bs_data.limiterBands,
551*e5436536SAndroid Build Coastguard Worker                         hFrameData->sbrPatchingMode,
552*e5436536SAndroid Build Coastguard Worker                         (flags & SBRDEC_USAC_HARMONICSBR) &&
553*e5436536SAndroid Build Coastguard Worker                                 (hFrameData->sbrPatchingMode == 0)
554*e5436536SAndroid Build Coastguard Worker                             ? GetxOverBandQmfTransposer(hSbrDec->hHBE)
555*e5436536SAndroid Build Coastguard Worker                             : NULL,
556*e5436536SAndroid Build Coastguard Worker                         Get41SbrQmfTransposer(hSbrDec->hHBE));
557*e5436536SAndroid Build Coastguard Worker 
558*e5436536SAndroid Build Coastguard Worker       hSbrDec->SbrCalculateEnvelope.sbrPatchingMode =
559*e5436536SAndroid Build Coastguard Worker           hFrameData->sbrPatchingMode;
560*e5436536SAndroid Build Coastguard Worker     }
561*e5436536SAndroid Build Coastguard Worker 
562*e5436536SAndroid Build Coastguard Worker     calculateSbrEnvelope(
563*e5436536SAndroid Build Coastguard Worker         &hSbrDec->qmfDomainInCh->scaling, &hSbrDec->SbrCalculateEnvelope,
564*e5436536SAndroid Build Coastguard Worker         hHeaderData, hFrameData, &pvcDynamicData, pLowBandReal, pLowBandImag,
565*e5436536SAndroid Build Coastguard Worker         flags & SBRDEC_LOW_POWER,
566*e5436536SAndroid Build Coastguard Worker 
567*e5436536SAndroid Build Coastguard Worker         degreeAlias, flags,
568*e5436536SAndroid Build Coastguard Worker         (hHeaderData->frameErrorFlag || hPrevFrameData->frameErrorFlag));
569*e5436536SAndroid Build Coastguard Worker 
570*e5436536SAndroid Build Coastguard Worker #if (SBRDEC_MAX_HB_FADE_FRAMES > 0)
571*e5436536SAndroid Build Coastguard Worker     /* Avoid hard onsets of high band */
572*e5436536SAndroid Build Coastguard Worker     if (hHeaderData->frameErrorFlag) {
573*e5436536SAndroid Build Coastguard Worker       if (hSbrDec->highBandFadeCnt < SBRDEC_MAX_HB_FADE_FRAMES) {
574*e5436536SAndroid Build Coastguard Worker         hSbrDec->highBandFadeCnt += 1;
575*e5436536SAndroid Build Coastguard Worker       }
576*e5436536SAndroid Build Coastguard Worker     } else {
577*e5436536SAndroid Build Coastguard Worker       if (hSbrDec->highBandFadeCnt >
578*e5436536SAndroid Build Coastguard Worker           0) { /* Manipulate high band scale factor to get a smooth fade-in */
579*e5436536SAndroid Build Coastguard Worker         hSbrDec->qmfDomainInCh->scaling.hb_scale += hSbrDec->highBandFadeCnt;
580*e5436536SAndroid Build Coastguard Worker         hSbrDec->qmfDomainInCh->scaling.hb_scale =
581*e5436536SAndroid Build Coastguard Worker             fMin(hSbrDec->qmfDomainInCh->scaling.hb_scale, DFRACT_BITS - 1);
582*e5436536SAndroid Build Coastguard Worker         hSbrDec->highBandFadeCnt -= 1;
583*e5436536SAndroid Build Coastguard Worker       }
584*e5436536SAndroid Build Coastguard Worker     }
585*e5436536SAndroid Build Coastguard Worker 
586*e5436536SAndroid Build Coastguard Worker #endif
587*e5436536SAndroid Build Coastguard Worker     /*
588*e5436536SAndroid Build Coastguard Worker       Update hPrevFrameData (to be used in the next frame)
589*e5436536SAndroid Build Coastguard Worker     */
590*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < hHeaderData->freqBandData.nInvfBands; i++) {
591*e5436536SAndroid Build Coastguard Worker       hPrevFrameData->sbr_invf_mode[i] = hFrameData->sbr_invf_mode[i];
592*e5436536SAndroid Build Coastguard Worker     }
593*e5436536SAndroid Build Coastguard Worker     hPrevFrameData->coupling = hFrameData->coupling;
594*e5436536SAndroid Build Coastguard Worker     hPrevFrameData->stopPos = borders[hFrameData->frameInfo.nEnvelopes];
595*e5436536SAndroid Build Coastguard Worker     hPrevFrameData->ampRes = hFrameData->ampResolutionCurrentFrame;
596*e5436536SAndroid Build Coastguard Worker     hPrevFrameData->prevSbrPitchInBins = hFrameData->sbrPitchInBins;
597*e5436536SAndroid Build Coastguard Worker     /* could be done in extractFrameInfo_pvc() but hPrevFrameData is not
598*e5436536SAndroid Build Coastguard Worker      * available there */
599*e5436536SAndroid Build Coastguard Worker     FDKmemcpy(&hPrevFrameData->prevFrameInfo, &hFrameData->frameInfo,
600*e5436536SAndroid Build Coastguard Worker               sizeof(FRAME_INFO));
601*e5436536SAndroid Build Coastguard Worker   } else {
602*e5436536SAndroid Build Coastguard Worker     /* rescale from lsb to nAnalysisBands in order to compensate scaling with
603*e5436536SAndroid Build Coastguard Worker      * hb_scale in this area, done by synthesisFiltering*/
604*e5436536SAndroid Build Coastguard Worker     int rescale;
605*e5436536SAndroid Build Coastguard Worker     int lsb;
606*e5436536SAndroid Build Coastguard Worker     int length;
607*e5436536SAndroid Build Coastguard Worker 
608*e5436536SAndroid Build Coastguard Worker     /* Reset hb_scale if no highband is present, because hb_scale is considered
609*e5436536SAndroid Build Coastguard Worker      * in the QMF-synthesis */
610*e5436536SAndroid Build Coastguard Worker     hSbrDec->qmfDomainInCh->scaling.hb_scale = saveLbScale;
611*e5436536SAndroid Build Coastguard Worker 
612*e5436536SAndroid Build Coastguard Worker     rescale = hSbrDec->qmfDomainInCh->scaling.hb_scale -
613*e5436536SAndroid Build Coastguard Worker               hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
614*e5436536SAndroid Build Coastguard Worker     lsb = hSbrDec->qmfDomainOutCh->fb.lsb;
615*e5436536SAndroid Build Coastguard Worker     length = (hSbrDec->qmfDomainInCh->fb.no_channels - lsb);
616*e5436536SAndroid Build Coastguard Worker 
617*e5436536SAndroid Build Coastguard Worker     if ((rescale < 0) && (length > 0)) {
618*e5436536SAndroid Build Coastguard Worker       if (!(flags & SBRDEC_LOW_POWER)) {
619*e5436536SAndroid Build Coastguard Worker         for (i = 0; i < ov_len; i++) {
620*e5436536SAndroid Build Coastguard Worker           scaleValues(&pLowBandReal[i][lsb], length, rescale);
621*e5436536SAndroid Build Coastguard Worker           scaleValues(&pLowBandImag[i][lsb], length, rescale);
622*e5436536SAndroid Build Coastguard Worker         }
623*e5436536SAndroid Build Coastguard Worker       } else {
624*e5436536SAndroid Build Coastguard Worker         for (i = 0; i < ov_len; i++) {
625*e5436536SAndroid Build Coastguard Worker           scaleValues(&pLowBandReal[i][lsb], length, rescale);
626*e5436536SAndroid Build Coastguard Worker         }
627*e5436536SAndroid Build Coastguard Worker       }
628*e5436536SAndroid Build Coastguard Worker     }
629*e5436536SAndroid Build Coastguard Worker   }
630*e5436536SAndroid Build Coastguard Worker 
631*e5436536SAndroid Build Coastguard Worker   if (!(flags & SBRDEC_USAC_HARMONICSBR)) {
632*e5436536SAndroid Build Coastguard Worker     int length = hSbrDec->qmfDomainInCh->fb.lsb;
633*e5436536SAndroid Build Coastguard Worker     if (flags & SBRDEC_SYNTAX_USAC) {
634*e5436536SAndroid Build Coastguard Worker       length = hSbrDec->qmfDomainInCh->fb.no_channels;
635*e5436536SAndroid Build Coastguard Worker     }
636*e5436536SAndroid Build Coastguard Worker 
637*e5436536SAndroid Build Coastguard Worker     /* in case of legacy sbr saving of filter states here */
638*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < LPC_ORDER + ov_len; i++) {
639*e5436536SAndroid Build Coastguard Worker       /*
640*e5436536SAndroid Build Coastguard Worker         Store the unmodified qmf Slots values (required for LPC filtering)
641*e5436536SAndroid Build Coastguard Worker       */
642*e5436536SAndroid Build Coastguard Worker       if (!(flags & SBRDEC_LOW_POWER)) {
643*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
644*e5436536SAndroid Build Coastguard Worker                   pLowBandReal[noCols - LPC_ORDER + i],
645*e5436536SAndroid Build Coastguard Worker                   length * sizeof(FIXP_DBL));
646*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i],
647*e5436536SAndroid Build Coastguard Worker                   pLowBandImag[noCols - LPC_ORDER + i],
648*e5436536SAndroid Build Coastguard Worker                   length * sizeof(FIXP_DBL));
649*e5436536SAndroid Build Coastguard Worker       } else
650*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
651*e5436536SAndroid Build Coastguard Worker                   pLowBandReal[noCols - LPC_ORDER + i],
652*e5436536SAndroid Build Coastguard Worker                   length * sizeof(FIXP_DBL));
653*e5436536SAndroid Build Coastguard Worker     }
654*e5436536SAndroid Build Coastguard Worker   }
655*e5436536SAndroid Build Coastguard Worker 
656*e5436536SAndroid Build Coastguard Worker   /*
657*e5436536SAndroid Build Coastguard Worker     Synthesis subband filtering.
658*e5436536SAndroid Build Coastguard Worker   */
659*e5436536SAndroid Build Coastguard Worker 
660*e5436536SAndroid Build Coastguard Worker   if (!(flags & SBRDEC_PS_DECODED)) {
661*e5436536SAndroid Build Coastguard Worker     if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
662*e5436536SAndroid Build Coastguard Worker       int outScalefactor = -(8);
663*e5436536SAndroid Build Coastguard Worker 
664*e5436536SAndroid Build Coastguard Worker       if (h_ps_d != NULL) {
665*e5436536SAndroid Build Coastguard Worker         h_ps_d->procFrameBased = 1; /* we here do frame based processing */
666*e5436536SAndroid Build Coastguard Worker       }
667*e5436536SAndroid Build Coastguard Worker 
668*e5436536SAndroid Build Coastguard Worker       sbrDecoder_drcApply(&hSbrDec->sbrDrcChannel, pLowBandReal,
669*e5436536SAndroid Build Coastguard Worker                           (flags & SBRDEC_LOW_POWER) ? NULL : pLowBandImag,
670*e5436536SAndroid Build Coastguard Worker                           hSbrDec->qmfDomainOutCh->fb.no_col, &outScalefactor);
671*e5436536SAndroid Build Coastguard Worker 
672*e5436536SAndroid Build Coastguard Worker       qmfChangeOutScalefactor(&hSbrDec->qmfDomainOutCh->fb, outScalefactor);
673*e5436536SAndroid Build Coastguard Worker 
674*e5436536SAndroid Build Coastguard Worker       {
675*e5436536SAndroid Build Coastguard Worker         HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData;
676*e5436536SAndroid Build Coastguard Worker         int save_usb = hSbrDec->qmfDomainOutCh->fb.usb;
677*e5436536SAndroid Build Coastguard Worker 
678*e5436536SAndroid Build Coastguard Worker #if (QMF_MAX_SYNTHESIS_BANDS <= 64)
679*e5436536SAndroid Build Coastguard Worker         C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
680*e5436536SAndroid Build Coastguard Worker #else
681*e5436536SAndroid Build Coastguard Worker         C_AALLOC_STACK_START(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
682*e5436536SAndroid Build Coastguard Worker #endif
683*e5436536SAndroid Build Coastguard Worker         if (hSbrDec->qmfDomainOutCh->fb.usb < hFreq->ov_highSubband) {
684*e5436536SAndroid Build Coastguard Worker           /* we need to patch usb for this frame as overlap may contain higher
685*e5436536SAndroid Build Coastguard Worker              frequency range if headerchange occured; fb. usb is always limited
686*e5436536SAndroid Build Coastguard Worker              to maximum fb.no_channels; In case of wrongly decoded headers it
687*e5436536SAndroid Build Coastguard Worker              might be that ov_highSubband is higher than the number of synthesis
688*e5436536SAndroid Build Coastguard Worker              channels (fb.no_channels), which is forbidden, therefore we need to
689*e5436536SAndroid Build Coastguard Worker              limit ov_highSubband with fMin function to avoid not allowed usb in
690*e5436536SAndroid Build Coastguard Worker              synthesis filterbank. */
691*e5436536SAndroid Build Coastguard Worker           hSbrDec->qmfDomainOutCh->fb.usb =
692*e5436536SAndroid Build Coastguard Worker               fMin((UINT)hFreq->ov_highSubband,
693*e5436536SAndroid Build Coastguard Worker                    (UINT)hSbrDec->qmfDomainOutCh->fb.no_channels);
694*e5436536SAndroid Build Coastguard Worker         }
695*e5436536SAndroid Build Coastguard Worker         {
696*e5436536SAndroid Build Coastguard Worker           qmfSynthesisFiltering(
697*e5436536SAndroid Build Coastguard Worker               &hSbrDec->qmfDomainOutCh->fb, pLowBandReal,
698*e5436536SAndroid Build Coastguard Worker               (flags & SBRDEC_LOW_POWER) ? NULL : pLowBandImag,
699*e5436536SAndroid Build Coastguard Worker               &hSbrDec->qmfDomainInCh->scaling,
700*e5436536SAndroid Build Coastguard Worker               hSbrDec->LppTrans.pSettings->overlap, timeOut, strideOut,
701*e5436536SAndroid Build Coastguard Worker               qmfTemp);
702*e5436536SAndroid Build Coastguard Worker         }
703*e5436536SAndroid Build Coastguard Worker         /* restore saved value */
704*e5436536SAndroid Build Coastguard Worker         hSbrDec->qmfDomainOutCh->fb.usb = save_usb;
705*e5436536SAndroid Build Coastguard Worker         hFreq->ov_highSubband = save_usb;
706*e5436536SAndroid Build Coastguard Worker #if (QMF_MAX_SYNTHESIS_BANDS <= 64)
707*e5436536SAndroid Build Coastguard Worker         C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
708*e5436536SAndroid Build Coastguard Worker #else
709*e5436536SAndroid Build Coastguard Worker         C_AALLOC_STACK_END(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
710*e5436536SAndroid Build Coastguard Worker #endif
711*e5436536SAndroid Build Coastguard Worker       }
712*e5436536SAndroid Build Coastguard Worker     }
713*e5436536SAndroid Build Coastguard Worker 
714*e5436536SAndroid Build Coastguard Worker   } else { /* (flags & SBRDEC_PS_DECODED) */
715*e5436536SAndroid Build Coastguard Worker     INT sdiff;
716*e5436536SAndroid Build Coastguard Worker     INT scaleFactorHighBand, scaleFactorLowBand_ov, scaleFactorLowBand_no_ov,
717*e5436536SAndroid Build Coastguard Worker         outScalefactor, outScalefactorR, outScalefactorL;
718*e5436536SAndroid Build Coastguard Worker 
719*e5436536SAndroid Build Coastguard Worker     HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->qmfDomainOutCh->fb;
720*e5436536SAndroid Build Coastguard Worker     HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->qmfDomainOutCh->fb;
721*e5436536SAndroid Build Coastguard Worker 
722*e5436536SAndroid Build Coastguard Worker     /* adapt scaling */
723*e5436536SAndroid Build Coastguard Worker     sdiff = hSbrDec->qmfDomainInCh->scaling.lb_scale -
724*e5436536SAndroid Build Coastguard Worker             reserve; /* Scaling difference */
725*e5436536SAndroid Build Coastguard Worker     scaleFactorHighBand = sdiff - hSbrDec->qmfDomainInCh->scaling.hb_scale;
726*e5436536SAndroid Build Coastguard Worker     scaleFactorLowBand_ov = sdiff - hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
727*e5436536SAndroid Build Coastguard Worker     scaleFactorLowBand_no_ov = sdiff - hSbrDec->qmfDomainInCh->scaling.lb_scale;
728*e5436536SAndroid Build Coastguard Worker 
729*e5436536SAndroid Build Coastguard Worker     /* Scale of low band overlapping QMF data */
730*e5436536SAndroid Build Coastguard Worker     scaleFactorLowBand_ov =
731*e5436536SAndroid Build Coastguard Worker         fMin(DFRACT_BITS - 1, fMax(-(DFRACT_BITS - 1), scaleFactorLowBand_ov));
732*e5436536SAndroid Build Coastguard Worker     /* Scale of low band current QMF data     */
733*e5436536SAndroid Build Coastguard Worker     scaleFactorLowBand_no_ov = fMin(
734*e5436536SAndroid Build Coastguard Worker         DFRACT_BITS - 1, fMax(-(DFRACT_BITS - 1), scaleFactorLowBand_no_ov));
735*e5436536SAndroid Build Coastguard Worker     /* Scale of current high band */
736*e5436536SAndroid Build Coastguard Worker     scaleFactorHighBand =
737*e5436536SAndroid Build Coastguard Worker         fMin(DFRACT_BITS - 1, fMax(-(DFRACT_BITS - 1), scaleFactorHighBand));
738*e5436536SAndroid Build Coastguard Worker 
739*e5436536SAndroid Build Coastguard Worker     if (h_ps_d->procFrameBased == 1) /* If we have switched from frame to slot
740*e5436536SAndroid Build Coastguard Worker                                         based processing copy filter states */
741*e5436536SAndroid Build Coastguard Worker     {                                /* procFrameBased will be unset later */
742*e5436536SAndroid Build Coastguard Worker       /* copy filter states from left to right */
743*e5436536SAndroid Build Coastguard Worker       /* was ((640)-(64))*sizeof(FIXP_QSS)
744*e5436536SAndroid Build Coastguard Worker          flexible amount of synthesis bands needed for QMF based resampling
745*e5436536SAndroid Build Coastguard Worker       */
746*e5436536SAndroid Build Coastguard Worker       FDK_ASSERT(hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis <=
747*e5436536SAndroid Build Coastguard Worker                  QMF_MAX_SYNTHESIS_BANDS);
748*e5436536SAndroid Build Coastguard Worker       synQmfRight->outScalefactor = synQmf->outScalefactor;
749*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates,
750*e5436536SAndroid Build Coastguard Worker                 9 * hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis *
751*e5436536SAndroid Build Coastguard Worker                     sizeof(FIXP_QSS));
752*e5436536SAndroid Build Coastguard Worker     }
753*e5436536SAndroid Build Coastguard Worker 
754*e5436536SAndroid Build Coastguard Worker     /* Feed delaylines when parametric stereo is switched on. */
755*e5436536SAndroid Build Coastguard Worker     PreparePsProcessing(h_ps_d, pLowBandReal, pLowBandImag,
756*e5436536SAndroid Build Coastguard Worker                         scaleFactorLowBand_ov);
757*e5436536SAndroid Build Coastguard Worker 
758*e5436536SAndroid Build Coastguard Worker     /* use the same synthese qmf values for left and right channel */
759*e5436536SAndroid Build Coastguard Worker     synQmfRight->no_col = synQmf->no_col;
760*e5436536SAndroid Build Coastguard Worker     synQmfRight->lsb = synQmf->lsb;
761*e5436536SAndroid Build Coastguard Worker     synQmfRight->usb = synQmf->usb;
762*e5436536SAndroid Build Coastguard Worker 
763*e5436536SAndroid Build Coastguard Worker     int env = 0;
764*e5436536SAndroid Build Coastguard Worker 
765*e5436536SAndroid Build Coastguard Worker     {
766*e5436536SAndroid Build Coastguard Worker #if (QMF_MAX_SYNTHESIS_BANDS <= 64)
767*e5436536SAndroid Build Coastguard Worker       C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL,
768*e5436536SAndroid Build Coastguard Worker                              2 * QMF_MAX_SYNTHESIS_BANDS);
769*e5436536SAndroid Build Coastguard Worker #else
770*e5436536SAndroid Build Coastguard Worker       C_AALLOC_STACK_START(pWorkBuffer, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
771*e5436536SAndroid Build Coastguard Worker #endif
772*e5436536SAndroid Build Coastguard Worker 
773*e5436536SAndroid Build Coastguard Worker       int maxShift = 0;
774*e5436536SAndroid Build Coastguard Worker 
775*e5436536SAndroid Build Coastguard Worker       if (hSbrDec->sbrDrcChannel.enable != 0) {
776*e5436536SAndroid Build Coastguard Worker         if (hSbrDec->sbrDrcChannel.prevFact_exp > maxShift) {
777*e5436536SAndroid Build Coastguard Worker           maxShift = hSbrDec->sbrDrcChannel.prevFact_exp;
778*e5436536SAndroid Build Coastguard Worker         }
779*e5436536SAndroid Build Coastguard Worker         if (hSbrDec->sbrDrcChannel.currFact_exp > maxShift) {
780*e5436536SAndroid Build Coastguard Worker           maxShift = hSbrDec->sbrDrcChannel.currFact_exp;
781*e5436536SAndroid Build Coastguard Worker         }
782*e5436536SAndroid Build Coastguard Worker         if (hSbrDec->sbrDrcChannel.nextFact_exp > maxShift) {
783*e5436536SAndroid Build Coastguard Worker           maxShift = hSbrDec->sbrDrcChannel.nextFact_exp;
784*e5436536SAndroid Build Coastguard Worker         }
785*e5436536SAndroid Build Coastguard Worker       }
786*e5436536SAndroid Build Coastguard Worker 
787*e5436536SAndroid Build Coastguard Worker       /* copy DRC data to right channel (with PS both channels use the same DRC
788*e5436536SAndroid Build Coastguard Worker        * gains) */
789*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(&hSbrDecRight->sbrDrcChannel, &hSbrDec->sbrDrcChannel,
790*e5436536SAndroid Build Coastguard Worker                 sizeof(SBRDEC_DRC_CHANNEL));
791*e5436536SAndroid Build Coastguard Worker 
792*e5436536SAndroid Build Coastguard Worker       outScalefactor = maxShift - (8);
793*e5436536SAndroid Build Coastguard Worker       outScalefactorL = outScalefactorR =
794*e5436536SAndroid Build Coastguard Worker           sbrInDataHeadroom + 1; /* +1: psDiffScale! (MPEG-PS) */
795*e5436536SAndroid Build Coastguard Worker 
796*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */
797*e5436536SAndroid Build Coastguard Worker 
798*e5436536SAndroid Build Coastguard Worker         /* qmf timeslot of right channel */
799*e5436536SAndroid Build Coastguard Worker         FIXP_DBL *rQmfReal = pWorkBuffer;
800*e5436536SAndroid Build Coastguard Worker         FIXP_DBL *rQmfImag = pWorkBuffer + synQmf->no_channels;
801*e5436536SAndroid Build Coastguard Worker 
802*e5436536SAndroid Build Coastguard Worker         {
803*e5436536SAndroid Build Coastguard Worker           if (i ==
804*e5436536SAndroid Build Coastguard Worker               h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env]) {
805*e5436536SAndroid Build Coastguard Worker             initSlotBasedRotation(h_ps_d, env,
806*e5436536SAndroid Build Coastguard Worker                                   hHeaderData->freqBandData.highSubband);
807*e5436536SAndroid Build Coastguard Worker             env++;
808*e5436536SAndroid Build Coastguard Worker           }
809*e5436536SAndroid Build Coastguard Worker 
810*e5436536SAndroid Build Coastguard Worker           ApplyPsSlot(
811*e5436536SAndroid Build Coastguard Worker               h_ps_d,             /* parametric stereo decoder handle  */
812*e5436536SAndroid Build Coastguard Worker               (pLowBandReal + i), /* one timeslot of left/mono channel */
813*e5436536SAndroid Build Coastguard Worker               (pLowBandImag + i), /* one timeslot of left/mono channel */
814*e5436536SAndroid Build Coastguard Worker               rQmfReal,           /* one timeslot or right channel     */
815*e5436536SAndroid Build Coastguard Worker               rQmfImag,           /* one timeslot or right channel     */
816*e5436536SAndroid Build Coastguard Worker               scaleFactorLowBand_no_ov,
817*e5436536SAndroid Build Coastguard Worker               (i < hSbrDec->LppTrans.pSettings->overlap)
818*e5436536SAndroid Build Coastguard Worker                   ? scaleFactorLowBand_ov
819*e5436536SAndroid Build Coastguard Worker                   : scaleFactorLowBand_no_ov,
820*e5436536SAndroid Build Coastguard Worker               scaleFactorHighBand, synQmf->lsb, synQmf->usb);
821*e5436536SAndroid Build Coastguard Worker         }
822*e5436536SAndroid Build Coastguard Worker 
823*e5436536SAndroid Build Coastguard Worker         sbrDecoder_drcApplySlot(/* right channel */
824*e5436536SAndroid Build Coastguard Worker                                 &hSbrDecRight->sbrDrcChannel, rQmfReal,
825*e5436536SAndroid Build Coastguard Worker                                 rQmfImag, i, synQmfRight->no_col, maxShift);
826*e5436536SAndroid Build Coastguard Worker 
827*e5436536SAndroid Build Coastguard Worker         sbrDecoder_drcApplySlot(/* left channel */
828*e5436536SAndroid Build Coastguard Worker                                 &hSbrDec->sbrDrcChannel, *(pLowBandReal + i),
829*e5436536SAndroid Build Coastguard Worker                                 *(pLowBandImag + i), i, synQmf->no_col,
830*e5436536SAndroid Build Coastguard Worker                                 maxShift);
831*e5436536SAndroid Build Coastguard Worker 
832*e5436536SAndroid Build Coastguard Worker         if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
833*e5436536SAndroid Build Coastguard Worker           qmfChangeOutScalefactor(synQmf, outScalefactor);
834*e5436536SAndroid Build Coastguard Worker           qmfChangeOutScalefactor(synQmfRight, outScalefactor);
835*e5436536SAndroid Build Coastguard Worker 
836*e5436536SAndroid Build Coastguard Worker           qmfSynthesisFilteringSlot(
837*e5436536SAndroid Build Coastguard Worker               synQmfRight, rQmfReal, /* QMF real buffer */
838*e5436536SAndroid Build Coastguard Worker               rQmfImag,              /* QMF imag buffer */
839*e5436536SAndroid Build Coastguard Worker               outScalefactorL, outScalefactorL,
840*e5436536SAndroid Build Coastguard Worker               timeOutRight + (i * synQmf->no_channels * strideOut), strideOut,
841*e5436536SAndroid Build Coastguard Worker               pWorkBuffer);
842*e5436536SAndroid Build Coastguard Worker 
843*e5436536SAndroid Build Coastguard Worker           qmfSynthesisFilteringSlot(
844*e5436536SAndroid Build Coastguard Worker               synQmf, *(pLowBandReal + i), /* QMF real buffer */
845*e5436536SAndroid Build Coastguard Worker               *(pLowBandImag + i),         /* QMF imag buffer */
846*e5436536SAndroid Build Coastguard Worker               outScalefactorR, outScalefactorR,
847*e5436536SAndroid Build Coastguard Worker               timeOut + (i * synQmf->no_channels * strideOut), strideOut,
848*e5436536SAndroid Build Coastguard Worker               pWorkBuffer);
849*e5436536SAndroid Build Coastguard Worker         }
850*e5436536SAndroid Build Coastguard Worker       } /* no_col loop  i  */
851*e5436536SAndroid Build Coastguard Worker #if (QMF_MAX_SYNTHESIS_BANDS <= 64)
852*e5436536SAndroid Build Coastguard Worker       C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
853*e5436536SAndroid Build Coastguard Worker #else
854*e5436536SAndroid Build Coastguard Worker       C_AALLOC_STACK_END(pWorkBuffer, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
855*e5436536SAndroid Build Coastguard Worker #endif
856*e5436536SAndroid Build Coastguard Worker     }
857*e5436536SAndroid Build Coastguard Worker   }
858*e5436536SAndroid Build Coastguard Worker 
859*e5436536SAndroid Build Coastguard Worker   sbrDecoder_drcUpdateChannel(&hSbrDec->sbrDrcChannel);
860*e5436536SAndroid Build Coastguard Worker 
861*e5436536SAndroid Build Coastguard Worker   /*
862*e5436536SAndroid Build Coastguard Worker     Update overlap buffer
863*e5436536SAndroid Build Coastguard Worker     Even bands above usb are copied to avoid outdated spectral data in case
864*e5436536SAndroid Build Coastguard Worker     the stop frequency raises.
865*e5436536SAndroid Build Coastguard Worker   */
866*e5436536SAndroid Build Coastguard Worker 
867*e5436536SAndroid Build Coastguard Worker   if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
868*e5436536SAndroid Build Coastguard Worker     {
869*e5436536SAndroid Build Coastguard Worker       FDK_QmfDomain_SaveOverlap(hSbrDec->qmfDomainInCh, 0);
870*e5436536SAndroid Build Coastguard Worker       FDK_ASSERT(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale == saveLbScale);
871*e5436536SAndroid Build Coastguard Worker     }
872*e5436536SAndroid Build Coastguard Worker   }
873*e5436536SAndroid Build Coastguard Worker 
874*e5436536SAndroid Build Coastguard Worker   hSbrDec->savedStates = 0;
875*e5436536SAndroid Build Coastguard Worker 
876*e5436536SAndroid Build Coastguard Worker   /* Save current frame status */
877*e5436536SAndroid Build Coastguard Worker   hPrevFrameData->frameErrorFlag = hHeaderData->frameErrorFlag;
878*e5436536SAndroid Build Coastguard Worker   hSbrDec->applySbrProc_old = applyProcessing;
879*e5436536SAndroid Build Coastguard Worker 
880*e5436536SAndroid Build Coastguard Worker } /* sbr_dec() */
881*e5436536SAndroid Build Coastguard Worker 
882*e5436536SAndroid Build Coastguard Worker /*!
883*e5436536SAndroid Build Coastguard Worker   \brief     Creates sbr decoder structure
884*e5436536SAndroid Build Coastguard Worker   \return    errorCode, 0 if successful
885*e5436536SAndroid Build Coastguard Worker */
886*e5436536SAndroid Build Coastguard Worker SBR_ERROR
createSbrDec(SBR_CHANNEL * hSbrChannel,HANDLE_SBR_HEADER_DATA hHeaderData,TRANSPOSER_SETTINGS * pSettings,const int downsampleFac,const UINT qmfFlags,const UINT flags,const int overlap,int chan,int codecFrameSize)887*e5436536SAndroid Build Coastguard Worker createSbrDec(SBR_CHANNEL *hSbrChannel,
888*e5436536SAndroid Build Coastguard Worker              HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
889*e5436536SAndroid Build Coastguard Worker              TRANSPOSER_SETTINGS *pSettings,
890*e5436536SAndroid Build Coastguard Worker              const int downsampleFac, /*!< Downsampling factor */
891*e5436536SAndroid Build Coastguard Worker              const UINT qmfFlags, /*!< flags -> 1: HQ/LP selector, 2: CLDFB */
892*e5436536SAndroid Build Coastguard Worker              const UINT flags, const int overlap,
893*e5436536SAndroid Build Coastguard Worker              int chan, /*!< Channel for which to assign buffers etc. */
894*e5436536SAndroid Build Coastguard Worker              int codecFrameSize)
895*e5436536SAndroid Build Coastguard Worker 
896*e5436536SAndroid Build Coastguard Worker {
897*e5436536SAndroid Build Coastguard Worker   SBR_ERROR err = SBRDEC_OK;
898*e5436536SAndroid Build Coastguard Worker   int timeSlots =
899*e5436536SAndroid Build Coastguard Worker       hHeaderData->numberTimeSlots; /* Number of SBR slots per frame */
900*e5436536SAndroid Build Coastguard Worker   int noCols =
901*e5436536SAndroid Build Coastguard Worker       timeSlots * hHeaderData->timeStep; /* Number of QMF slots per frame */
902*e5436536SAndroid Build Coastguard Worker   HANDLE_SBR_DEC hs = &(hSbrChannel->SbrDec);
903*e5436536SAndroid Build Coastguard Worker 
904*e5436536SAndroid Build Coastguard Worker #if (SBRDEC_MAX_HB_FADE_FRAMES > 0)
905*e5436536SAndroid Build Coastguard Worker   hs->highBandFadeCnt = SBRDEC_MAX_HB_FADE_FRAMES;
906*e5436536SAndroid Build Coastguard Worker 
907*e5436536SAndroid Build Coastguard Worker #endif
908*e5436536SAndroid Build Coastguard Worker   hs->scale_hbe = 15;
909*e5436536SAndroid Build Coastguard Worker   hs->scale_lb = 15;
910*e5436536SAndroid Build Coastguard Worker   hs->scale_ov = 15;
911*e5436536SAndroid Build Coastguard Worker 
912*e5436536SAndroid Build Coastguard Worker   hs->prev_frame_lSbr = 0;
913*e5436536SAndroid Build Coastguard Worker   hs->prev_frame_hbeSbr = 0;
914*e5436536SAndroid Build Coastguard Worker 
915*e5436536SAndroid Build Coastguard Worker   hs->codecFrameSize = codecFrameSize;
916*e5436536SAndroid Build Coastguard Worker 
917*e5436536SAndroid Build Coastguard Worker   /*
918*e5436536SAndroid Build Coastguard Worker     create envelope calculator
919*e5436536SAndroid Build Coastguard Worker   */
920*e5436536SAndroid Build Coastguard Worker   err = createSbrEnvelopeCalc(&hs->SbrCalculateEnvelope, hHeaderData, chan,
921*e5436536SAndroid Build Coastguard Worker                               flags);
922*e5436536SAndroid Build Coastguard Worker   if (err != SBRDEC_OK) {
923*e5436536SAndroid Build Coastguard Worker     return err;
924*e5436536SAndroid Build Coastguard Worker   }
925*e5436536SAndroid Build Coastguard Worker 
926*e5436536SAndroid Build Coastguard Worker   initSbrPrevFrameData(&hSbrChannel->prevFrameData, timeSlots);
927*e5436536SAndroid Build Coastguard Worker 
928*e5436536SAndroid Build Coastguard Worker   /*
929*e5436536SAndroid Build Coastguard Worker     create transposer
930*e5436536SAndroid Build Coastguard Worker   */
931*e5436536SAndroid Build Coastguard Worker   err = createLppTransposer(
932*e5436536SAndroid Build Coastguard Worker       &hs->LppTrans, pSettings, hHeaderData->freqBandData.lowSubband,
933*e5436536SAndroid Build Coastguard Worker       hHeaderData->freqBandData.v_k_master, hHeaderData->freqBandData.numMaster,
934*e5436536SAndroid Build Coastguard Worker       hHeaderData->freqBandData.highSubband, timeSlots, noCols,
935*e5436536SAndroid Build Coastguard Worker       hHeaderData->freqBandData.freqBandTableNoise,
936*e5436536SAndroid Build Coastguard Worker       hHeaderData->freqBandData.nNfb, hHeaderData->sbrProcSmplRate, chan,
937*e5436536SAndroid Build Coastguard Worker       overlap);
938*e5436536SAndroid Build Coastguard Worker   if (err != SBRDEC_OK) {
939*e5436536SAndroid Build Coastguard Worker     return err;
940*e5436536SAndroid Build Coastguard Worker   }
941*e5436536SAndroid Build Coastguard Worker 
942*e5436536SAndroid Build Coastguard Worker   if (flags & SBRDEC_USAC_HARMONICSBR) {
943*e5436536SAndroid Build Coastguard Worker     int noChannels, bSbr41 = flags & SBRDEC_QUAD_RATE ? 1 : 0;
944*e5436536SAndroid Build Coastguard Worker 
945*e5436536SAndroid Build Coastguard Worker     noChannels =
946*e5436536SAndroid Build Coastguard Worker         QMF_SYNTH_CHANNELS /
947*e5436536SAndroid Build Coastguard Worker         ((bSbr41 + 1) * 2); /* 32 for (32:64 and 24:64) and 16 for 16:64 */
948*e5436536SAndroid Build Coastguard Worker 
949*e5436536SAndroid Build Coastguard Worker     /* shared memory between hbeLightTimeDelayBuffer and hQmfHBESlotsReal if
950*e5436536SAndroid Build Coastguard Worker      * SBRDEC_HBE_ENABLE */
951*e5436536SAndroid Build Coastguard Worker     hSbrChannel->SbrDec.tmp_memory = (FIXP_DBL **)fdkCallocMatrix2D_aligned(
952*e5436536SAndroid Build Coastguard Worker         noCols, noChannels, sizeof(FIXP_DBL));
953*e5436536SAndroid Build Coastguard Worker     if (hSbrChannel->SbrDec.tmp_memory == NULL) {
954*e5436536SAndroid Build Coastguard Worker       return SBRDEC_MEM_ALLOC_FAILED;
955*e5436536SAndroid Build Coastguard Worker     }
956*e5436536SAndroid Build Coastguard Worker 
957*e5436536SAndroid Build Coastguard Worker     hSbrChannel->SbrDec.hQmfHBESlotsReal = hSbrChannel->SbrDec.tmp_memory;
958*e5436536SAndroid Build Coastguard Worker     hSbrChannel->SbrDec.hQmfHBESlotsImag =
959*e5436536SAndroid Build Coastguard Worker         (FIXP_DBL **)fdkCallocMatrix2D_aligned(noCols, noChannels,
960*e5436536SAndroid Build Coastguard Worker                                                sizeof(FIXP_DBL));
961*e5436536SAndroid Build Coastguard Worker     if (hSbrChannel->SbrDec.hQmfHBESlotsImag == NULL) {
962*e5436536SAndroid Build Coastguard Worker       return SBRDEC_MEM_ALLOC_FAILED;
963*e5436536SAndroid Build Coastguard Worker     }
964*e5436536SAndroid Build Coastguard Worker 
965*e5436536SAndroid Build Coastguard Worker     /* buffers containing unmodified qmf data; required when switching from
966*e5436536SAndroid Build Coastguard Worker      * legacy SBR to HBE                       */
967*e5436536SAndroid Build Coastguard Worker     /* buffer can be used as LPCFilterstates buffer because legacy SBR needs
968*e5436536SAndroid Build Coastguard Worker      * exactly these values for LPC filtering */
969*e5436536SAndroid Build Coastguard Worker     hSbrChannel->SbrDec.codecQMFBufferReal =
970*e5436536SAndroid Build Coastguard Worker         (FIXP_DBL **)fdkCallocMatrix2D_aligned(noCols, noChannels,
971*e5436536SAndroid Build Coastguard Worker                                                sizeof(FIXP_DBL));
972*e5436536SAndroid Build Coastguard Worker     if (hSbrChannel->SbrDec.codecQMFBufferReal == NULL) {
973*e5436536SAndroid Build Coastguard Worker       return SBRDEC_MEM_ALLOC_FAILED;
974*e5436536SAndroid Build Coastguard Worker     }
975*e5436536SAndroid Build Coastguard Worker 
976*e5436536SAndroid Build Coastguard Worker     hSbrChannel->SbrDec.codecQMFBufferImag =
977*e5436536SAndroid Build Coastguard Worker         (FIXP_DBL **)fdkCallocMatrix2D_aligned(noCols, noChannels,
978*e5436536SAndroid Build Coastguard Worker                                                sizeof(FIXP_DBL));
979*e5436536SAndroid Build Coastguard Worker     if (hSbrChannel->SbrDec.codecQMFBufferImag == NULL) {
980*e5436536SAndroid Build Coastguard Worker       return SBRDEC_MEM_ALLOC_FAILED;
981*e5436536SAndroid Build Coastguard Worker     }
982*e5436536SAndroid Build Coastguard Worker 
983*e5436536SAndroid Build Coastguard Worker     err = QmfTransposerCreate(&hs->hHBE, codecFrameSize, 0, bSbr41);
984*e5436536SAndroid Build Coastguard Worker     if (err != SBRDEC_OK) {
985*e5436536SAndroid Build Coastguard Worker       return err;
986*e5436536SAndroid Build Coastguard Worker     }
987*e5436536SAndroid Build Coastguard Worker   }
988*e5436536SAndroid Build Coastguard Worker 
989*e5436536SAndroid Build Coastguard Worker   return err;
990*e5436536SAndroid Build Coastguard Worker }
991*e5436536SAndroid Build Coastguard Worker 
992*e5436536SAndroid Build Coastguard Worker /*!
993*e5436536SAndroid Build Coastguard Worker   \brief     Delete sbr decoder structure
994*e5436536SAndroid Build Coastguard Worker   \return    errorCode, 0 if successful
995*e5436536SAndroid Build Coastguard Worker */
deleteSbrDec(SBR_CHANNEL * hSbrChannel)996*e5436536SAndroid Build Coastguard Worker int deleteSbrDec(SBR_CHANNEL *hSbrChannel) {
997*e5436536SAndroid Build Coastguard Worker   HANDLE_SBR_DEC hs = &hSbrChannel->SbrDec;
998*e5436536SAndroid Build Coastguard Worker 
999*e5436536SAndroid Build Coastguard Worker   deleteSbrEnvelopeCalc(&hs->SbrCalculateEnvelope);
1000*e5436536SAndroid Build Coastguard Worker 
1001*e5436536SAndroid Build Coastguard Worker   if (hs->tmp_memory != NULL) {
1002*e5436536SAndroid Build Coastguard Worker     FDK_FREE_MEMORY_2D_ALIGNED(hs->tmp_memory);
1003*e5436536SAndroid Build Coastguard Worker   }
1004*e5436536SAndroid Build Coastguard Worker 
1005*e5436536SAndroid Build Coastguard Worker   /* modify here */
1006*e5436536SAndroid Build Coastguard Worker   FDK_FREE_MEMORY_2D_ALIGNED(hs->hQmfHBESlotsImag);
1007*e5436536SAndroid Build Coastguard Worker 
1008*e5436536SAndroid Build Coastguard Worker   if (hs->hHBE != NULL) QmfTransposerClose(hs->hHBE);
1009*e5436536SAndroid Build Coastguard Worker 
1010*e5436536SAndroid Build Coastguard Worker   if (hs->codecQMFBufferReal != NULL) {
1011*e5436536SAndroid Build Coastguard Worker     FDK_FREE_MEMORY_2D_ALIGNED(hs->codecQMFBufferReal);
1012*e5436536SAndroid Build Coastguard Worker   }
1013*e5436536SAndroid Build Coastguard Worker 
1014*e5436536SAndroid Build Coastguard Worker   if (hs->codecQMFBufferImag != NULL) {
1015*e5436536SAndroid Build Coastguard Worker     FDK_FREE_MEMORY_2D_ALIGNED(hs->codecQMFBufferImag);
1016*e5436536SAndroid Build Coastguard Worker   }
1017*e5436536SAndroid Build Coastguard Worker 
1018*e5436536SAndroid Build Coastguard Worker   return 0;
1019*e5436536SAndroid Build Coastguard Worker }
1020*e5436536SAndroid Build Coastguard Worker 
1021*e5436536SAndroid Build Coastguard Worker /*!
1022*e5436536SAndroid Build Coastguard Worker   \brief     resets sbr decoder structure
1023*e5436536SAndroid Build Coastguard Worker   \return    errorCode, 0 if successful
1024*e5436536SAndroid Build Coastguard Worker */
1025*e5436536SAndroid Build Coastguard Worker SBR_ERROR
resetSbrDec(HANDLE_SBR_DEC hSbrDec,HANDLE_SBR_HEADER_DATA hHeaderData,HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData,const int downsampleFac,const UINT flags,HANDLE_SBR_FRAME_DATA hFrameData)1026*e5436536SAndroid Build Coastguard Worker resetSbrDec(HANDLE_SBR_DEC hSbrDec, HANDLE_SBR_HEADER_DATA hHeaderData,
1027*e5436536SAndroid Build Coastguard Worker             HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, const int downsampleFac,
1028*e5436536SAndroid Build Coastguard Worker             const UINT flags, HANDLE_SBR_FRAME_DATA hFrameData) {
1029*e5436536SAndroid Build Coastguard Worker   SBR_ERROR sbrError = SBRDEC_OK;
1030*e5436536SAndroid Build Coastguard Worker   int i;
1031*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *pLowBandReal[128];
1032*e5436536SAndroid Build Coastguard Worker   FIXP_DBL *pLowBandImag[128];
1033*e5436536SAndroid Build Coastguard Worker   int useLP = flags & SBRDEC_LOW_POWER;
1034*e5436536SAndroid Build Coastguard Worker 
1035*e5436536SAndroid Build Coastguard Worker   int old_lsb = hSbrDec->qmfDomainInCh->fb.lsb;
1036*e5436536SAndroid Build Coastguard Worker   int old_usb = hSbrDec->qmfDomainInCh->fb.usb;
1037*e5436536SAndroid Build Coastguard Worker   int new_lsb = hHeaderData->freqBandData.lowSubband;
1038*e5436536SAndroid Build Coastguard Worker   /* int new_usb = hHeaderData->freqBandData.highSubband; */
1039*e5436536SAndroid Build Coastguard Worker   int l, startBand, stopBand, startSlot, size;
1040*e5436536SAndroid Build Coastguard Worker 
1041*e5436536SAndroid Build Coastguard Worker   FIXP_DBL **OverlapBufferReal = hSbrDec->qmfDomainInCh->hQmfSlotsReal;
1042*e5436536SAndroid Build Coastguard Worker   FIXP_DBL **OverlapBufferImag = hSbrDec->qmfDomainInCh->hQmfSlotsImag;
1043*e5436536SAndroid Build Coastguard Worker 
1044*e5436536SAndroid Build Coastguard Worker   /* in case the previous frame was not active in terms of SBR processing, the
1045*e5436536SAndroid Build Coastguard Worker      full band from 0 to no_channels was rescaled and not overwritten. Thats why
1046*e5436536SAndroid Build Coastguard Worker      the scaling factor lb_scale can be seen as assigned to all bands from 0 to
1047*e5436536SAndroid Build Coastguard Worker      no_channels in the previous frame. The same states for the current frame if
1048*e5436536SAndroid Build Coastguard Worker      the current frame is not active in terms of SBR processing
1049*e5436536SAndroid Build Coastguard Worker   */
1050*e5436536SAndroid Build Coastguard Worker   int applySbrProc = (hHeaderData->syncState == SBR_ACTIVE ||
1051*e5436536SAndroid Build Coastguard Worker                       (hHeaderData->frameErrorFlag == 0 &&
1052*e5436536SAndroid Build Coastguard Worker                        hHeaderData->syncState == SBR_HEADER));
1053*e5436536SAndroid Build Coastguard Worker   int applySbrProc_old = hSbrDec->applySbrProc_old;
1054*e5436536SAndroid Build Coastguard Worker 
1055*e5436536SAndroid Build Coastguard Worker   if (!applySbrProc) {
1056*e5436536SAndroid Build Coastguard Worker     new_lsb = (hSbrDec->qmfDomainInCh->fb).no_channels;
1057*e5436536SAndroid Build Coastguard Worker   }
1058*e5436536SAndroid Build Coastguard Worker   if (!applySbrProc_old) {
1059*e5436536SAndroid Build Coastguard Worker     old_lsb = (hSbrDec->qmfDomainInCh->fb).no_channels;
1060*e5436536SAndroid Build Coastguard Worker     old_usb = old_lsb;
1061*e5436536SAndroid Build Coastguard Worker   }
1062*e5436536SAndroid Build Coastguard Worker 
1063*e5436536SAndroid Build Coastguard Worker   resetSbrEnvelopeCalc(&hSbrDec->SbrCalculateEnvelope);
1064*e5436536SAndroid Build Coastguard Worker 
1065*e5436536SAndroid Build Coastguard Worker   /* Change lsb and usb */
1066*e5436536SAndroid Build Coastguard Worker   /* Synthesis */
1067*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(hSbrDec->qmfDomainOutCh != NULL);
1068*e5436536SAndroid Build Coastguard Worker   hSbrDec->qmfDomainOutCh->fb.lsb =
1069*e5436536SAndroid Build Coastguard Worker       fixMin((INT)hSbrDec->qmfDomainOutCh->fb.no_channels,
1070*e5436536SAndroid Build Coastguard Worker              (INT)hHeaderData->freqBandData.lowSubband);
1071*e5436536SAndroid Build Coastguard Worker   hSbrDec->qmfDomainOutCh->fb.usb =
1072*e5436536SAndroid Build Coastguard Worker       fixMin((INT)hSbrDec->qmfDomainOutCh->fb.no_channels,
1073*e5436536SAndroid Build Coastguard Worker              (INT)hHeaderData->freqBandData.highSubband);
1074*e5436536SAndroid Build Coastguard Worker   /* Analysis */
1075*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(hSbrDec->qmfDomainInCh != NULL);
1076*e5436536SAndroid Build Coastguard Worker   hSbrDec->qmfDomainInCh->fb.lsb = hSbrDec->qmfDomainOutCh->fb.lsb;
1077*e5436536SAndroid Build Coastguard Worker   hSbrDec->qmfDomainInCh->fb.usb = hSbrDec->qmfDomainOutCh->fb.usb;
1078*e5436536SAndroid Build Coastguard Worker 
1079*e5436536SAndroid Build Coastguard Worker   /*
1080*e5436536SAndroid Build Coastguard Worker     The following initialization of spectral data in the overlap buffer
1081*e5436536SAndroid Build Coastguard Worker     is required for dynamic x-over or a change of the start-freq for 2 reasons:
1082*e5436536SAndroid Build Coastguard Worker 
1083*e5436536SAndroid Build Coastguard Worker     1. If the lowband gets _wider_, unadjusted data would remain
1084*e5436536SAndroid Build Coastguard Worker 
1085*e5436536SAndroid Build Coastguard Worker     2. If the lowband becomes _smaller_, the highest bands of the old lowband
1086*e5436536SAndroid Build Coastguard Worker        must be cleared because the whitening would be affected
1087*e5436536SAndroid Build Coastguard Worker   */
1088*e5436536SAndroid Build Coastguard Worker   startBand = old_lsb;
1089*e5436536SAndroid Build Coastguard Worker   stopBand = new_lsb;
1090*e5436536SAndroid Build Coastguard Worker   startSlot = fMax(0, hHeaderData->timeStep * (hPrevFrameData->stopPos -
1091*e5436536SAndroid Build Coastguard Worker                                                hHeaderData->numberTimeSlots));
1092*e5436536SAndroid Build Coastguard Worker   size = fMax(0, stopBand - startBand);
1093*e5436536SAndroid Build Coastguard Worker 
1094*e5436536SAndroid Build Coastguard Worker   /* in case of USAC we don't want to zero out the memory, as this can lead to
1095*e5436536SAndroid Build Coastguard Worker      holes in the spectrum; fix shall only be applied for USAC not for MPEG-4
1096*e5436536SAndroid Build Coastguard Worker      SBR, in this case setting zero remains         */
1097*e5436536SAndroid Build Coastguard Worker   if (!(flags & SBRDEC_SYNTAX_USAC)) {
1098*e5436536SAndroid Build Coastguard Worker     /* keep already adjusted data in the x-over-area */
1099*e5436536SAndroid Build Coastguard Worker     if (!useLP) {
1100*e5436536SAndroid Build Coastguard Worker       for (l = startSlot; l < hSbrDec->LppTrans.pSettings->overlap; l++) {
1101*e5436536SAndroid Build Coastguard Worker         FDKmemclear(&OverlapBufferReal[l][startBand], size * sizeof(FIXP_DBL));
1102*e5436536SAndroid Build Coastguard Worker         FDKmemclear(&OverlapBufferImag[l][startBand], size * sizeof(FIXP_DBL));
1103*e5436536SAndroid Build Coastguard Worker       }
1104*e5436536SAndroid Build Coastguard Worker     } else {
1105*e5436536SAndroid Build Coastguard Worker       for (l = startSlot; l < hSbrDec->LppTrans.pSettings->overlap; l++) {
1106*e5436536SAndroid Build Coastguard Worker         FDKmemclear(&OverlapBufferReal[l][startBand], size * sizeof(FIXP_DBL));
1107*e5436536SAndroid Build Coastguard Worker       }
1108*e5436536SAndroid Build Coastguard Worker     }
1109*e5436536SAndroid Build Coastguard Worker 
1110*e5436536SAndroid Build Coastguard Worker     /*
1111*e5436536SAndroid Build Coastguard Worker     reset LPC filter states
1112*e5436536SAndroid Build Coastguard Worker     */
1113*e5436536SAndroid Build Coastguard Worker     startBand = fixMin(old_lsb, new_lsb);
1114*e5436536SAndroid Build Coastguard Worker     stopBand = fixMax(old_lsb, new_lsb);
1115*e5436536SAndroid Build Coastguard Worker     size = fixMax(0, stopBand - startBand);
1116*e5436536SAndroid Build Coastguard Worker 
1117*e5436536SAndroid Build Coastguard Worker     FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[0][startBand],
1118*e5436536SAndroid Build Coastguard Worker                 size * sizeof(FIXP_DBL));
1119*e5436536SAndroid Build Coastguard Worker     FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[1][startBand],
1120*e5436536SAndroid Build Coastguard Worker                 size * sizeof(FIXP_DBL));
1121*e5436536SAndroid Build Coastguard Worker     if (!useLP) {
1122*e5436536SAndroid Build Coastguard Worker       FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[0][startBand],
1123*e5436536SAndroid Build Coastguard Worker                   size * sizeof(FIXP_DBL));
1124*e5436536SAndroid Build Coastguard Worker       FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[1][startBand],
1125*e5436536SAndroid Build Coastguard Worker                   size * sizeof(FIXP_DBL));
1126*e5436536SAndroid Build Coastguard Worker     }
1127*e5436536SAndroid Build Coastguard Worker   }
1128*e5436536SAndroid Build Coastguard Worker 
1129*e5436536SAndroid Build Coastguard Worker   if (startSlot != 0) {
1130*e5436536SAndroid Build Coastguard Worker     int source_exp, target_exp, delta_exp, target_lsb, target_usb, reserve;
1131*e5436536SAndroid Build Coastguard Worker     FIXP_DBL maxVal;
1132*e5436536SAndroid Build Coastguard Worker 
1133*e5436536SAndroid Build Coastguard Worker     /*
1134*e5436536SAndroid Build Coastguard Worker     Rescale already processed spectral data between old and new x-over
1135*e5436536SAndroid Build Coastguard Worker     frequency. This must be done because of the separate scalefactors for
1136*e5436536SAndroid Build Coastguard Worker     lowband and highband.
1137*e5436536SAndroid Build Coastguard Worker     */
1138*e5436536SAndroid Build Coastguard Worker 
1139*e5436536SAndroid Build Coastguard Worker     /* We have four relevant transitions to cover:
1140*e5436536SAndroid Build Coastguard Worker     1. old_usb is lower than new_lsb; old SBR area is completely below new SBR
1141*e5436536SAndroid Build Coastguard Worker     area.
1142*e5436536SAndroid Build Coastguard Worker        -> entire old area was highband and belongs to lowband now
1143*e5436536SAndroid Build Coastguard Worker           and has to be rescaled.
1144*e5436536SAndroid Build Coastguard Worker     2. old_lsb is higher than new_usb; new SBR area is completely below old SBR
1145*e5436536SAndroid Build Coastguard Worker     area.
1146*e5436536SAndroid Build Coastguard Worker        -> old area between new_lsb and old_lsb was lowband and belongs to
1147*e5436536SAndroid Build Coastguard Worker     highband now and has to be rescaled to match new highband scale.
1148*e5436536SAndroid Build Coastguard Worker     3. old_lsb is lower and old_usb is higher than new_lsb; old and new SBR
1149*e5436536SAndroid Build Coastguard Worker     areas overlap.
1150*e5436536SAndroid Build Coastguard Worker        -> old area between old_lsb and new_lsb was highband and belongs to
1151*e5436536SAndroid Build Coastguard Worker     lowband now and has to be rescaled to match new lowband scale.
1152*e5436536SAndroid Build Coastguard Worker     4. new_lsb is lower and new_usb_is higher than old_lsb; old and new SBR
1153*e5436536SAndroid Build Coastguard Worker     areas overlap.
1154*e5436536SAndroid Build Coastguard Worker        -> old area between new_lsb and old_usb was lowband and belongs to
1155*e5436536SAndroid Build Coastguard Worker     highband now and has to be rescaled to match new highband scale.
1156*e5436536SAndroid Build Coastguard Worker     */
1157*e5436536SAndroid Build Coastguard Worker 
1158*e5436536SAndroid Build Coastguard Worker     if (new_lsb > old_lsb) {
1159*e5436536SAndroid Build Coastguard Worker       /* case 1 and 3 */
1160*e5436536SAndroid Build Coastguard Worker       source_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_hb_scale);
1161*e5436536SAndroid Build Coastguard Worker       target_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale);
1162*e5436536SAndroid Build Coastguard Worker 
1163*e5436536SAndroid Build Coastguard Worker       startBand = old_lsb;
1164*e5436536SAndroid Build Coastguard Worker 
1165*e5436536SAndroid Build Coastguard Worker       if (new_lsb >= old_usb) {
1166*e5436536SAndroid Build Coastguard Worker         /* case 1 */
1167*e5436536SAndroid Build Coastguard Worker         stopBand = old_usb;
1168*e5436536SAndroid Build Coastguard Worker       } else {
1169*e5436536SAndroid Build Coastguard Worker         /* case 3 */
1170*e5436536SAndroid Build Coastguard Worker         stopBand = new_lsb;
1171*e5436536SAndroid Build Coastguard Worker       }
1172*e5436536SAndroid Build Coastguard Worker 
1173*e5436536SAndroid Build Coastguard Worker       target_lsb = 0;
1174*e5436536SAndroid Build Coastguard Worker       target_usb = old_lsb;
1175*e5436536SAndroid Build Coastguard Worker     } else {
1176*e5436536SAndroid Build Coastguard Worker       /* case 2 and 4 */
1177*e5436536SAndroid Build Coastguard Worker       source_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale);
1178*e5436536SAndroid Build Coastguard Worker       target_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_hb_scale);
1179*e5436536SAndroid Build Coastguard Worker 
1180*e5436536SAndroid Build Coastguard Worker       startBand = new_lsb;
1181*e5436536SAndroid Build Coastguard Worker       stopBand = old_lsb;
1182*e5436536SAndroid Build Coastguard Worker 
1183*e5436536SAndroid Build Coastguard Worker       target_lsb = old_lsb;
1184*e5436536SAndroid Build Coastguard Worker       target_usb = old_usb;
1185*e5436536SAndroid Build Coastguard Worker     }
1186*e5436536SAndroid Build Coastguard Worker 
1187*e5436536SAndroid Build Coastguard Worker     maxVal =
1188*e5436536SAndroid Build Coastguard Worker         maxSubbandSample(OverlapBufferReal, (useLP) ? NULL : OverlapBufferImag,
1189*e5436536SAndroid Build Coastguard Worker                          startBand, stopBand, 0, startSlot);
1190*e5436536SAndroid Build Coastguard Worker 
1191*e5436536SAndroid Build Coastguard Worker     reserve = ((LONG)maxVal != 0 ? CntLeadingZeros(maxVal) - 1 : 0);
1192*e5436536SAndroid Build Coastguard Worker     reserve = fixMin(
1193*e5436536SAndroid Build Coastguard Worker         reserve,
1194*e5436536SAndroid Build Coastguard Worker         DFRACT_BITS - 1 -
1195*e5436536SAndroid Build Coastguard Worker             EXP2SCALE(
1196*e5436536SAndroid Build Coastguard Worker                 source_exp)); /* what is this line for, why do we need it? */
1197*e5436536SAndroid Build Coastguard Worker 
1198*e5436536SAndroid Build Coastguard Worker     /* process only if x-over-area is not dominant after rescale;
1199*e5436536SAndroid Build Coastguard Worker        otherwise I'm not sure if all buffers are scaled correctly;
1200*e5436536SAndroid Build Coastguard Worker     */
1201*e5436536SAndroid Build Coastguard Worker     if (target_exp - (source_exp - reserve) >= 0) {
1202*e5436536SAndroid Build Coastguard Worker       rescaleSubbandSamples(OverlapBufferReal,
1203*e5436536SAndroid Build Coastguard Worker                             (useLP) ? NULL : OverlapBufferImag, startBand,
1204*e5436536SAndroid Build Coastguard Worker                             stopBand, 0, startSlot, reserve);
1205*e5436536SAndroid Build Coastguard Worker       source_exp -= reserve;
1206*e5436536SAndroid Build Coastguard Worker     }
1207*e5436536SAndroid Build Coastguard Worker 
1208*e5436536SAndroid Build Coastguard Worker     delta_exp = target_exp - source_exp;
1209*e5436536SAndroid Build Coastguard Worker 
1210*e5436536SAndroid Build Coastguard Worker     if (delta_exp < 0) { /* x-over-area is dominant */
1211*e5436536SAndroid Build Coastguard Worker       startBand = target_lsb;
1212*e5436536SAndroid Build Coastguard Worker       stopBand = target_usb;
1213*e5436536SAndroid Build Coastguard Worker       delta_exp = -delta_exp;
1214*e5436536SAndroid Build Coastguard Worker 
1215*e5436536SAndroid Build Coastguard Worker       if (new_lsb > old_lsb) {
1216*e5436536SAndroid Build Coastguard Worker         /* The lowband has to be rescaled */
1217*e5436536SAndroid Build Coastguard Worker         hSbrDec->qmfDomainInCh->scaling.ov_lb_scale = EXP2SCALE(source_exp);
1218*e5436536SAndroid Build Coastguard Worker       } else {
1219*e5436536SAndroid Build Coastguard Worker         /* The highband has to be rescaled */
1220*e5436536SAndroid Build Coastguard Worker         hSbrDec->qmfDomainInCh->scaling.ov_hb_scale = EXP2SCALE(source_exp);
1221*e5436536SAndroid Build Coastguard Worker       }
1222*e5436536SAndroid Build Coastguard Worker     }
1223*e5436536SAndroid Build Coastguard Worker 
1224*e5436536SAndroid Build Coastguard Worker     FDK_ASSERT(startBand <= stopBand);
1225*e5436536SAndroid Build Coastguard Worker 
1226*e5436536SAndroid Build Coastguard Worker     if (!useLP) {
1227*e5436536SAndroid Build Coastguard Worker       for (l = 0; l < startSlot; l++) {
1228*e5436536SAndroid Build Coastguard Worker         scaleValues(OverlapBufferReal[l] + startBand, stopBand - startBand,
1229*e5436536SAndroid Build Coastguard Worker                     -delta_exp);
1230*e5436536SAndroid Build Coastguard Worker         scaleValues(OverlapBufferImag[l] + startBand, stopBand - startBand,
1231*e5436536SAndroid Build Coastguard Worker                     -delta_exp);
1232*e5436536SAndroid Build Coastguard Worker       }
1233*e5436536SAndroid Build Coastguard Worker     } else
1234*e5436536SAndroid Build Coastguard Worker       for (l = 0; l < startSlot; l++) {
1235*e5436536SAndroid Build Coastguard Worker         scaleValues(OverlapBufferReal[l] + startBand, stopBand - startBand,
1236*e5436536SAndroid Build Coastguard Worker                     -delta_exp);
1237*e5436536SAndroid Build Coastguard Worker       }
1238*e5436536SAndroid Build Coastguard Worker   } /* startSlot != 0 */
1239*e5436536SAndroid Build Coastguard Worker 
1240*e5436536SAndroid Build Coastguard Worker   /*
1241*e5436536SAndroid Build Coastguard Worker     Initialize transposer and limiter
1242*e5436536SAndroid Build Coastguard Worker   */
1243*e5436536SAndroid Build Coastguard Worker   sbrError = resetLppTransposer(
1244*e5436536SAndroid Build Coastguard Worker       &hSbrDec->LppTrans, hHeaderData->freqBandData.lowSubband,
1245*e5436536SAndroid Build Coastguard Worker       hHeaderData->freqBandData.v_k_master, hHeaderData->freqBandData.numMaster,
1246*e5436536SAndroid Build Coastguard Worker       hHeaderData->freqBandData.freqBandTableNoise,
1247*e5436536SAndroid Build Coastguard Worker       hHeaderData->freqBandData.nNfb, hHeaderData->freqBandData.highSubband,
1248*e5436536SAndroid Build Coastguard Worker       hHeaderData->sbrProcSmplRate);
1249*e5436536SAndroid Build Coastguard Worker   if (sbrError != SBRDEC_OK) return sbrError;
1250*e5436536SAndroid Build Coastguard Worker 
1251*e5436536SAndroid Build Coastguard Worker   hSbrDec->savedStates = 0;
1252*e5436536SAndroid Build Coastguard Worker 
1253*e5436536SAndroid Build Coastguard Worker   if ((flags & SBRDEC_USAC_HARMONICSBR) && applySbrProc) {
1254*e5436536SAndroid Build Coastguard Worker     sbrError = QmfTransposerReInit(hSbrDec->hHBE,
1255*e5436536SAndroid Build Coastguard Worker                                    hHeaderData->freqBandData.freqBandTable,
1256*e5436536SAndroid Build Coastguard Worker                                    hHeaderData->freqBandData.nSfb);
1257*e5436536SAndroid Build Coastguard Worker     if (sbrError != SBRDEC_OK) return sbrError;
1258*e5436536SAndroid Build Coastguard Worker 
1259*e5436536SAndroid Build Coastguard Worker     /* copy saved states from previous frame to legacy SBR lpc filterstate
1260*e5436536SAndroid Build Coastguard Worker      * buffer   */
1261*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < LPC_ORDER + hSbrDec->LppTrans.pSettings->overlap; i++) {
1262*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(
1263*e5436536SAndroid Build Coastguard Worker           hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
1264*e5436536SAndroid Build Coastguard Worker           hSbrDec->codecQMFBufferReal[hSbrDec->hHBE->noCols - LPC_ORDER -
1265*e5436536SAndroid Build Coastguard Worker                                       hSbrDec->LppTrans.pSettings->overlap + i],
1266*e5436536SAndroid Build Coastguard Worker           hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
1267*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(
1268*e5436536SAndroid Build Coastguard Worker           hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i],
1269*e5436536SAndroid Build Coastguard Worker           hSbrDec->codecQMFBufferImag[hSbrDec->hHBE->noCols - LPC_ORDER -
1270*e5436536SAndroid Build Coastguard Worker                                       hSbrDec->LppTrans.pSettings->overlap + i],
1271*e5436536SAndroid Build Coastguard Worker           hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
1272*e5436536SAndroid Build Coastguard Worker     }
1273*e5436536SAndroid Build Coastguard Worker     hSbrDec->savedStates = 1;
1274*e5436536SAndroid Build Coastguard Worker 
1275*e5436536SAndroid Build Coastguard Worker     {
1276*e5436536SAndroid Build Coastguard Worker       /* map QMF buffer to pointer array (Overlap + Frame)*/
1277*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER; i++) {
1278*e5436536SAndroid Build Coastguard Worker         pLowBandReal[i] = hSbrDec->LppTrans.lpcFilterStatesRealHBE[i];
1279*e5436536SAndroid Build Coastguard Worker         pLowBandImag[i] = hSbrDec->LppTrans.lpcFilterStatesImagHBE[i];
1280*e5436536SAndroid Build Coastguard Worker       }
1281*e5436536SAndroid Build Coastguard Worker 
1282*e5436536SAndroid Build Coastguard Worker       /* map QMF buffer to pointer array (Overlap + Frame)*/
1283*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < hSbrDec->hHBE->noCols; i++) {
1284*e5436536SAndroid Build Coastguard Worker         pLowBandReal[i + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
1285*e5436536SAndroid Build Coastguard Worker             hSbrDec->codecQMFBufferReal[i];
1286*e5436536SAndroid Build Coastguard Worker         pLowBandImag[i + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
1287*e5436536SAndroid Build Coastguard Worker             hSbrDec->codecQMFBufferImag[i];
1288*e5436536SAndroid Build Coastguard Worker       }
1289*e5436536SAndroid Build Coastguard Worker 
1290*e5436536SAndroid Build Coastguard Worker       if (flags & SBRDEC_QUAD_RATE) {
1291*e5436536SAndroid Build Coastguard Worker         if (hFrameData->sbrPatchingMode == 0) {
1292*e5436536SAndroid Build Coastguard Worker           int *xOverQmf = GetxOverBandQmfTransposer(hSbrDec->hHBE);
1293*e5436536SAndroid Build Coastguard Worker 
1294*e5436536SAndroid Build Coastguard Worker           /* in case of harmonic SBR and no HBE_LP map additional buffer for
1295*e5436536SAndroid Build Coastguard Worker           one more frame to pointer arry */
1296*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < hSbrDec->hHBE->noCols / 2; i++) {
1297*e5436536SAndroid Build Coastguard Worker             pLowBandReal[i + hSbrDec->hHBE->noCols +
1298*e5436536SAndroid Build Coastguard Worker                          hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
1299*e5436536SAndroid Build Coastguard Worker                 hSbrDec->hQmfHBESlotsReal[i];
1300*e5436536SAndroid Build Coastguard Worker             pLowBandImag[i + hSbrDec->hHBE->noCols +
1301*e5436536SAndroid Build Coastguard Worker                          hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
1302*e5436536SAndroid Build Coastguard Worker                 hSbrDec->hQmfHBESlotsImag[i];
1303*e5436536SAndroid Build Coastguard Worker           }
1304*e5436536SAndroid Build Coastguard Worker 
1305*e5436536SAndroid Build Coastguard Worker           QmfTransposerApply(
1306*e5436536SAndroid Build Coastguard Worker               hSbrDec->hHBE,
1307*e5436536SAndroid Build Coastguard Worker               pLowBandReal + hSbrDec->LppTrans.pSettings->overlap +
1308*e5436536SAndroid Build Coastguard Worker                   hSbrDec->hHBE->noCols / 2 + LPC_ORDER,
1309*e5436536SAndroid Build Coastguard Worker               pLowBandImag + hSbrDec->LppTrans.pSettings->overlap +
1310*e5436536SAndroid Build Coastguard Worker                   hSbrDec->hHBE->noCols / 2 + LPC_ORDER,
1311*e5436536SAndroid Build Coastguard Worker               hSbrDec->hHBE->noCols, pLowBandReal, pLowBandImag,
1312*e5436536SAndroid Build Coastguard Worker               hSbrDec->LppTrans.lpcFilterStatesRealHBE,
1313*e5436536SAndroid Build Coastguard Worker               hSbrDec->LppTrans.lpcFilterStatesImagHBE,
1314*e5436536SAndroid Build Coastguard Worker               hPrevFrameData->prevSbrPitchInBins, hSbrDec->scale_lb,
1315*e5436536SAndroid Build Coastguard Worker               hSbrDec->scale_hbe, &hSbrDec->qmfDomainInCh->scaling.hb_scale,
1316*e5436536SAndroid Build Coastguard Worker               hHeaderData->timeStep, hFrameData->frameInfo.borders[0],
1317*e5436536SAndroid Build Coastguard Worker               hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_OUTDIFF);
1318*e5436536SAndroid Build Coastguard Worker 
1319*e5436536SAndroid Build Coastguard Worker           copyHarmonicSpectrum(
1320*e5436536SAndroid Build Coastguard Worker               xOverQmf, pLowBandReal, pLowBandImag, hSbrDec->hHBE->noCols,
1321*e5436536SAndroid Build Coastguard Worker               hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_OUTDIFF);
1322*e5436536SAndroid Build Coastguard Worker         }
1323*e5436536SAndroid Build Coastguard Worker       } else {
1324*e5436536SAndroid Build Coastguard Worker         /* in case of harmonic SBR and no HBE_LP map additional buffer for
1325*e5436536SAndroid Build Coastguard Worker         one more frame to pointer arry */
1326*e5436536SAndroid Build Coastguard Worker         for (i = 0; i < hSbrDec->hHBE->noCols; i++) {
1327*e5436536SAndroid Build Coastguard Worker           pLowBandReal[i + hSbrDec->hHBE->noCols +
1328*e5436536SAndroid Build Coastguard Worker                        hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
1329*e5436536SAndroid Build Coastguard Worker               hSbrDec->hQmfHBESlotsReal[i];
1330*e5436536SAndroid Build Coastguard Worker           pLowBandImag[i + hSbrDec->hHBE->noCols +
1331*e5436536SAndroid Build Coastguard Worker                        hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
1332*e5436536SAndroid Build Coastguard Worker               hSbrDec->hQmfHBESlotsImag[i];
1333*e5436536SAndroid Build Coastguard Worker         }
1334*e5436536SAndroid Build Coastguard Worker 
1335*e5436536SAndroid Build Coastguard Worker         if (hFrameData->sbrPatchingMode == 0) {
1336*e5436536SAndroid Build Coastguard Worker           QmfTransposerApply(
1337*e5436536SAndroid Build Coastguard Worker               hSbrDec->hHBE,
1338*e5436536SAndroid Build Coastguard Worker               pLowBandReal + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER,
1339*e5436536SAndroid Build Coastguard Worker               pLowBandImag + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER,
1340*e5436536SAndroid Build Coastguard Worker               hSbrDec->hHBE->noCols, pLowBandReal, pLowBandImag,
1341*e5436536SAndroid Build Coastguard Worker               hSbrDec->LppTrans.lpcFilterStatesRealHBE,
1342*e5436536SAndroid Build Coastguard Worker               hSbrDec->LppTrans.lpcFilterStatesImagHBE,
1343*e5436536SAndroid Build Coastguard Worker               0 /* not required for keeping states updated in this frame*/,
1344*e5436536SAndroid Build Coastguard Worker               hSbrDec->scale_lb, hSbrDec->scale_lb,
1345*e5436536SAndroid Build Coastguard Worker               &hSbrDec->qmfDomainInCh->scaling.hb_scale, hHeaderData->timeStep,
1346*e5436536SAndroid Build Coastguard Worker               hFrameData->frameInfo.borders[0],
1347*e5436536SAndroid Build Coastguard Worker               hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_NOOUT);
1348*e5436536SAndroid Build Coastguard Worker         }
1349*e5436536SAndroid Build Coastguard Worker 
1350*e5436536SAndroid Build Coastguard Worker         QmfTransposerApply(
1351*e5436536SAndroid Build Coastguard Worker             hSbrDec->hHBE,
1352*e5436536SAndroid Build Coastguard Worker             pLowBandReal + hSbrDec->LppTrans.pSettings->overlap +
1353*e5436536SAndroid Build Coastguard Worker                 hSbrDec->hHBE->noCols + LPC_ORDER,
1354*e5436536SAndroid Build Coastguard Worker             pLowBandImag + hSbrDec->LppTrans.pSettings->overlap +
1355*e5436536SAndroid Build Coastguard Worker                 hSbrDec->hHBE->noCols + LPC_ORDER,
1356*e5436536SAndroid Build Coastguard Worker             hSbrDec->hHBE->noCols, pLowBandReal, pLowBandImag,
1357*e5436536SAndroid Build Coastguard Worker             hSbrDec->LppTrans.lpcFilterStatesRealHBE,
1358*e5436536SAndroid Build Coastguard Worker             hSbrDec->LppTrans.lpcFilterStatesImagHBE,
1359*e5436536SAndroid Build Coastguard Worker             hPrevFrameData->prevSbrPitchInBins, hSbrDec->scale_lb,
1360*e5436536SAndroid Build Coastguard Worker             hSbrDec->scale_hbe, &hSbrDec->qmfDomainInCh->scaling.hb_scale,
1361*e5436536SAndroid Build Coastguard Worker             hHeaderData->timeStep, hFrameData->frameInfo.borders[0],
1362*e5436536SAndroid Build Coastguard Worker             hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_OUTDIFF);
1363*e5436536SAndroid Build Coastguard Worker       }
1364*e5436536SAndroid Build Coastguard Worker 
1365*e5436536SAndroid Build Coastguard Worker       if (hFrameData->sbrPatchingMode == 0) {
1366*e5436536SAndroid Build Coastguard Worker         for (i = startSlot; i < hSbrDec->LppTrans.pSettings->overlap; i++) {
1367*e5436536SAndroid Build Coastguard Worker           /*
1368*e5436536SAndroid Build Coastguard Worker           Store the unmodified qmf Slots values for upper part of spectrum
1369*e5436536SAndroid Build Coastguard Worker           (required for LPC filtering) required if next frame is a HBE frame
1370*e5436536SAndroid Build Coastguard Worker           */
1371*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(hSbrDec->qmfDomainInCh->hQmfSlotsReal[i],
1372*e5436536SAndroid Build Coastguard Worker                     hSbrDec->LppTrans.lpcFilterStatesRealHBE[i + LPC_ORDER],
1373*e5436536SAndroid Build Coastguard Worker                     (64) * sizeof(FIXP_DBL));
1374*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(hSbrDec->qmfDomainInCh->hQmfSlotsImag[i],
1375*e5436536SAndroid Build Coastguard Worker                     hSbrDec->LppTrans.lpcFilterStatesImagHBE[i + LPC_ORDER],
1376*e5436536SAndroid Build Coastguard Worker                     (64) * sizeof(FIXP_DBL));
1377*e5436536SAndroid Build Coastguard Worker         }
1378*e5436536SAndroid Build Coastguard Worker 
1379*e5436536SAndroid Build Coastguard Worker         for (i = startSlot; i < hSbrDec->LppTrans.pSettings->overlap; i++) {
1380*e5436536SAndroid Build Coastguard Worker           /*
1381*e5436536SAndroid Build Coastguard Worker           Store the unmodified qmf Slots values for upper part of spectrum
1382*e5436536SAndroid Build Coastguard Worker           (required for LPC filtering) required if next frame is a HBE frame
1383*e5436536SAndroid Build Coastguard Worker           */
1384*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(
1385*e5436536SAndroid Build Coastguard Worker               hSbrDec->qmfDomainInCh->hQmfSlotsReal[i],
1386*e5436536SAndroid Build Coastguard Worker               hSbrDec->codecQMFBufferReal[hSbrDec->hHBE->noCols -
1387*e5436536SAndroid Build Coastguard Worker                                           hSbrDec->LppTrans.pSettings->overlap +
1388*e5436536SAndroid Build Coastguard Worker                                           i],
1389*e5436536SAndroid Build Coastguard Worker               new_lsb * sizeof(FIXP_DBL));
1390*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(
1391*e5436536SAndroid Build Coastguard Worker               hSbrDec->qmfDomainInCh->hQmfSlotsImag[i],
1392*e5436536SAndroid Build Coastguard Worker               hSbrDec->codecQMFBufferImag[hSbrDec->hHBE->noCols -
1393*e5436536SAndroid Build Coastguard Worker                                           hSbrDec->LppTrans.pSettings->overlap +
1394*e5436536SAndroid Build Coastguard Worker                                           i],
1395*e5436536SAndroid Build Coastguard Worker               new_lsb * sizeof(FIXP_DBL));
1396*e5436536SAndroid Build Coastguard Worker         }
1397*e5436536SAndroid Build Coastguard Worker       }
1398*e5436536SAndroid Build Coastguard Worker     }
1399*e5436536SAndroid Build Coastguard Worker   }
1400*e5436536SAndroid Build Coastguard Worker 
1401*e5436536SAndroid Build Coastguard Worker   {
1402*e5436536SAndroid Build Coastguard Worker     int adapt_lb = 0, diff = 0,
1403*e5436536SAndroid Build Coastguard Worker         new_scale = hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
1404*e5436536SAndroid Build Coastguard Worker 
1405*e5436536SAndroid Build Coastguard Worker     if ((hSbrDec->qmfDomainInCh->scaling.ov_lb_scale !=
1406*e5436536SAndroid Build Coastguard Worker          hSbrDec->qmfDomainInCh->scaling.lb_scale) &&
1407*e5436536SAndroid Build Coastguard Worker         startSlot != 0) {
1408*e5436536SAndroid Build Coastguard Worker       /* we need to adapt spectrum to have equal scale factor, always larger
1409*e5436536SAndroid Build Coastguard Worker        * than zero */
1410*e5436536SAndroid Build Coastguard Worker       diff = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale) -
1411*e5436536SAndroid Build Coastguard Worker              SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.lb_scale);
1412*e5436536SAndroid Build Coastguard Worker 
1413*e5436536SAndroid Build Coastguard Worker       if (diff > 0) {
1414*e5436536SAndroid Build Coastguard Worker         adapt_lb = 1;
1415*e5436536SAndroid Build Coastguard Worker         diff = -diff;
1416*e5436536SAndroid Build Coastguard Worker         new_scale = hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
1417*e5436536SAndroid Build Coastguard Worker       }
1418*e5436536SAndroid Build Coastguard Worker 
1419*e5436536SAndroid Build Coastguard Worker       stopBand = new_lsb;
1420*e5436536SAndroid Build Coastguard Worker     }
1421*e5436536SAndroid Build Coastguard Worker 
1422*e5436536SAndroid Build Coastguard Worker     if (hFrameData->sbrPatchingMode == 1) {
1423*e5436536SAndroid Build Coastguard Worker       /* scale states from LegSBR filterstates buffer */
1424*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER; i++) {
1425*e5436536SAndroid Build Coastguard Worker         scaleValues(hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i], new_lsb,
1426*e5436536SAndroid Build Coastguard Worker                     diff);
1427*e5436536SAndroid Build Coastguard Worker         if (!useLP) {
1428*e5436536SAndroid Build Coastguard Worker           scaleValues(hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i], new_lsb,
1429*e5436536SAndroid Build Coastguard Worker                       diff);
1430*e5436536SAndroid Build Coastguard Worker         }
1431*e5436536SAndroid Build Coastguard Worker       }
1432*e5436536SAndroid Build Coastguard Worker 
1433*e5436536SAndroid Build Coastguard Worker       if (flags & SBRDEC_SYNTAX_USAC) {
1434*e5436536SAndroid Build Coastguard Worker         /* get missing states between old and new x_over from LegSBR
1435*e5436536SAndroid Build Coastguard Worker          * filterstates buffer */
1436*e5436536SAndroid Build Coastguard Worker         /* in case of legacy SBR we leave these values zeroed out */
1437*e5436536SAndroid Build Coastguard Worker         for (i = startSlot; i < hSbrDec->LppTrans.pSettings->overlap; i++) {
1438*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(&OverlapBufferReal[i][old_lsb],
1439*e5436536SAndroid Build Coastguard Worker                     &hSbrDec->LppTrans
1440*e5436536SAndroid Build Coastguard Worker                          .lpcFilterStatesRealLegSBR[LPC_ORDER + i][old_lsb],
1441*e5436536SAndroid Build Coastguard Worker                     fMax(new_lsb - old_lsb, 0) * sizeof(FIXP_DBL));
1442*e5436536SAndroid Build Coastguard Worker           if (!useLP) {
1443*e5436536SAndroid Build Coastguard Worker             FDKmemcpy(&OverlapBufferImag[i][old_lsb],
1444*e5436536SAndroid Build Coastguard Worker                       &hSbrDec->LppTrans
1445*e5436536SAndroid Build Coastguard Worker                            .lpcFilterStatesImagLegSBR[LPC_ORDER + i][old_lsb],
1446*e5436536SAndroid Build Coastguard Worker                       fMax(new_lsb - old_lsb, 0) * sizeof(FIXP_DBL));
1447*e5436536SAndroid Build Coastguard Worker           }
1448*e5436536SAndroid Build Coastguard Worker         }
1449*e5436536SAndroid Build Coastguard Worker       }
1450*e5436536SAndroid Build Coastguard Worker 
1451*e5436536SAndroid Build Coastguard Worker       if (new_lsb > old_lsb) {
1452*e5436536SAndroid Build Coastguard Worker         stopBand = old_lsb;
1453*e5436536SAndroid Build Coastguard Worker       }
1454*e5436536SAndroid Build Coastguard Worker     }
1455*e5436536SAndroid Build Coastguard Worker     if ((adapt_lb == 1) && (stopBand > startBand)) {
1456*e5436536SAndroid Build Coastguard Worker       for (l = startSlot; l < hSbrDec->LppTrans.pSettings->overlap; l++) {
1457*e5436536SAndroid Build Coastguard Worker         scaleValues(OverlapBufferReal[l] + startBand, stopBand - startBand,
1458*e5436536SAndroid Build Coastguard Worker                     diff);
1459*e5436536SAndroid Build Coastguard Worker         if (!useLP) {
1460*e5436536SAndroid Build Coastguard Worker           scaleValues(OverlapBufferImag[l] + startBand, stopBand - startBand,
1461*e5436536SAndroid Build Coastguard Worker                       diff);
1462*e5436536SAndroid Build Coastguard Worker         }
1463*e5436536SAndroid Build Coastguard Worker       }
1464*e5436536SAndroid Build Coastguard Worker     }
1465*e5436536SAndroid Build Coastguard Worker     hSbrDec->qmfDomainInCh->scaling.ov_lb_scale = new_scale;
1466*e5436536SAndroid Build Coastguard Worker   }
1467*e5436536SAndroid Build Coastguard Worker 
1468*e5436536SAndroid Build Coastguard Worker   sbrError = ResetLimiterBands(hHeaderData->freqBandData.limiterBandTable,
1469*e5436536SAndroid Build Coastguard Worker                                &hHeaderData->freqBandData.noLimiterBands,
1470*e5436536SAndroid Build Coastguard Worker                                hHeaderData->freqBandData.freqBandTable[0],
1471*e5436536SAndroid Build Coastguard Worker                                hHeaderData->freqBandData.nSfb[0],
1472*e5436536SAndroid Build Coastguard Worker                                hSbrDec->LppTrans.pSettings->patchParam,
1473*e5436536SAndroid Build Coastguard Worker                                hSbrDec->LppTrans.pSettings->noOfPatches,
1474*e5436536SAndroid Build Coastguard Worker                                hHeaderData->bs_data.limiterBands,
1475*e5436536SAndroid Build Coastguard Worker                                hFrameData->sbrPatchingMode,
1476*e5436536SAndroid Build Coastguard Worker                                GetxOverBandQmfTransposer(hSbrDec->hHBE),
1477*e5436536SAndroid Build Coastguard Worker                                Get41SbrQmfTransposer(hSbrDec->hHBE));
1478*e5436536SAndroid Build Coastguard Worker 
1479*e5436536SAndroid Build Coastguard Worker   hSbrDec->SbrCalculateEnvelope.sbrPatchingMode = hFrameData->sbrPatchingMode;
1480*e5436536SAndroid Build Coastguard Worker 
1481*e5436536SAndroid Build Coastguard Worker   return sbrError;
1482*e5436536SAndroid Build Coastguard Worker }
1483