xref: /aosp_15_r20/external/aac/libSBRenc/src/ps_main.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 - 2018 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 encoder library ******************************
96*e5436536SAndroid Build Coastguard Worker 
97*e5436536SAndroid Build Coastguard Worker    Author(s):   M. Multrus
98*e5436536SAndroid Build Coastguard Worker 
99*e5436536SAndroid Build Coastguard Worker    Description: PS Wrapper, Downmix
100*e5436536SAndroid Build Coastguard Worker 
101*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
102*e5436536SAndroid Build Coastguard Worker 
103*e5436536SAndroid Build Coastguard Worker #include "ps_main.h"
104*e5436536SAndroid Build Coastguard Worker 
105*e5436536SAndroid Build Coastguard Worker /* Includes ******************************************************************/
106*e5436536SAndroid Build Coastguard Worker #include "ps_bitenc.h"
107*e5436536SAndroid Build Coastguard Worker #include "sbrenc_ram.h"
108*e5436536SAndroid Build Coastguard Worker 
109*e5436536SAndroid Build Coastguard Worker /*--------------- function declarations --------------------*/
110*e5436536SAndroid Build Coastguard Worker static void psFindBestScaling(
111*e5436536SAndroid Build Coastguard Worker     HANDLE_PARAMETRIC_STEREO hParametricStereo,
112*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
113*e5436536SAndroid Build Coastguard Worker     UCHAR *dynBandScale, FIXP_DBL *maxBandValue, SCHAR *dmxScale);
114*e5436536SAndroid Build Coastguard Worker 
115*e5436536SAndroid Build Coastguard Worker /*------------- function definitions ----------------*/
PSEnc_Create(HANDLE_PARAMETRIC_STEREO * phParametricStereo)116*e5436536SAndroid Build Coastguard Worker FDK_PSENC_ERROR PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo) {
117*e5436536SAndroid Build Coastguard Worker   FDK_PSENC_ERROR error = PSENC_OK;
118*e5436536SAndroid Build Coastguard Worker   HANDLE_PARAMETRIC_STEREO hParametricStereo = NULL;
119*e5436536SAndroid Build Coastguard Worker 
120*e5436536SAndroid Build Coastguard Worker   if (phParametricStereo == NULL) {
121*e5436536SAndroid Build Coastguard Worker     error = PSENC_INVALID_HANDLE;
122*e5436536SAndroid Build Coastguard Worker   } else {
123*e5436536SAndroid Build Coastguard Worker     int i;
124*e5436536SAndroid Build Coastguard Worker 
125*e5436536SAndroid Build Coastguard Worker     if (NULL == (hParametricStereo = GetRam_ParamStereo())) {
126*e5436536SAndroid Build Coastguard Worker       error = PSENC_MEMORY_ERROR;
127*e5436536SAndroid Build Coastguard Worker       goto bail;
128*e5436536SAndroid Build Coastguard Worker     }
129*e5436536SAndroid Build Coastguard Worker     FDKmemclear(hParametricStereo, sizeof(PARAMETRIC_STEREO));
130*e5436536SAndroid Build Coastguard Worker 
131*e5436536SAndroid Build Coastguard Worker     if (PSENC_OK !=
132*e5436536SAndroid Build Coastguard Worker         (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) {
133*e5436536SAndroid Build Coastguard Worker       error = PSENC_MEMORY_ERROR;
134*e5436536SAndroid Build Coastguard Worker       goto bail;
135*e5436536SAndroid Build Coastguard Worker     }
136*e5436536SAndroid Build Coastguard Worker 
137*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < MAX_PS_CHANNELS; i++) {
138*e5436536SAndroid Build Coastguard Worker       if (FDKhybridAnalysisOpen(
139*e5436536SAndroid Build Coastguard Worker               &hParametricStereo->fdkHybAnaFilter[i],
140*e5436536SAndroid Build Coastguard Worker               hParametricStereo->__staticHybAnaStatesLF[i],
141*e5436536SAndroid Build Coastguard Worker               sizeof(hParametricStereo->__staticHybAnaStatesLF[i]),
142*e5436536SAndroid Build Coastguard Worker               hParametricStereo->__staticHybAnaStatesHF[i],
143*e5436536SAndroid Build Coastguard Worker               sizeof(hParametricStereo->__staticHybAnaStatesHF[i])) != 0) {
144*e5436536SAndroid Build Coastguard Worker         error = PSENC_MEMORY_ERROR;
145*e5436536SAndroid Build Coastguard Worker         goto bail;
146*e5436536SAndroid Build Coastguard Worker       }
147*e5436536SAndroid Build Coastguard Worker     }
148*e5436536SAndroid Build Coastguard Worker   }
149*e5436536SAndroid Build Coastguard Worker 
150*e5436536SAndroid Build Coastguard Worker bail:
151*e5436536SAndroid Build Coastguard Worker   if (phParametricStereo != NULL) {
152*e5436536SAndroid Build Coastguard Worker     *phParametricStereo = hParametricStereo; /* return allocated handle */
153*e5436536SAndroid Build Coastguard Worker   }
154*e5436536SAndroid Build Coastguard Worker 
155*e5436536SAndroid Build Coastguard Worker   if (error != PSENC_OK) {
156*e5436536SAndroid Build Coastguard Worker     PSEnc_Destroy(phParametricStereo);
157*e5436536SAndroid Build Coastguard Worker   }
158*e5436536SAndroid Build Coastguard Worker   return error;
159*e5436536SAndroid Build Coastguard Worker }
160*e5436536SAndroid Build Coastguard Worker 
PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo,const HANDLE_PSENC_CONFIG hPsEncConfig,INT noQmfSlots,INT noQmfBands,UCHAR * dynamic_RAM)161*e5436536SAndroid Build Coastguard Worker FDK_PSENC_ERROR PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo,
162*e5436536SAndroid Build Coastguard Worker                            const HANDLE_PSENC_CONFIG hPsEncConfig,
163*e5436536SAndroid Build Coastguard Worker                            INT noQmfSlots, INT noQmfBands, UCHAR *dynamic_RAM) {
164*e5436536SAndroid Build Coastguard Worker   FDK_PSENC_ERROR error = PSENC_OK;
165*e5436536SAndroid Build Coastguard Worker 
166*e5436536SAndroid Build Coastguard Worker   if ((NULL == hParametricStereo) || (NULL == hPsEncConfig)) {
167*e5436536SAndroid Build Coastguard Worker     error = PSENC_INVALID_HANDLE;
168*e5436536SAndroid Build Coastguard Worker   } else {
169*e5436536SAndroid Build Coastguard Worker     int ch, i;
170*e5436536SAndroid Build Coastguard Worker 
171*e5436536SAndroid Build Coastguard Worker     hParametricStereo->initPS = 1;
172*e5436536SAndroid Build Coastguard Worker     hParametricStereo->noQmfSlots = noQmfSlots;
173*e5436536SAndroid Build Coastguard Worker     hParametricStereo->noQmfBands = noQmfBands;
174*e5436536SAndroid Build Coastguard Worker 
175*e5436536SAndroid Build Coastguard Worker     /* clear delay lines */
176*e5436536SAndroid Build Coastguard Worker     FDKmemclear(hParametricStereo->qmfDelayLines,
177*e5436536SAndroid Build Coastguard Worker                 sizeof(hParametricStereo->qmfDelayLines));
178*e5436536SAndroid Build Coastguard Worker 
179*e5436536SAndroid Build Coastguard Worker     hParametricStereo->qmfDelayScale = FRACT_BITS - 1;
180*e5436536SAndroid Build Coastguard Worker 
181*e5436536SAndroid Build Coastguard Worker     /* create configuration for hybrid filter bank */
182*e5436536SAndroid Build Coastguard Worker     for (ch = 0; ch < MAX_PS_CHANNELS; ch++) {
183*e5436536SAndroid Build Coastguard Worker       FDKhybridAnalysisInit(&hParametricStereo->fdkHybAnaFilter[ch],
184*e5436536SAndroid Build Coastguard Worker                             THREE_TO_TEN, 64, 64, 1);
185*e5436536SAndroid Build Coastguard Worker     } /* ch */
186*e5436536SAndroid Build Coastguard Worker 
187*e5436536SAndroid Build Coastguard Worker     FDKhybridSynthesisInit(&hParametricStereo->fdkHybSynFilter, THREE_TO_TEN,
188*e5436536SAndroid Build Coastguard Worker                            64, 64);
189*e5436536SAndroid Build Coastguard Worker 
190*e5436536SAndroid Build Coastguard Worker     /* determine average delay */
191*e5436536SAndroid Build Coastguard Worker     hParametricStereo->psDelay =
192*e5436536SAndroid Build Coastguard Worker         (HYBRID_FILTER_DELAY * hParametricStereo->noQmfBands);
193*e5436536SAndroid Build Coastguard Worker 
194*e5436536SAndroid Build Coastguard Worker     if ((hPsEncConfig->maxEnvelopes < PSENC_NENV_1) ||
195*e5436536SAndroid Build Coastguard Worker         (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX)) {
196*e5436536SAndroid Build Coastguard Worker       hPsEncConfig->maxEnvelopes = PSENC_NENV_DEFAULT;
197*e5436536SAndroid Build Coastguard Worker     }
198*e5436536SAndroid Build Coastguard Worker     hParametricStereo->maxEnvelopes = hPsEncConfig->maxEnvelopes;
199*e5436536SAndroid Build Coastguard Worker 
200*e5436536SAndroid Build Coastguard Worker     if (PSENC_OK !=
201*e5436536SAndroid Build Coastguard Worker         (error = FDKsbrEnc_InitPSEncode(
202*e5436536SAndroid Build Coastguard Worker              hParametricStereo->hPsEncode, (PS_BANDS)hPsEncConfig->nStereoBands,
203*e5436536SAndroid Build Coastguard Worker              hPsEncConfig->iidQuantErrorThreshold))) {
204*e5436536SAndroid Build Coastguard Worker       goto bail;
205*e5436536SAndroid Build Coastguard Worker     }
206*e5436536SAndroid Build Coastguard Worker 
207*e5436536SAndroid Build Coastguard Worker     for (ch = 0; ch < MAX_PS_CHANNELS; ch++) {
208*e5436536SAndroid Build Coastguard Worker       FIXP_DBL *pDynReal = GetRam_Sbr_envRBuffer(ch, dynamic_RAM);
209*e5436536SAndroid Build Coastguard Worker       FIXP_DBL *pDynImag = GetRam_Sbr_envIBuffer(ch, dynamic_RAM);
210*e5436536SAndroid Build Coastguard Worker 
211*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < HYBRID_FRAMESIZE; i++) {
212*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][ch][0] =
213*e5436536SAndroid Build Coastguard Worker             &pDynReal[i * MAX_HYBRID_BANDS];
214*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][ch][1] =
215*e5436536SAndroid Build Coastguard Worker             &pDynImag[i * MAX_HYBRID_BANDS];
216*e5436536SAndroid Build Coastguard Worker         ;
217*e5436536SAndroid Build Coastguard Worker       }
218*e5436536SAndroid Build Coastguard Worker 
219*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < HYBRID_READ_OFFSET; i++) {
220*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[i][ch][0] =
221*e5436536SAndroid Build Coastguard Worker             hParametricStereo->__staticHybridData[i][ch][0];
222*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[i][ch][1] =
223*e5436536SAndroid Build Coastguard Worker             hParametricStereo->__staticHybridData[i][ch][1];
224*e5436536SAndroid Build Coastguard Worker       }
225*e5436536SAndroid Build Coastguard Worker     } /* ch */
226*e5436536SAndroid Build Coastguard Worker 
227*e5436536SAndroid Build Coastguard Worker     /* clear static hybrid buffer */
228*e5436536SAndroid Build Coastguard Worker     FDKmemclear(hParametricStereo->__staticHybridData,
229*e5436536SAndroid Build Coastguard Worker                 sizeof(hParametricStereo->__staticHybridData));
230*e5436536SAndroid Build Coastguard Worker 
231*e5436536SAndroid Build Coastguard Worker     /* clear bs buffer */
232*e5436536SAndroid Build Coastguard Worker     FDKmemclear(hParametricStereo->psOut, sizeof(hParametricStereo->psOut));
233*e5436536SAndroid Build Coastguard Worker 
234*e5436536SAndroid Build Coastguard Worker     hParametricStereo->psOut[0].enablePSHeader =
235*e5436536SAndroid Build Coastguard Worker         1; /* write ps header in first frame */
236*e5436536SAndroid Build Coastguard Worker 
237*e5436536SAndroid Build Coastguard Worker     /* clear scaling buffer */
238*e5436536SAndroid Build Coastguard Worker     FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR) * PS_MAX_BANDS);
239*e5436536SAndroid Build Coastguard Worker     FDKmemclear(hParametricStereo->maxBandValue,
240*e5436536SAndroid Build Coastguard Worker                 sizeof(FIXP_DBL) * PS_MAX_BANDS);
241*e5436536SAndroid Build Coastguard Worker 
242*e5436536SAndroid Build Coastguard Worker   } /* valid handle */
243*e5436536SAndroid Build Coastguard Worker bail:
244*e5436536SAndroid Build Coastguard Worker   return error;
245*e5436536SAndroid Build Coastguard Worker }
246*e5436536SAndroid Build Coastguard Worker 
PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO * phParametricStereo)247*e5436536SAndroid Build Coastguard Worker FDK_PSENC_ERROR PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *phParametricStereo) {
248*e5436536SAndroid Build Coastguard Worker   FDK_PSENC_ERROR error = PSENC_OK;
249*e5436536SAndroid Build Coastguard Worker 
250*e5436536SAndroid Build Coastguard Worker   if (NULL != phParametricStereo) {
251*e5436536SAndroid Build Coastguard Worker     HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo;
252*e5436536SAndroid Build Coastguard Worker     if (hParametricStereo != NULL) {
253*e5436536SAndroid Build Coastguard Worker       FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode);
254*e5436536SAndroid Build Coastguard Worker       FreeRam_ParamStereo(phParametricStereo);
255*e5436536SAndroid Build Coastguard Worker     }
256*e5436536SAndroid Build Coastguard Worker   }
257*e5436536SAndroid Build Coastguard Worker 
258*e5436536SAndroid Build Coastguard Worker   return error;
259*e5436536SAndroid Build Coastguard Worker }
260*e5436536SAndroid Build Coastguard Worker 
ExtractPSParameters(HANDLE_PARAMETRIC_STEREO hParametricStereo,const int sendHeader,FIXP_DBL * hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2])261*e5436536SAndroid Build Coastguard Worker static FDK_PSENC_ERROR ExtractPSParameters(
262*e5436536SAndroid Build Coastguard Worker     HANDLE_PARAMETRIC_STEREO hParametricStereo, const int sendHeader,
263*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2]) {
264*e5436536SAndroid Build Coastguard Worker   FDK_PSENC_ERROR error = PSENC_OK;
265*e5436536SAndroid Build Coastguard Worker 
266*e5436536SAndroid Build Coastguard Worker   if (hParametricStereo == NULL) {
267*e5436536SAndroid Build Coastguard Worker     error = PSENC_INVALID_HANDLE;
268*e5436536SAndroid Build Coastguard Worker   } else {
269*e5436536SAndroid Build Coastguard Worker     /* call ps encode function */
270*e5436536SAndroid Build Coastguard Worker     if (hParametricStereo->initPS) {
271*e5436536SAndroid Build Coastguard Worker       hParametricStereo->psOut[1] = hParametricStereo->psOut[0];
272*e5436536SAndroid Build Coastguard Worker     }
273*e5436536SAndroid Build Coastguard Worker     hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
274*e5436536SAndroid Build Coastguard Worker 
275*e5436536SAndroid Build Coastguard Worker     if (PSENC_OK !=
276*e5436536SAndroid Build Coastguard Worker         (error = FDKsbrEnc_PSEncode(
277*e5436536SAndroid Build Coastguard Worker              hParametricStereo->hPsEncode, &hParametricStereo->psOut[1],
278*e5436536SAndroid Build Coastguard Worker              hParametricStereo->dynBandScale, hParametricStereo->maxEnvelopes,
279*e5436536SAndroid Build Coastguard Worker              hybridData, hParametricStereo->noQmfSlots, sendHeader))) {
280*e5436536SAndroid Build Coastguard Worker       goto bail;
281*e5436536SAndroid Build Coastguard Worker     }
282*e5436536SAndroid Build Coastguard Worker 
283*e5436536SAndroid Build Coastguard Worker     if (hParametricStereo->initPS) {
284*e5436536SAndroid Build Coastguard Worker       hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
285*e5436536SAndroid Build Coastguard Worker       hParametricStereo->initPS = 0;
286*e5436536SAndroid Build Coastguard Worker     }
287*e5436536SAndroid Build Coastguard Worker   }
288*e5436536SAndroid Build Coastguard Worker bail:
289*e5436536SAndroid Build Coastguard Worker   return error;
290*e5436536SAndroid Build Coastguard Worker }
291*e5436536SAndroid Build Coastguard Worker 
DownmixPSQmfData(HANDLE_PARAMETRIC_STEREO hParametricStereo,HANDLE_QMF_FILTER_BANK sbrSynthQmf,FIXP_DBL ** RESTRICT mixRealQmfData,FIXP_DBL ** RESTRICT mixImagQmfData,INT_PCM * downsampledOutSignal,const UINT downsampledOutSignalBufSize,FIXP_DBL * hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],const INT noQmfSlots,const INT psQmfScale[MAX_PS_CHANNELS],SCHAR * qmfScale)292*e5436536SAndroid Build Coastguard Worker static FDK_PSENC_ERROR DownmixPSQmfData(
293*e5436536SAndroid Build Coastguard Worker     HANDLE_PARAMETRIC_STEREO hParametricStereo,
294*e5436536SAndroid Build Coastguard Worker     HANDLE_QMF_FILTER_BANK sbrSynthQmf, FIXP_DBL **RESTRICT mixRealQmfData,
295*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **RESTRICT mixImagQmfData, INT_PCM *downsampledOutSignal,
296*e5436536SAndroid Build Coastguard Worker     const UINT downsampledOutSignalBufSize,
297*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
298*e5436536SAndroid Build Coastguard Worker     const INT noQmfSlots, const INT psQmfScale[MAX_PS_CHANNELS],
299*e5436536SAndroid Build Coastguard Worker     SCHAR *qmfScale) {
300*e5436536SAndroid Build Coastguard Worker   FDK_PSENC_ERROR error = PSENC_OK;
301*e5436536SAndroid Build Coastguard Worker 
302*e5436536SAndroid Build Coastguard Worker   if (hParametricStereo == NULL) {
303*e5436536SAndroid Build Coastguard Worker     error = PSENC_INVALID_HANDLE;
304*e5436536SAndroid Build Coastguard Worker   } else {
305*e5436536SAndroid Build Coastguard Worker     int n, k;
306*e5436536SAndroid Build Coastguard Worker     C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 2 * 64)
307*e5436536SAndroid Build Coastguard Worker 
308*e5436536SAndroid Build Coastguard Worker     /* define scalings */
309*e5436536SAndroid Build Coastguard Worker     int dynQmfScale = fixMax(
310*e5436536SAndroid Build Coastguard Worker         0, hParametricStereo->dmxScale -
311*e5436536SAndroid Build Coastguard Worker                1); /* scale one bit more for addition of left and right */
312*e5436536SAndroid Build Coastguard Worker     int downmixScale = psQmfScale[0] - dynQmfScale;
313*e5436536SAndroid Build Coastguard Worker     const FIXP_DBL maxStereoScaleFactor = MAXVAL_DBL; /* 2.f/2.f */
314*e5436536SAndroid Build Coastguard Worker 
315*e5436536SAndroid Build Coastguard Worker     for (n = 0; n < noQmfSlots; n++) {
316*e5436536SAndroid Build Coastguard Worker       FIXP_DBL tmpHybrid[2][MAX_HYBRID_BANDS];
317*e5436536SAndroid Build Coastguard Worker 
318*e5436536SAndroid Build Coastguard Worker       for (k = 0; k < 71; k++) {
319*e5436536SAndroid Build Coastguard Worker         int dynScale, sc; /* scaling */
320*e5436536SAndroid Build Coastguard Worker         FIXP_DBL tmpLeftReal, tmpRightReal, tmpLeftImag, tmpRightImag;
321*e5436536SAndroid Build Coastguard Worker         FIXP_DBL tmpScaleFactor, stereoScaleFactor;
322*e5436536SAndroid Build Coastguard Worker 
323*e5436536SAndroid Build Coastguard Worker         tmpLeftReal = hybridData[n][0][0][k];
324*e5436536SAndroid Build Coastguard Worker         tmpLeftImag = hybridData[n][0][1][k];
325*e5436536SAndroid Build Coastguard Worker         tmpRightReal = hybridData[n][1][0][k];
326*e5436536SAndroid Build Coastguard Worker         tmpRightImag = hybridData[n][1][1][k];
327*e5436536SAndroid Build Coastguard Worker 
328*e5436536SAndroid Build Coastguard Worker         sc = fixMax(
329*e5436536SAndroid Build Coastguard Worker             0, CntLeadingZeros(fixMax(
330*e5436536SAndroid Build Coastguard Worker                    fixMax(fixp_abs(tmpLeftReal), fixp_abs(tmpLeftImag)),
331*e5436536SAndroid Build Coastguard Worker                    fixMax(fixp_abs(tmpRightReal), fixp_abs(tmpRightImag)))) -
332*e5436536SAndroid Build Coastguard Worker                    2);
333*e5436536SAndroid Build Coastguard Worker 
334*e5436536SAndroid Build Coastguard Worker         tmpLeftReal <<= sc;
335*e5436536SAndroid Build Coastguard Worker         tmpLeftImag <<= sc;
336*e5436536SAndroid Build Coastguard Worker         tmpRightReal <<= sc;
337*e5436536SAndroid Build Coastguard Worker         tmpRightImag <<= sc;
338*e5436536SAndroid Build Coastguard Worker         dynScale = fixMin(sc - dynQmfScale, DFRACT_BITS - 1);
339*e5436536SAndroid Build Coastguard Worker 
340*e5436536SAndroid Build Coastguard Worker         /* calc stereo scale factor to avoid loss of energy in bands */
341*e5436536SAndroid Build Coastguard Worker         /* stereo scale factor = min(2.0f, sqrt( (abs(l(k, n)^2 + abs(r(k, n)^2
342*e5436536SAndroid Build Coastguard Worker          * )))/(0.5f*abs(l(k, n) + r(k, n))) )) */
343*e5436536SAndroid Build Coastguard Worker         stereoScaleFactor = fPow2Div2(tmpLeftReal) + fPow2Div2(tmpLeftImag) +
344*e5436536SAndroid Build Coastguard Worker                             fPow2Div2(tmpRightReal) + fPow2Div2(tmpRightImag);
345*e5436536SAndroid Build Coastguard Worker 
346*e5436536SAndroid Build Coastguard Worker         /* might be that tmpScaleFactor becomes negative, so fabs(.) */
347*e5436536SAndroid Build Coastguard Worker         tmpScaleFactor =
348*e5436536SAndroid Build Coastguard Worker             fixp_abs(stereoScaleFactor + fMult(tmpLeftReal, tmpRightReal) +
349*e5436536SAndroid Build Coastguard Worker                      fMult(tmpLeftImag, tmpRightImag));
350*e5436536SAndroid Build Coastguard Worker 
351*e5436536SAndroid Build Coastguard Worker         /* min(2.0f, sqrt(stereoScaleFactor/(0.5f*tmpScaleFactor)))  */
352*e5436536SAndroid Build Coastguard Worker         if ((stereoScaleFactor >> 1) <
353*e5436536SAndroid Build Coastguard Worker             fMult(maxStereoScaleFactor, tmpScaleFactor)) {
354*e5436536SAndroid Build Coastguard Worker           int sc_num = CountLeadingBits(stereoScaleFactor);
355*e5436536SAndroid Build Coastguard Worker           int sc_denum = CountLeadingBits(tmpScaleFactor);
356*e5436536SAndroid Build Coastguard Worker           sc = -(sc_num - sc_denum);
357*e5436536SAndroid Build Coastguard Worker 
358*e5436536SAndroid Build Coastguard Worker           tmpScaleFactor = schur_div((stereoScaleFactor << (sc_num)) >> 1,
359*e5436536SAndroid Build Coastguard Worker                                      tmpScaleFactor << sc_denum, 16);
360*e5436536SAndroid Build Coastguard Worker 
361*e5436536SAndroid Build Coastguard Worker           /* prevent odd scaling for next sqrt calculation */
362*e5436536SAndroid Build Coastguard Worker           if (sc & 0x1) {
363*e5436536SAndroid Build Coastguard Worker             sc++;
364*e5436536SAndroid Build Coastguard Worker             tmpScaleFactor >>= 1;
365*e5436536SAndroid Build Coastguard Worker           }
366*e5436536SAndroid Build Coastguard Worker           stereoScaleFactor = sqrtFixp(tmpScaleFactor);
367*e5436536SAndroid Build Coastguard Worker           stereoScaleFactor <<= (sc >> 1);
368*e5436536SAndroid Build Coastguard Worker         } else {
369*e5436536SAndroid Build Coastguard Worker           stereoScaleFactor = maxStereoScaleFactor;
370*e5436536SAndroid Build Coastguard Worker         }
371*e5436536SAndroid Build Coastguard Worker 
372*e5436536SAndroid Build Coastguard Worker         /* write data to hybrid output */
373*e5436536SAndroid Build Coastguard Worker         tmpHybrid[0][k] = fMultDiv2(stereoScaleFactor,
374*e5436536SAndroid Build Coastguard Worker                                     (FIXP_DBL)(tmpLeftReal + tmpRightReal)) >>
375*e5436536SAndroid Build Coastguard Worker                           dynScale;
376*e5436536SAndroid Build Coastguard Worker         tmpHybrid[1][k] = fMultDiv2(stereoScaleFactor,
377*e5436536SAndroid Build Coastguard Worker                                     (FIXP_DBL)(tmpLeftImag + tmpRightImag)) >>
378*e5436536SAndroid Build Coastguard Worker                           dynScale;
379*e5436536SAndroid Build Coastguard Worker 
380*e5436536SAndroid Build Coastguard Worker       } /* hybrid bands - k */
381*e5436536SAndroid Build Coastguard Worker 
382*e5436536SAndroid Build Coastguard Worker       FDKhybridSynthesisApply(&hParametricStereo->fdkHybSynFilter, tmpHybrid[0],
383*e5436536SAndroid Build Coastguard Worker                               tmpHybrid[1], mixRealQmfData[n],
384*e5436536SAndroid Build Coastguard Worker                               mixImagQmfData[n]);
385*e5436536SAndroid Build Coastguard Worker 
386*e5436536SAndroid Build Coastguard Worker       qmfSynthesisFilteringSlot(
387*e5436536SAndroid Build Coastguard Worker           sbrSynthQmf, mixRealQmfData[n], mixImagQmfData[n], downmixScale - 7,
388*e5436536SAndroid Build Coastguard Worker           downmixScale - 7,
389*e5436536SAndroid Build Coastguard Worker           downsampledOutSignal + (n * sbrSynthQmf->no_channels), 1,
390*e5436536SAndroid Build Coastguard Worker           pWorkBuffer);
391*e5436536SAndroid Build Coastguard Worker 
392*e5436536SAndroid Build Coastguard Worker     } /* slots */
393*e5436536SAndroid Build Coastguard Worker 
394*e5436536SAndroid Build Coastguard Worker     *qmfScale = -downmixScale + 7;
395*e5436536SAndroid Build Coastguard Worker 
396*e5436536SAndroid Build Coastguard Worker     C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2 * 64)
397*e5436536SAndroid Build Coastguard Worker 
398*e5436536SAndroid Build Coastguard Worker     {
399*e5436536SAndroid Build Coastguard Worker       const INT noQmfSlots2 = hParametricStereo->noQmfSlots >> 1;
400*e5436536SAndroid Build Coastguard Worker       const int noQmfBands = hParametricStereo->noQmfBands;
401*e5436536SAndroid Build Coastguard Worker 
402*e5436536SAndroid Build Coastguard Worker       INT scale, i, j, slotOffset;
403*e5436536SAndroid Build Coastguard Worker 
404*e5436536SAndroid Build Coastguard Worker       FIXP_DBL tmp[2][64];
405*e5436536SAndroid Build Coastguard Worker 
406*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < noQmfSlots2; i++) {
407*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(tmp[0], hParametricStereo->qmfDelayLines[0][i],
408*e5436536SAndroid Build Coastguard Worker                   noQmfBands * sizeof(FIXP_DBL));
409*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(tmp[1], hParametricStereo->qmfDelayLines[1][i],
410*e5436536SAndroid Build Coastguard Worker                   noQmfBands * sizeof(FIXP_DBL));
411*e5436536SAndroid Build Coastguard Worker 
412*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(hParametricStereo->qmfDelayLines[0][i],
413*e5436536SAndroid Build Coastguard Worker                   mixRealQmfData[i + noQmfSlots2],
414*e5436536SAndroid Build Coastguard Worker                   noQmfBands * sizeof(FIXP_DBL));
415*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(hParametricStereo->qmfDelayLines[1][i],
416*e5436536SAndroid Build Coastguard Worker                   mixImagQmfData[i + noQmfSlots2],
417*e5436536SAndroid Build Coastguard Worker                   noQmfBands * sizeof(FIXP_DBL));
418*e5436536SAndroid Build Coastguard Worker 
419*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(mixRealQmfData[i + noQmfSlots2], mixRealQmfData[i],
420*e5436536SAndroid Build Coastguard Worker                   noQmfBands * sizeof(FIXP_DBL));
421*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(mixImagQmfData[i + noQmfSlots2], mixImagQmfData[i],
422*e5436536SAndroid Build Coastguard Worker                   noQmfBands * sizeof(FIXP_DBL));
423*e5436536SAndroid Build Coastguard Worker 
424*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(mixRealQmfData[i], tmp[0], noQmfBands * sizeof(FIXP_DBL));
425*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(mixImagQmfData[i], tmp[1], noQmfBands * sizeof(FIXP_DBL));
426*e5436536SAndroid Build Coastguard Worker       }
427*e5436536SAndroid Build Coastguard Worker 
428*e5436536SAndroid Build Coastguard Worker       if (hParametricStereo->qmfDelayScale > *qmfScale) {
429*e5436536SAndroid Build Coastguard Worker         scale = hParametricStereo->qmfDelayScale - *qmfScale;
430*e5436536SAndroid Build Coastguard Worker         slotOffset = 0;
431*e5436536SAndroid Build Coastguard Worker       } else {
432*e5436536SAndroid Build Coastguard Worker         scale = *qmfScale - hParametricStereo->qmfDelayScale;
433*e5436536SAndroid Build Coastguard Worker         slotOffset = noQmfSlots2;
434*e5436536SAndroid Build Coastguard Worker       }
435*e5436536SAndroid Build Coastguard Worker 
436*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < noQmfSlots2; i++) {
437*e5436536SAndroid Build Coastguard Worker         for (j = 0; j < noQmfBands; j++) {
438*e5436536SAndroid Build Coastguard Worker           mixRealQmfData[i + slotOffset][j] >>= scale;
439*e5436536SAndroid Build Coastguard Worker           mixImagQmfData[i + slotOffset][j] >>= scale;
440*e5436536SAndroid Build Coastguard Worker         }
441*e5436536SAndroid Build Coastguard Worker       }
442*e5436536SAndroid Build Coastguard Worker 
443*e5436536SAndroid Build Coastguard Worker       scale = *qmfScale;
444*e5436536SAndroid Build Coastguard Worker       *qmfScale = fMin(*qmfScale, hParametricStereo->qmfDelayScale);
445*e5436536SAndroid Build Coastguard Worker       hParametricStereo->qmfDelayScale = scale;
446*e5436536SAndroid Build Coastguard Worker     }
447*e5436536SAndroid Build Coastguard Worker 
448*e5436536SAndroid Build Coastguard Worker   } /* valid handle */
449*e5436536SAndroid Build Coastguard Worker 
450*e5436536SAndroid Build Coastguard Worker   return error;
451*e5436536SAndroid Build Coastguard Worker }
452*e5436536SAndroid Build Coastguard Worker 
FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo,HANDLE_FDK_BITSTREAM hBitstream)453*e5436536SAndroid Build Coastguard Worker INT FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo,
454*e5436536SAndroid Build Coastguard Worker                                 HANDLE_FDK_BITSTREAM hBitstream) {
455*e5436536SAndroid Build Coastguard Worker   return (
456*e5436536SAndroid Build Coastguard Worker       (hParametricStereo != NULL)
457*e5436536SAndroid Build Coastguard Worker           ? FDKsbrEnc_WritePSBitstream(&hParametricStereo->psOut[0], hBitstream)
458*e5436536SAndroid Build Coastguard Worker           : 0);
459*e5436536SAndroid Build Coastguard Worker }
460*e5436536SAndroid Build Coastguard Worker 
FDKsbrEnc_PSEnc_ParametricStereoProcessing(HANDLE_PARAMETRIC_STEREO hParametricStereo,INT_PCM * samples[2],UINT samplesBufSize,QMF_FILTER_BANK ** hQmfAnalysis,FIXP_DBL ** RESTRICT downmixedRealQmfData,FIXP_DBL ** RESTRICT downmixedImagQmfData,INT_PCM * downsampledOutSignal,HANDLE_QMF_FILTER_BANK sbrSynthQmf,SCHAR * qmfScale,const int sendHeader)461*e5436536SAndroid Build Coastguard Worker FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing(
462*e5436536SAndroid Build Coastguard Worker     HANDLE_PARAMETRIC_STEREO hParametricStereo, INT_PCM *samples[2],
463*e5436536SAndroid Build Coastguard Worker     UINT samplesBufSize, QMF_FILTER_BANK **hQmfAnalysis,
464*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **RESTRICT downmixedRealQmfData,
465*e5436536SAndroid Build Coastguard Worker     FIXP_DBL **RESTRICT downmixedImagQmfData, INT_PCM *downsampledOutSignal,
466*e5436536SAndroid Build Coastguard Worker     HANDLE_QMF_FILTER_BANK sbrSynthQmf, SCHAR *qmfScale, const int sendHeader) {
467*e5436536SAndroid Build Coastguard Worker   FDK_PSENC_ERROR error = PSENC_OK;
468*e5436536SAndroid Build Coastguard Worker   INT psQmfScale[MAX_PS_CHANNELS] = {0};
469*e5436536SAndroid Build Coastguard Worker   int psCh, i;
470*e5436536SAndroid Build Coastguard Worker   C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 4 * 64)
471*e5436536SAndroid Build Coastguard Worker 
472*e5436536SAndroid Build Coastguard Worker   for (psCh = 0; psCh < MAX_PS_CHANNELS; psCh++) {
473*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < hQmfAnalysis[psCh]->no_col; i++) {
474*e5436536SAndroid Build Coastguard Worker       qmfAnalysisFilteringSlot(
475*e5436536SAndroid Build Coastguard Worker           hQmfAnalysis[psCh], &pWorkBuffer[2 * 64], /* qmfReal[64] */
476*e5436536SAndroid Build Coastguard Worker           &pWorkBuffer[3 * 64],                     /* qmfImag[64] */
477*e5436536SAndroid Build Coastguard Worker           samples[psCh] + i * hQmfAnalysis[psCh]->no_channels, 1,
478*e5436536SAndroid Build Coastguard Worker           &pWorkBuffer[0 * 64] /* qmf workbuffer 2*64 */
479*e5436536SAndroid Build Coastguard Worker       );
480*e5436536SAndroid Build Coastguard Worker 
481*e5436536SAndroid Build Coastguard Worker       FDKhybridAnalysisApply(
482*e5436536SAndroid Build Coastguard Worker           &hParametricStereo->fdkHybAnaFilter[psCh],
483*e5436536SAndroid Build Coastguard Worker           &pWorkBuffer[2 * 64], /* qmfReal[64] */
484*e5436536SAndroid Build Coastguard Worker           &pWorkBuffer[3 * 64], /* qmfImag[64] */
485*e5436536SAndroid Build Coastguard Worker           hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][psCh][0],
486*e5436536SAndroid Build Coastguard Worker           hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][psCh][1]);
487*e5436536SAndroid Build Coastguard Worker 
488*e5436536SAndroid Build Coastguard Worker     } /* no_col loop  i  */
489*e5436536SAndroid Build Coastguard Worker 
490*e5436536SAndroid Build Coastguard Worker     psQmfScale[psCh] = hQmfAnalysis[psCh]->outScalefactor;
491*e5436536SAndroid Build Coastguard Worker 
492*e5436536SAndroid Build Coastguard Worker   } /* for psCh */
493*e5436536SAndroid Build Coastguard Worker 
494*e5436536SAndroid Build Coastguard Worker   C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 4 * 64)
495*e5436536SAndroid Build Coastguard Worker 
496*e5436536SAndroid Build Coastguard Worker   /* find best scaling in new QMF and Hybrid data */
497*e5436536SAndroid Build Coastguard Worker   psFindBestScaling(
498*e5436536SAndroid Build Coastguard Worker       hParametricStereo, &hParametricStereo->pHybridData[HYBRID_READ_OFFSET],
499*e5436536SAndroid Build Coastguard Worker       hParametricStereo->dynBandScale, hParametricStereo->maxBandValue,
500*e5436536SAndroid Build Coastguard Worker       &hParametricStereo->dmxScale);
501*e5436536SAndroid Build Coastguard Worker 
502*e5436536SAndroid Build Coastguard Worker   /* extract the ps parameters */
503*e5436536SAndroid Build Coastguard Worker   if (PSENC_OK !=
504*e5436536SAndroid Build Coastguard Worker       (error = ExtractPSParameters(hParametricStereo, sendHeader,
505*e5436536SAndroid Build Coastguard Worker                                    &hParametricStereo->pHybridData[0]))) {
506*e5436536SAndroid Build Coastguard Worker     goto bail;
507*e5436536SAndroid Build Coastguard Worker   }
508*e5436536SAndroid Build Coastguard Worker 
509*e5436536SAndroid Build Coastguard Worker   /* save hybrid date for next frame */
510*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < HYBRID_READ_OFFSET; i++) {
511*e5436536SAndroid Build Coastguard Worker     FDKmemcpy(
512*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[i][0][0],
513*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][0][0],
514*e5436536SAndroid Build Coastguard Worker         MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* left, real */
515*e5436536SAndroid Build Coastguard Worker     FDKmemcpy(
516*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[i][0][1],
517*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][0][1],
518*e5436536SAndroid Build Coastguard Worker         MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* left, imag */
519*e5436536SAndroid Build Coastguard Worker     FDKmemcpy(
520*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[i][1][0],
521*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][1][0],
522*e5436536SAndroid Build Coastguard Worker         MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* right, real */
523*e5436536SAndroid Build Coastguard Worker     FDKmemcpy(
524*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[i][1][1],
525*e5436536SAndroid Build Coastguard Worker         hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][1][1],
526*e5436536SAndroid Build Coastguard Worker         MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* right, imag */
527*e5436536SAndroid Build Coastguard Worker   }
528*e5436536SAndroid Build Coastguard Worker 
529*e5436536SAndroid Build Coastguard Worker   /* downmix and hybrid synthesis */
530*e5436536SAndroid Build Coastguard Worker   if (PSENC_OK !=
531*e5436536SAndroid Build Coastguard Worker       (error = DownmixPSQmfData(
532*e5436536SAndroid Build Coastguard Worker            hParametricStereo, sbrSynthQmf, downmixedRealQmfData,
533*e5436536SAndroid Build Coastguard Worker            downmixedImagQmfData, downsampledOutSignal, samplesBufSize,
534*e5436536SAndroid Build Coastguard Worker            &hParametricStereo->pHybridData[HYBRID_READ_OFFSET],
535*e5436536SAndroid Build Coastguard Worker            hParametricStereo->noQmfSlots, psQmfScale, qmfScale))) {
536*e5436536SAndroid Build Coastguard Worker     goto bail;
537*e5436536SAndroid Build Coastguard Worker   }
538*e5436536SAndroid Build Coastguard Worker 
539*e5436536SAndroid Build Coastguard Worker bail:
540*e5436536SAndroid Build Coastguard Worker 
541*e5436536SAndroid Build Coastguard Worker   return error;
542*e5436536SAndroid Build Coastguard Worker }
543*e5436536SAndroid Build Coastguard Worker 
psFindBestScaling(HANDLE_PARAMETRIC_STEREO hParametricStereo,FIXP_DBL * hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],UCHAR * dynBandScale,FIXP_DBL * maxBandValue,SCHAR * dmxScale)544*e5436536SAndroid Build Coastguard Worker static void psFindBestScaling(
545*e5436536SAndroid Build Coastguard Worker     HANDLE_PARAMETRIC_STEREO hParametricStereo,
546*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
547*e5436536SAndroid Build Coastguard Worker     UCHAR *dynBandScale, FIXP_DBL *maxBandValue, SCHAR *dmxScale) {
548*e5436536SAndroid Build Coastguard Worker   HANDLE_PS_ENCODE hPsEncode = hParametricStereo->hPsEncode;
549*e5436536SAndroid Build Coastguard Worker 
550*e5436536SAndroid Build Coastguard Worker   INT group, bin, col, band;
551*e5436536SAndroid Build Coastguard Worker   const INT frameSize = hParametricStereo->noQmfSlots;
552*e5436536SAndroid Build Coastguard Worker   const INT psBands = (INT)hPsEncode->psEncMode;
553*e5436536SAndroid Build Coastguard Worker   const INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups;
554*e5436536SAndroid Build Coastguard Worker 
555*e5436536SAndroid Build Coastguard Worker   /* group wise scaling */
556*e5436536SAndroid Build Coastguard Worker   FIXP_DBL maxVal[2][PS_MAX_BANDS];
557*e5436536SAndroid Build Coastguard Worker   FIXP_DBL maxValue = FL2FXCONST_DBL(0.f);
558*e5436536SAndroid Build Coastguard Worker 
559*e5436536SAndroid Build Coastguard Worker   FDKmemclear(maxVal, sizeof(maxVal));
560*e5436536SAndroid Build Coastguard Worker 
561*e5436536SAndroid Build Coastguard Worker   /* start with hybrid data */
562*e5436536SAndroid Build Coastguard Worker   for (group = 0; group < nIidGroups; group++) {
563*e5436536SAndroid Build Coastguard Worker     /* Translate group to bin */
564*e5436536SAndroid Build Coastguard Worker     bin = hPsEncode->subband2parameterIndex[group];
565*e5436536SAndroid Build Coastguard Worker 
566*e5436536SAndroid Build Coastguard Worker     /* Translate from 20 bins to 10 bins */
567*e5436536SAndroid Build Coastguard Worker     if (hPsEncode->psEncMode == PS_BANDS_COARSE) {
568*e5436536SAndroid Build Coastguard Worker       bin >>= 1;
569*e5436536SAndroid Build Coastguard Worker     }
570*e5436536SAndroid Build Coastguard Worker 
571*e5436536SAndroid Build Coastguard Worker     /* QMF downmix scaling */
572*e5436536SAndroid Build Coastguard Worker     for (col = 0; col < frameSize; col++) {
573*e5436536SAndroid Build Coastguard Worker       int i, section = (col < frameSize - HYBRID_READ_OFFSET) ? 0 : 1;
574*e5436536SAndroid Build Coastguard Worker       FIXP_DBL tmp = maxVal[section][bin];
575*e5436536SAndroid Build Coastguard Worker       for (i = hPsEncode->iidGroupBorders[group];
576*e5436536SAndroid Build Coastguard Worker            i < hPsEncode->iidGroupBorders[group + 1]; i++) {
577*e5436536SAndroid Build Coastguard Worker         tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][0][0][i]));
578*e5436536SAndroid Build Coastguard Worker         tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][0][1][i]));
579*e5436536SAndroid Build Coastguard Worker         tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][1][0][i]));
580*e5436536SAndroid Build Coastguard Worker         tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][1][1][i]));
581*e5436536SAndroid Build Coastguard Worker       }
582*e5436536SAndroid Build Coastguard Worker       maxVal[section][bin] = tmp;
583*e5436536SAndroid Build Coastguard Worker     }
584*e5436536SAndroid Build Coastguard Worker   } /* nIidGroups */
585*e5436536SAndroid Build Coastguard Worker 
586*e5436536SAndroid Build Coastguard Worker   /* convert maxSpec to maxScaling, find scaling space */
587*e5436536SAndroid Build Coastguard Worker   for (band = 0; band < psBands; band++) {
588*e5436536SAndroid Build Coastguard Worker #ifndef MULT_16x16
589*e5436536SAndroid Build Coastguard Worker     dynBandScale[band] =
590*e5436536SAndroid Build Coastguard Worker         CountLeadingBits(fixMax(maxVal[0][band], maxBandValue[band]));
591*e5436536SAndroid Build Coastguard Worker #else
592*e5436536SAndroid Build Coastguard Worker     dynBandScale[band] = fixMax(
593*e5436536SAndroid Build Coastguard Worker         0, CountLeadingBits(fixMax(maxVal[0][band], maxBandValue[band])) -
594*e5436536SAndroid Build Coastguard Worker                FRACT_BITS);
595*e5436536SAndroid Build Coastguard Worker #endif
596*e5436536SAndroid Build Coastguard Worker     maxValue = fixMax(maxValue, fixMax(maxVal[0][band], maxVal[1][band]));
597*e5436536SAndroid Build Coastguard Worker     maxBandValue[band] = fixMax(maxVal[0][band], maxVal[1][band]);
598*e5436536SAndroid Build Coastguard Worker   }
599*e5436536SAndroid Build Coastguard Worker 
600*e5436536SAndroid Build Coastguard Worker     /* calculate maximal scaling for QMF downmix */
601*e5436536SAndroid Build Coastguard Worker #ifndef MULT_16x16
602*e5436536SAndroid Build Coastguard Worker   *dmxScale = fixMin(DFRACT_BITS, CountLeadingBits(maxValue));
603*e5436536SAndroid Build Coastguard Worker #else
604*e5436536SAndroid Build Coastguard Worker   *dmxScale = fixMax(0, fixMin(FRACT_BITS, CountLeadingBits((maxValue))));
605*e5436536SAndroid Build Coastguard Worker #endif
606*e5436536SAndroid Build Coastguard Worker }
607