xref: /aosp_15_r20/external/aac/libAACdec/src/stereo.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 - 2019 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 /**************************** AAC decoder library ******************************
96*e5436536SAndroid Build Coastguard Worker 
97*e5436536SAndroid Build Coastguard Worker    Author(s):   Josef Hoepfl
98*e5436536SAndroid Build Coastguard Worker 
99*e5436536SAndroid Build Coastguard Worker    Description: joint stereo processing
100*e5436536SAndroid Build Coastguard Worker 
101*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
102*e5436536SAndroid Build Coastguard Worker 
103*e5436536SAndroid Build Coastguard Worker #include "stereo.h"
104*e5436536SAndroid Build Coastguard Worker 
105*e5436536SAndroid Build Coastguard Worker #include "aac_rom.h"
106*e5436536SAndroid Build Coastguard Worker #include "FDK_bitstream.h"
107*e5436536SAndroid Build Coastguard Worker #include "channelinfo.h"
108*e5436536SAndroid Build Coastguard Worker #include "FDK_audio.h"
109*e5436536SAndroid Build Coastguard Worker 
110*e5436536SAndroid Build Coastguard Worker enum { L = 0, R = 1 };
111*e5436536SAndroid Build Coastguard Worker 
112*e5436536SAndroid Build Coastguard Worker #include "block.h"
113*e5436536SAndroid Build Coastguard Worker 
CJointStereo_Read(HANDLE_FDK_BITSTREAM bs,CJointStereoData * pJointStereoData,const int windowGroups,const int scaleFactorBandsTransmitted,const int max_sfb_ste_clear,CJointStereoPersistentData * pJointStereoPersistentData,CCplxPredictionData * cplxPredictionData,int cplxPredictionActiv,int scaleFactorBandsTotal,int windowSequence,const UINT flags)114*e5436536SAndroid Build Coastguard Worker int CJointStereo_Read(HANDLE_FDK_BITSTREAM bs,
115*e5436536SAndroid Build Coastguard Worker                       CJointStereoData *pJointStereoData,
116*e5436536SAndroid Build Coastguard Worker                       const int windowGroups,
117*e5436536SAndroid Build Coastguard Worker                       const int scaleFactorBandsTransmitted,
118*e5436536SAndroid Build Coastguard Worker                       const int max_sfb_ste_clear,
119*e5436536SAndroid Build Coastguard Worker                       CJointStereoPersistentData *pJointStereoPersistentData,
120*e5436536SAndroid Build Coastguard Worker                       CCplxPredictionData *cplxPredictionData,
121*e5436536SAndroid Build Coastguard Worker                       int cplxPredictionActiv, int scaleFactorBandsTotal,
122*e5436536SAndroid Build Coastguard Worker                       int windowSequence, const UINT flags) {
123*e5436536SAndroid Build Coastguard Worker   int group, band;
124*e5436536SAndroid Build Coastguard Worker 
125*e5436536SAndroid Build Coastguard Worker   pJointStereoData->MsMaskPresent = (UCHAR)FDKreadBits(bs, 2);
126*e5436536SAndroid Build Coastguard Worker 
127*e5436536SAndroid Build Coastguard Worker   FDKmemclear(pJointStereoData->MsUsed,
128*e5436536SAndroid Build Coastguard Worker               scaleFactorBandsTransmitted * sizeof(UCHAR));
129*e5436536SAndroid Build Coastguard Worker 
130*e5436536SAndroid Build Coastguard Worker   pJointStereoData->cplx_pred_flag = 0;
131*e5436536SAndroid Build Coastguard Worker   if (cplxPredictionActiv) {
132*e5436536SAndroid Build Coastguard Worker     cplxPredictionData->pred_dir = 0;
133*e5436536SAndroid Build Coastguard Worker     cplxPredictionData->complex_coef = 0;
134*e5436536SAndroid Build Coastguard Worker     cplxPredictionData->use_prev_frame = 0;
135*e5436536SAndroid Build Coastguard Worker     cplxPredictionData->igf_pred_dir = 0;
136*e5436536SAndroid Build Coastguard Worker   }
137*e5436536SAndroid Build Coastguard Worker 
138*e5436536SAndroid Build Coastguard Worker   switch (pJointStereoData->MsMaskPresent) {
139*e5436536SAndroid Build Coastguard Worker     case 0: /* no M/S */
140*e5436536SAndroid Build Coastguard Worker       /* all flags are already cleared */
141*e5436536SAndroid Build Coastguard Worker       break;
142*e5436536SAndroid Build Coastguard Worker 
143*e5436536SAndroid Build Coastguard Worker     case 1: /* read ms_used */
144*e5436536SAndroid Build Coastguard Worker       for (group = 0; group < windowGroups; group++) {
145*e5436536SAndroid Build Coastguard Worker         for (band = 0; band < scaleFactorBandsTransmitted; band++) {
146*e5436536SAndroid Build Coastguard Worker           pJointStereoData->MsUsed[band] |= (FDKreadBits(bs, 1) << group);
147*e5436536SAndroid Build Coastguard Worker         }
148*e5436536SAndroid Build Coastguard Worker       }
149*e5436536SAndroid Build Coastguard Worker       break;
150*e5436536SAndroid Build Coastguard Worker 
151*e5436536SAndroid Build Coastguard Worker     case 2: /* full spectrum M/S */
152*e5436536SAndroid Build Coastguard Worker       for (band = 0; band < scaleFactorBandsTransmitted; band++) {
153*e5436536SAndroid Build Coastguard Worker         pJointStereoData->MsUsed[band] = 255; /* set all flags to 1 */
154*e5436536SAndroid Build Coastguard Worker       }
155*e5436536SAndroid Build Coastguard Worker       break;
156*e5436536SAndroid Build Coastguard Worker 
157*e5436536SAndroid Build Coastguard Worker     case 3:
158*e5436536SAndroid Build Coastguard Worker       /* M/S coding is disabled, complex stereo prediction is enabled */
159*e5436536SAndroid Build Coastguard Worker       if (flags & (AC_USAC | AC_RSVD50 | AC_RSV603DA)) {
160*e5436536SAndroid Build Coastguard Worker         if (cplxPredictionActiv) { /* 'if (stereoConfigIndex == 0)' */
161*e5436536SAndroid Build Coastguard Worker 
162*e5436536SAndroid Build Coastguard Worker           pJointStereoData->cplx_pred_flag = 1;
163*e5436536SAndroid Build Coastguard Worker 
164*e5436536SAndroid Build Coastguard Worker           /* cplx_pred_data()  cp. ISO/IEC FDIS 23003-3:2011(E)  Table 26 */
165*e5436536SAndroid Build Coastguard Worker           int cplx_pred_all = 0; /* local use only */
166*e5436536SAndroid Build Coastguard Worker           cplx_pred_all = FDKreadBits(bs, 1);
167*e5436536SAndroid Build Coastguard Worker 
168*e5436536SAndroid Build Coastguard Worker           if (cplx_pred_all) {
169*e5436536SAndroid Build Coastguard Worker             for (group = 0; group < windowGroups; group++) {
170*e5436536SAndroid Build Coastguard Worker               UCHAR groupmask = ((UCHAR)1 << group);
171*e5436536SAndroid Build Coastguard Worker               for (band = 0; band < scaleFactorBandsTransmitted; band++) {
172*e5436536SAndroid Build Coastguard Worker                 pJointStereoData->MsUsed[band] |= groupmask;
173*e5436536SAndroid Build Coastguard Worker               }
174*e5436536SAndroid Build Coastguard Worker             }
175*e5436536SAndroid Build Coastguard Worker           } else {
176*e5436536SAndroid Build Coastguard Worker             for (group = 0; group < windowGroups; group++) {
177*e5436536SAndroid Build Coastguard Worker               for (band = 0; band < scaleFactorBandsTransmitted;
178*e5436536SAndroid Build Coastguard Worker                    band += SFB_PER_PRED_BAND) {
179*e5436536SAndroid Build Coastguard Worker                 pJointStereoData->MsUsed[band] |= (FDKreadBits(bs, 1) << group);
180*e5436536SAndroid Build Coastguard Worker                 if ((band + 1) < scaleFactorBandsTotal) {
181*e5436536SAndroid Build Coastguard Worker                   pJointStereoData->MsUsed[band + 1] |=
182*e5436536SAndroid Build Coastguard Worker                       (pJointStereoData->MsUsed[band] & ((UCHAR)1 << group));
183*e5436536SAndroid Build Coastguard Worker                 }
184*e5436536SAndroid Build Coastguard Worker               }
185*e5436536SAndroid Build Coastguard Worker             }
186*e5436536SAndroid Build Coastguard Worker           }
187*e5436536SAndroid Build Coastguard Worker         } else {
188*e5436536SAndroid Build Coastguard Worker           return -1;
189*e5436536SAndroid Build Coastguard Worker         }
190*e5436536SAndroid Build Coastguard Worker       }
191*e5436536SAndroid Build Coastguard Worker       break;
192*e5436536SAndroid Build Coastguard Worker   }
193*e5436536SAndroid Build Coastguard Worker 
194*e5436536SAndroid Build Coastguard Worker   if (cplxPredictionActiv) {
195*e5436536SAndroid Build Coastguard Worker     /* If all sfb are MS-ed then no complex prediction */
196*e5436536SAndroid Build Coastguard Worker     if (pJointStereoData->MsMaskPresent == 3) {
197*e5436536SAndroid Build Coastguard Worker       if (pJointStereoData->cplx_pred_flag) {
198*e5436536SAndroid Build Coastguard Worker         int delta_code_time = 0;
199*e5436536SAndroid Build Coastguard Worker 
200*e5436536SAndroid Build Coastguard Worker         /* set pointer to Huffman codebooks */
201*e5436536SAndroid Build Coastguard Worker         const CodeBookDescription *hcb = &AACcodeBookDescriptionTable[BOOKSCL];
202*e5436536SAndroid Build Coastguard Worker         /* set predictors to zero in case of a transition from long to short
203*e5436536SAndroid Build Coastguard Worker          * window sequences and vice versa */
204*e5436536SAndroid Build Coastguard Worker         if (((windowSequence == BLOCK_SHORT) &&
205*e5436536SAndroid Build Coastguard Worker              (pJointStereoPersistentData->winSeqPrev != BLOCK_SHORT)) ||
206*e5436536SAndroid Build Coastguard Worker             ((pJointStereoPersistentData->winSeqPrev == BLOCK_SHORT) &&
207*e5436536SAndroid Build Coastguard Worker              (windowSequence != BLOCK_SHORT))) {
208*e5436536SAndroid Build Coastguard Worker           FDKmemclear(pJointStereoPersistentData->alpha_q_re_prev,
209*e5436536SAndroid Build Coastguard Worker                       JointStereoMaximumGroups * JointStereoMaximumBands *
210*e5436536SAndroid Build Coastguard Worker                           sizeof(SHORT));
211*e5436536SAndroid Build Coastguard Worker           FDKmemclear(pJointStereoPersistentData->alpha_q_im_prev,
212*e5436536SAndroid Build Coastguard Worker                       JointStereoMaximumGroups * JointStereoMaximumBands *
213*e5436536SAndroid Build Coastguard Worker                           sizeof(SHORT));
214*e5436536SAndroid Build Coastguard Worker         }
215*e5436536SAndroid Build Coastguard Worker         {
216*e5436536SAndroid Build Coastguard Worker           FDKmemclear(cplxPredictionData->alpha_q_re,
217*e5436536SAndroid Build Coastguard Worker                       JointStereoMaximumGroups * JointStereoMaximumBands *
218*e5436536SAndroid Build Coastguard Worker                           sizeof(SHORT));
219*e5436536SAndroid Build Coastguard Worker           FDKmemclear(cplxPredictionData->alpha_q_im,
220*e5436536SAndroid Build Coastguard Worker                       JointStereoMaximumGroups * JointStereoMaximumBands *
221*e5436536SAndroid Build Coastguard Worker                           sizeof(SHORT));
222*e5436536SAndroid Build Coastguard Worker         }
223*e5436536SAndroid Build Coastguard Worker 
224*e5436536SAndroid Build Coastguard Worker         /* 0 = mid->side prediction, 1 = side->mid prediction */
225*e5436536SAndroid Build Coastguard Worker         cplxPredictionData->pred_dir = FDKreadBits(bs, 1);
226*e5436536SAndroid Build Coastguard Worker         cplxPredictionData->complex_coef = FDKreadBits(bs, 1);
227*e5436536SAndroid Build Coastguard Worker 
228*e5436536SAndroid Build Coastguard Worker         if (cplxPredictionData->complex_coef) {
229*e5436536SAndroid Build Coastguard Worker           if (flags & AC_INDEP) {
230*e5436536SAndroid Build Coastguard Worker             cplxPredictionData->use_prev_frame = 0;
231*e5436536SAndroid Build Coastguard Worker           } else {
232*e5436536SAndroid Build Coastguard Worker             cplxPredictionData->use_prev_frame = FDKreadBits(bs, 1);
233*e5436536SAndroid Build Coastguard Worker           }
234*e5436536SAndroid Build Coastguard Worker         }
235*e5436536SAndroid Build Coastguard Worker 
236*e5436536SAndroid Build Coastguard Worker         if (flags & AC_INDEP) {
237*e5436536SAndroid Build Coastguard Worker           delta_code_time = 0;
238*e5436536SAndroid Build Coastguard Worker         } else {
239*e5436536SAndroid Build Coastguard Worker           delta_code_time = FDKreadBits(bs, 1);
240*e5436536SAndroid Build Coastguard Worker         }
241*e5436536SAndroid Build Coastguard Worker 
242*e5436536SAndroid Build Coastguard Worker         {
243*e5436536SAndroid Build Coastguard Worker           int last_alpha_q_re = 0, last_alpha_q_im = 0;
244*e5436536SAndroid Build Coastguard Worker 
245*e5436536SAndroid Build Coastguard Worker           for (group = 0; group < windowGroups; group++) {
246*e5436536SAndroid Build Coastguard Worker             for (band = 0; band < scaleFactorBandsTransmitted;
247*e5436536SAndroid Build Coastguard Worker                  band += SFB_PER_PRED_BAND) {
248*e5436536SAndroid Build Coastguard Worker               if (delta_code_time == 1) {
249*e5436536SAndroid Build Coastguard Worker                 if (group > 0) {
250*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_re =
251*e5436536SAndroid Build Coastguard Worker                       cplxPredictionData->alpha_q_re[group - 1][band];
252*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_im =
253*e5436536SAndroid Build Coastguard Worker                       cplxPredictionData->alpha_q_im[group - 1][band];
254*e5436536SAndroid Build Coastguard Worker                 } else if ((windowSequence == BLOCK_SHORT) &&
255*e5436536SAndroid Build Coastguard Worker                            (pJointStereoPersistentData->winSeqPrev ==
256*e5436536SAndroid Build Coastguard Worker                             BLOCK_SHORT)) {
257*e5436536SAndroid Build Coastguard Worker                   /* Included for error-robustness */
258*e5436536SAndroid Build Coastguard Worker                   if (pJointStereoPersistentData->winGroupsPrev == 0) return -1;
259*e5436536SAndroid Build Coastguard Worker 
260*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_re =
261*e5436536SAndroid Build Coastguard Worker                       pJointStereoPersistentData->alpha_q_re_prev
262*e5436536SAndroid Build Coastguard Worker                           [pJointStereoPersistentData->winGroupsPrev - 1][band];
263*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_im =
264*e5436536SAndroid Build Coastguard Worker                       pJointStereoPersistentData->alpha_q_im_prev
265*e5436536SAndroid Build Coastguard Worker                           [pJointStereoPersistentData->winGroupsPrev - 1][band];
266*e5436536SAndroid Build Coastguard Worker                 } else {
267*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_re =
268*e5436536SAndroid Build Coastguard Worker                       pJointStereoPersistentData->alpha_q_re_prev[group][band];
269*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_im =
270*e5436536SAndroid Build Coastguard Worker                       pJointStereoPersistentData->alpha_q_im_prev[group][band];
271*e5436536SAndroid Build Coastguard Worker                 }
272*e5436536SAndroid Build Coastguard Worker 
273*e5436536SAndroid Build Coastguard Worker               } else {
274*e5436536SAndroid Build Coastguard Worker                 if (band > 0) {
275*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_re =
276*e5436536SAndroid Build Coastguard Worker                       cplxPredictionData->alpha_q_re[group][band - 1];
277*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_im =
278*e5436536SAndroid Build Coastguard Worker                       cplxPredictionData->alpha_q_im[group][band - 1];
279*e5436536SAndroid Build Coastguard Worker                 } else {
280*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_re = 0;
281*e5436536SAndroid Build Coastguard Worker                   last_alpha_q_im = 0;
282*e5436536SAndroid Build Coastguard Worker                 }
283*e5436536SAndroid Build Coastguard Worker 
284*e5436536SAndroid Build Coastguard Worker               } /* if (delta_code_time == 1) */
285*e5436536SAndroid Build Coastguard Worker 
286*e5436536SAndroid Build Coastguard Worker               if (pJointStereoData->MsUsed[band] & ((UCHAR)1 << group)) {
287*e5436536SAndroid Build Coastguard Worker                 int dpcm_alpha_re, dpcm_alpha_im;
288*e5436536SAndroid Build Coastguard Worker 
289*e5436536SAndroid Build Coastguard Worker                 dpcm_alpha_re = CBlock_DecodeHuffmanWord(bs, hcb);
290*e5436536SAndroid Build Coastguard Worker                 dpcm_alpha_re -= 60;
291*e5436536SAndroid Build Coastguard Worker                 dpcm_alpha_re *= -1;
292*e5436536SAndroid Build Coastguard Worker 
293*e5436536SAndroid Build Coastguard Worker                 cplxPredictionData->alpha_q_re[group][band] =
294*e5436536SAndroid Build Coastguard Worker                     dpcm_alpha_re + last_alpha_q_re;
295*e5436536SAndroid Build Coastguard Worker 
296*e5436536SAndroid Build Coastguard Worker                 if (cplxPredictionData->complex_coef) {
297*e5436536SAndroid Build Coastguard Worker                   dpcm_alpha_im = CBlock_DecodeHuffmanWord(bs, hcb);
298*e5436536SAndroid Build Coastguard Worker                   dpcm_alpha_im -= 60;
299*e5436536SAndroid Build Coastguard Worker                   dpcm_alpha_im *= -1;
300*e5436536SAndroid Build Coastguard Worker 
301*e5436536SAndroid Build Coastguard Worker                   cplxPredictionData->alpha_q_im[group][band] =
302*e5436536SAndroid Build Coastguard Worker                       dpcm_alpha_im + last_alpha_q_im;
303*e5436536SAndroid Build Coastguard Worker                 } else {
304*e5436536SAndroid Build Coastguard Worker                   cplxPredictionData->alpha_q_im[group][band] = 0;
305*e5436536SAndroid Build Coastguard Worker                 }
306*e5436536SAndroid Build Coastguard Worker 
307*e5436536SAndroid Build Coastguard Worker               } else {
308*e5436536SAndroid Build Coastguard Worker                 cplxPredictionData->alpha_q_re[group][band] = 0;
309*e5436536SAndroid Build Coastguard Worker                 cplxPredictionData->alpha_q_im[group][band] = 0;
310*e5436536SAndroid Build Coastguard Worker               } /* if (pJointStereoData->MsUsed[band] & ((UCHAR)1 << group)) */
311*e5436536SAndroid Build Coastguard Worker 
312*e5436536SAndroid Build Coastguard Worker               if ((band + 1) <
313*e5436536SAndroid Build Coastguard Worker                   scaleFactorBandsTransmitted) { /* <= this should be the
314*e5436536SAndroid Build Coastguard Worker                                                     correct way (cp.
315*e5436536SAndroid Build Coastguard Worker                                                     ISO_IEC_FDIS_23003-0(E) */
316*e5436536SAndroid Build Coastguard Worker                 /*    7.7.2.3.2 Decoding of prediction coefficients) */
317*e5436536SAndroid Build Coastguard Worker                 cplxPredictionData->alpha_q_re[group][band + 1] =
318*e5436536SAndroid Build Coastguard Worker                     cplxPredictionData->alpha_q_re[group][band];
319*e5436536SAndroid Build Coastguard Worker                 cplxPredictionData->alpha_q_im[group][band + 1] =
320*e5436536SAndroid Build Coastguard Worker                     cplxPredictionData->alpha_q_im[group][band];
321*e5436536SAndroid Build Coastguard Worker               } /* if ((band+1)<scaleFactorBandsTotal) */
322*e5436536SAndroid Build Coastguard Worker 
323*e5436536SAndroid Build Coastguard Worker               pJointStereoPersistentData->alpha_q_re_prev[group][band] =
324*e5436536SAndroid Build Coastguard Worker                   cplxPredictionData->alpha_q_re[group][band];
325*e5436536SAndroid Build Coastguard Worker               pJointStereoPersistentData->alpha_q_im_prev[group][band] =
326*e5436536SAndroid Build Coastguard Worker                   cplxPredictionData->alpha_q_im[group][band];
327*e5436536SAndroid Build Coastguard Worker             }
328*e5436536SAndroid Build Coastguard Worker 
329*e5436536SAndroid Build Coastguard Worker             for (band = scaleFactorBandsTransmitted; band < max_sfb_ste_clear;
330*e5436536SAndroid Build Coastguard Worker                  band++) {
331*e5436536SAndroid Build Coastguard Worker               cplxPredictionData->alpha_q_re[group][band] = 0;
332*e5436536SAndroid Build Coastguard Worker               cplxPredictionData->alpha_q_im[group][band] = 0;
333*e5436536SAndroid Build Coastguard Worker               pJointStereoPersistentData->alpha_q_re_prev[group][band] = 0;
334*e5436536SAndroid Build Coastguard Worker               pJointStereoPersistentData->alpha_q_im_prev[group][band] = 0;
335*e5436536SAndroid Build Coastguard Worker             }
336*e5436536SAndroid Build Coastguard Worker           }
337*e5436536SAndroid Build Coastguard Worker         }
338*e5436536SAndroid Build Coastguard Worker       }
339*e5436536SAndroid Build Coastguard Worker     } else {
340*e5436536SAndroid Build Coastguard Worker       for (group = 0; group < windowGroups; group++) {
341*e5436536SAndroid Build Coastguard Worker         for (band = 0; band < max_sfb_ste_clear; band++) {
342*e5436536SAndroid Build Coastguard Worker           pJointStereoPersistentData->alpha_q_re_prev[group][band] = 0;
343*e5436536SAndroid Build Coastguard Worker           pJointStereoPersistentData->alpha_q_im_prev[group][band] = 0;
344*e5436536SAndroid Build Coastguard Worker         }
345*e5436536SAndroid Build Coastguard Worker       }
346*e5436536SAndroid Build Coastguard Worker     }
347*e5436536SAndroid Build Coastguard Worker 
348*e5436536SAndroid Build Coastguard Worker     pJointStereoPersistentData->winGroupsPrev = windowGroups;
349*e5436536SAndroid Build Coastguard Worker   }
350*e5436536SAndroid Build Coastguard Worker 
351*e5436536SAndroid Build Coastguard Worker   return 0;
352*e5436536SAndroid Build Coastguard Worker }
353*e5436536SAndroid Build Coastguard Worker 
CJointStereo_filterAndAdd(FIXP_DBL * in,int len,int windowLen,const FIXP_FILT * coeff,FIXP_DBL * out,UCHAR isCurrent)354*e5436536SAndroid Build Coastguard Worker static void CJointStereo_filterAndAdd(
355*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *in, int len, int windowLen, const FIXP_FILT *coeff, FIXP_DBL *out,
356*e5436536SAndroid Build Coastguard Worker     UCHAR isCurrent /* output values with even index get a
357*e5436536SAndroid Build Coastguard Worker                        positve addon (=1) or a negative addon
358*e5436536SAndroid Build Coastguard Worker                        (=0) */
359*e5436536SAndroid Build Coastguard Worker ) {
360*e5436536SAndroid Build Coastguard Worker   int i, j;
361*e5436536SAndroid Build Coastguard Worker 
362*e5436536SAndroid Build Coastguard Worker   int indices_1[] = {2, 1, 0, 1, 2, 3};
363*e5436536SAndroid Build Coastguard Worker   int indices_2[] = {1, 0, 0, 2, 3, 4};
364*e5436536SAndroid Build Coastguard Worker   int indices_3[] = {0, 0, 1, 3, 4, 5};
365*e5436536SAndroid Build Coastguard Worker 
366*e5436536SAndroid Build Coastguard Worker   int subtr_1[] = {6, 5, 4, 2, 1, 1};
367*e5436536SAndroid Build Coastguard Worker   int subtr_2[] = {5, 4, 3, 1, 1, 2};
368*e5436536SAndroid Build Coastguard Worker   int subtr_3[] = {4, 3, 2, 1, 2, 3};
369*e5436536SAndroid Build Coastguard Worker 
370*e5436536SAndroid Build Coastguard Worker   if (isCurrent == 1) {
371*e5436536SAndroid Build Coastguard Worker     /* exploit the symmetry of the table: coeff[6] = - coeff[0],
372*e5436536SAndroid Build Coastguard Worker                                           coeff[5] = - coeff[1],
373*e5436536SAndroid Build Coastguard Worker                                           coeff[4] = - coeff[2],
374*e5436536SAndroid Build Coastguard Worker                                           coeff[3] = 0
375*e5436536SAndroid Build Coastguard Worker     */
376*e5436536SAndroid Build Coastguard Worker 
377*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
378*e5436536SAndroid Build Coastguard Worker       out[0] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_1[i]]) >> SR_FNA_OUT;
379*e5436536SAndroid Build Coastguard Worker       out[0] +=
380*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[indices_1[5 - i]]) >> SR_FNA_OUT;
381*e5436536SAndroid Build Coastguard Worker     }
382*e5436536SAndroid Build Coastguard Worker 
383*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
384*e5436536SAndroid Build Coastguard Worker       out[1] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_2[i]]) >> SR_FNA_OUT;
385*e5436536SAndroid Build Coastguard Worker       out[1] +=
386*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[indices_2[5 - i]]) >> SR_FNA_OUT;
387*e5436536SAndroid Build Coastguard Worker     }
388*e5436536SAndroid Build Coastguard Worker 
389*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
390*e5436536SAndroid Build Coastguard Worker       out[2] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_3[i]]) >> SR_FNA_OUT;
391*e5436536SAndroid Build Coastguard Worker       out[2] +=
392*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[indices_3[5 - i]]) >> SR_FNA_OUT;
393*e5436536SAndroid Build Coastguard Worker     }
394*e5436536SAndroid Build Coastguard Worker 
395*e5436536SAndroid Build Coastguard Worker     for (j = 3; j < (len - 3); j++) {
396*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < 3; i++) {
397*e5436536SAndroid Build Coastguard Worker         out[j] -= (FIXP_DBL)fMultDiv2(coeff[i], in[j - 3 + i]) >> SR_FNA_OUT;
398*e5436536SAndroid Build Coastguard Worker         out[j] += (FIXP_DBL)fMultDiv2(coeff[i], in[j + 3 - i]) >> SR_FNA_OUT;
399*e5436536SAndroid Build Coastguard Worker       }
400*e5436536SAndroid Build Coastguard Worker     }
401*e5436536SAndroid Build Coastguard Worker 
402*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
403*e5436536SAndroid Build Coastguard Worker       out[len - 3] -=
404*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_1[i]]) >> SR_FNA_OUT;
405*e5436536SAndroid Build Coastguard Worker       out[len - 3] +=
406*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_1[5 - i]]) >> SR_FNA_OUT;
407*e5436536SAndroid Build Coastguard Worker     }
408*e5436536SAndroid Build Coastguard Worker 
409*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
410*e5436536SAndroid Build Coastguard Worker       out[len - 2] -=
411*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_2[i]]) >> SR_FNA_OUT;
412*e5436536SAndroid Build Coastguard Worker       out[len - 2] +=
413*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_2[5 - i]]) >> SR_FNA_OUT;
414*e5436536SAndroid Build Coastguard Worker     }
415*e5436536SAndroid Build Coastguard Worker 
416*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
417*e5436536SAndroid Build Coastguard Worker       out[len - 1] -=
418*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_3[i]]) >> SR_FNA_OUT;
419*e5436536SAndroid Build Coastguard Worker       out[len - 1] +=
420*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_3[5 - i]]) >> SR_FNA_OUT;
421*e5436536SAndroid Build Coastguard Worker     }
422*e5436536SAndroid Build Coastguard Worker 
423*e5436536SAndroid Build Coastguard Worker   } else {
424*e5436536SAndroid Build Coastguard Worker     /* exploit the symmetry of the table: coeff[6] = coeff[0],
425*e5436536SAndroid Build Coastguard Worker                                           coeff[5] = coeff[1],
426*e5436536SAndroid Build Coastguard Worker                                           coeff[4] = coeff[2]
427*e5436536SAndroid Build Coastguard Worker     */
428*e5436536SAndroid Build Coastguard Worker 
429*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
430*e5436536SAndroid Build Coastguard Worker       out[0] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_1[i]] >> SR_FNA_OUT);
431*e5436536SAndroid Build Coastguard Worker       out[0] -=
432*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[indices_1[5 - i]] >> SR_FNA_OUT);
433*e5436536SAndroid Build Coastguard Worker     }
434*e5436536SAndroid Build Coastguard Worker     out[0] -= (FIXP_DBL)fMultDiv2(coeff[3], in[0] >> SR_FNA_OUT);
435*e5436536SAndroid Build Coastguard Worker 
436*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
437*e5436536SAndroid Build Coastguard Worker       out[1] += (FIXP_DBL)fMultDiv2(coeff[i], in[indices_2[i]] >> SR_FNA_OUT);
438*e5436536SAndroid Build Coastguard Worker       out[1] +=
439*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[indices_2[5 - i]] >> SR_FNA_OUT);
440*e5436536SAndroid Build Coastguard Worker     }
441*e5436536SAndroid Build Coastguard Worker     out[1] += (FIXP_DBL)fMultDiv2(coeff[3], in[1] >> SR_FNA_OUT);
442*e5436536SAndroid Build Coastguard Worker 
443*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
444*e5436536SAndroid Build Coastguard Worker       out[2] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_3[i]] >> SR_FNA_OUT);
445*e5436536SAndroid Build Coastguard Worker       out[2] -=
446*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[indices_3[5 - i]] >> SR_FNA_OUT);
447*e5436536SAndroid Build Coastguard Worker     }
448*e5436536SAndroid Build Coastguard Worker     out[2] -= (FIXP_DBL)fMultDiv2(coeff[3], in[2] >> SR_FNA_OUT);
449*e5436536SAndroid Build Coastguard Worker 
450*e5436536SAndroid Build Coastguard Worker     for (j = 3; j < (len - 4); j++) {
451*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < 3; i++) {
452*e5436536SAndroid Build Coastguard Worker         out[j] += (FIXP_DBL)fMultDiv2(coeff[i], in[j - 3 + i] >> SR_FNA_OUT);
453*e5436536SAndroid Build Coastguard Worker         out[j] += (FIXP_DBL)fMultDiv2(coeff[i], in[j + 3 - i] >> SR_FNA_OUT);
454*e5436536SAndroid Build Coastguard Worker       }
455*e5436536SAndroid Build Coastguard Worker       out[j] += (FIXP_DBL)fMultDiv2(coeff[3], in[j] >> SR_FNA_OUT);
456*e5436536SAndroid Build Coastguard Worker 
457*e5436536SAndroid Build Coastguard Worker       j++;
458*e5436536SAndroid Build Coastguard Worker 
459*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < 3; i++) {
460*e5436536SAndroid Build Coastguard Worker         out[j] -= (FIXP_DBL)fMultDiv2(coeff[i], in[j - 3 + i] >> SR_FNA_OUT);
461*e5436536SAndroid Build Coastguard Worker         out[j] -= (FIXP_DBL)fMultDiv2(coeff[i], in[j + 3 - i] >> SR_FNA_OUT);
462*e5436536SAndroid Build Coastguard Worker       }
463*e5436536SAndroid Build Coastguard Worker       out[j] -= (FIXP_DBL)fMultDiv2(coeff[3], in[j] >> SR_FNA_OUT);
464*e5436536SAndroid Build Coastguard Worker     }
465*e5436536SAndroid Build Coastguard Worker 
466*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
467*e5436536SAndroid Build Coastguard Worker       out[len - 3] +=
468*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_1[i]] >> SR_FNA_OUT);
469*e5436536SAndroid Build Coastguard Worker       out[len - 3] +=
470*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_1[5 - i]] >> SR_FNA_OUT);
471*e5436536SAndroid Build Coastguard Worker     }
472*e5436536SAndroid Build Coastguard Worker     out[len - 3] += (FIXP_DBL)fMultDiv2(coeff[3], in[len - 3] >> SR_FNA_OUT);
473*e5436536SAndroid Build Coastguard Worker 
474*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
475*e5436536SAndroid Build Coastguard Worker       out[len - 2] -=
476*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_2[i]] >> SR_FNA_OUT);
477*e5436536SAndroid Build Coastguard Worker       out[len - 2] -=
478*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_2[5 - i]] >> SR_FNA_OUT);
479*e5436536SAndroid Build Coastguard Worker     }
480*e5436536SAndroid Build Coastguard Worker     out[len - 2] -= (FIXP_DBL)fMultDiv2(coeff[3], in[len - 2] >> SR_FNA_OUT);
481*e5436536SAndroid Build Coastguard Worker 
482*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < 3; i++) {
483*e5436536SAndroid Build Coastguard Worker       out[len - 1] +=
484*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_3[i]] >> SR_FNA_OUT);
485*e5436536SAndroid Build Coastguard Worker       out[len - 1] +=
486*e5436536SAndroid Build Coastguard Worker           (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_3[5 - i]] >> SR_FNA_OUT);
487*e5436536SAndroid Build Coastguard Worker     }
488*e5436536SAndroid Build Coastguard Worker     out[len - 1] += (FIXP_DBL)fMultDiv2(coeff[3], in[len - 1] >> SR_FNA_OUT);
489*e5436536SAndroid Build Coastguard Worker   }
490*e5436536SAndroid Build Coastguard Worker }
491*e5436536SAndroid Build Coastguard Worker 
CJointStereo_GenerateMSOutput(FIXP_DBL * pSpecLCurrBand,FIXP_DBL * pSpecRCurrBand,UINT leftScale,UINT rightScale,UINT nSfbBands)492*e5436536SAndroid Build Coastguard Worker static inline void CJointStereo_GenerateMSOutput(FIXP_DBL *pSpecLCurrBand,
493*e5436536SAndroid Build Coastguard Worker                                                  FIXP_DBL *pSpecRCurrBand,
494*e5436536SAndroid Build Coastguard Worker                                                  UINT leftScale,
495*e5436536SAndroid Build Coastguard Worker                                                  UINT rightScale,
496*e5436536SAndroid Build Coastguard Worker                                                  UINT nSfbBands) {
497*e5436536SAndroid Build Coastguard Worker   unsigned int i;
498*e5436536SAndroid Build Coastguard Worker 
499*e5436536SAndroid Build Coastguard Worker   FIXP_DBL leftCoefficient0;
500*e5436536SAndroid Build Coastguard Worker   FIXP_DBL leftCoefficient1;
501*e5436536SAndroid Build Coastguard Worker   FIXP_DBL leftCoefficient2;
502*e5436536SAndroid Build Coastguard Worker   FIXP_DBL leftCoefficient3;
503*e5436536SAndroid Build Coastguard Worker 
504*e5436536SAndroid Build Coastguard Worker   FIXP_DBL rightCoefficient0;
505*e5436536SAndroid Build Coastguard Worker   FIXP_DBL rightCoefficient1;
506*e5436536SAndroid Build Coastguard Worker   FIXP_DBL rightCoefficient2;
507*e5436536SAndroid Build Coastguard Worker   FIXP_DBL rightCoefficient3;
508*e5436536SAndroid Build Coastguard Worker 
509*e5436536SAndroid Build Coastguard Worker   for (i = nSfbBands; i > 0; i -= 4) {
510*e5436536SAndroid Build Coastguard Worker     leftCoefficient0 = pSpecLCurrBand[i - 4];
511*e5436536SAndroid Build Coastguard Worker     leftCoefficient1 = pSpecLCurrBand[i - 3];
512*e5436536SAndroid Build Coastguard Worker     leftCoefficient2 = pSpecLCurrBand[i - 2];
513*e5436536SAndroid Build Coastguard Worker     leftCoefficient3 = pSpecLCurrBand[i - 1];
514*e5436536SAndroid Build Coastguard Worker 
515*e5436536SAndroid Build Coastguard Worker     rightCoefficient0 = pSpecRCurrBand[i - 4];
516*e5436536SAndroid Build Coastguard Worker     rightCoefficient1 = pSpecRCurrBand[i - 3];
517*e5436536SAndroid Build Coastguard Worker     rightCoefficient2 = pSpecRCurrBand[i - 2];
518*e5436536SAndroid Build Coastguard Worker     rightCoefficient3 = pSpecRCurrBand[i - 1];
519*e5436536SAndroid Build Coastguard Worker 
520*e5436536SAndroid Build Coastguard Worker     /* MS output generation */
521*e5436536SAndroid Build Coastguard Worker     leftCoefficient0 >>= leftScale;
522*e5436536SAndroid Build Coastguard Worker     leftCoefficient1 >>= leftScale;
523*e5436536SAndroid Build Coastguard Worker     leftCoefficient2 >>= leftScale;
524*e5436536SAndroid Build Coastguard Worker     leftCoefficient3 >>= leftScale;
525*e5436536SAndroid Build Coastguard Worker 
526*e5436536SAndroid Build Coastguard Worker     rightCoefficient0 >>= rightScale;
527*e5436536SAndroid Build Coastguard Worker     rightCoefficient1 >>= rightScale;
528*e5436536SAndroid Build Coastguard Worker     rightCoefficient2 >>= rightScale;
529*e5436536SAndroid Build Coastguard Worker     rightCoefficient3 >>= rightScale;
530*e5436536SAndroid Build Coastguard Worker 
531*e5436536SAndroid Build Coastguard Worker     pSpecLCurrBand[i - 4] = leftCoefficient0 + rightCoefficient0;
532*e5436536SAndroid Build Coastguard Worker     pSpecLCurrBand[i - 3] = leftCoefficient1 + rightCoefficient1;
533*e5436536SAndroid Build Coastguard Worker     pSpecLCurrBand[i - 2] = leftCoefficient2 + rightCoefficient2;
534*e5436536SAndroid Build Coastguard Worker     pSpecLCurrBand[i - 1] = leftCoefficient3 + rightCoefficient3;
535*e5436536SAndroid Build Coastguard Worker 
536*e5436536SAndroid Build Coastguard Worker     pSpecRCurrBand[i - 4] = leftCoefficient0 - rightCoefficient0;
537*e5436536SAndroid Build Coastguard Worker     pSpecRCurrBand[i - 3] = leftCoefficient1 - rightCoefficient1;
538*e5436536SAndroid Build Coastguard Worker     pSpecRCurrBand[i - 2] = leftCoefficient2 - rightCoefficient2;
539*e5436536SAndroid Build Coastguard Worker     pSpecRCurrBand[i - 1] = leftCoefficient3 - rightCoefficient3;
540*e5436536SAndroid Build Coastguard Worker   }
541*e5436536SAndroid Build Coastguard Worker }
542*e5436536SAndroid Build Coastguard Worker 
CJointStereo_ApplyMS(CAacDecoderChannelInfo * pAacDecoderChannelInfo[2],CAacDecoderStaticChannelInfo * pAacDecoderStaticChannelInfo[2],FIXP_DBL * spectrumL,FIXP_DBL * spectrumR,SHORT * SFBleftScale,SHORT * SFBrightScale,SHORT * specScaleL,SHORT * specScaleR,const SHORT * pScaleFactorBandOffsets,const UCHAR * pWindowGroupLength,const int windowGroups,const int max_sfb_ste_outside,const int scaleFactorBandsTransmittedL,const int scaleFactorBandsTransmittedR,FIXP_DBL * store_dmx_re_prev,SHORT * store_dmx_re_prev_e,const int mainband_flag)543*e5436536SAndroid Build Coastguard Worker void CJointStereo_ApplyMS(
544*e5436536SAndroid Build Coastguard Worker     CAacDecoderChannelInfo *pAacDecoderChannelInfo[2],
545*e5436536SAndroid Build Coastguard Worker     CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[2],
546*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *spectrumL, FIXP_DBL *spectrumR, SHORT *SFBleftScale,
547*e5436536SAndroid Build Coastguard Worker     SHORT *SFBrightScale, SHORT *specScaleL, SHORT *specScaleR,
548*e5436536SAndroid Build Coastguard Worker     const SHORT *pScaleFactorBandOffsets, const UCHAR *pWindowGroupLength,
549*e5436536SAndroid Build Coastguard Worker     const int windowGroups, const int max_sfb_ste_outside,
550*e5436536SAndroid Build Coastguard Worker     const int scaleFactorBandsTransmittedL,
551*e5436536SAndroid Build Coastguard Worker     const int scaleFactorBandsTransmittedR, FIXP_DBL *store_dmx_re_prev,
552*e5436536SAndroid Build Coastguard Worker     SHORT *store_dmx_re_prev_e, const int mainband_flag) {
553*e5436536SAndroid Build Coastguard Worker   int window, group, band;
554*e5436536SAndroid Build Coastguard Worker   UCHAR groupMask;
555*e5436536SAndroid Build Coastguard Worker   CJointStereoData *pJointStereoData =
556*e5436536SAndroid Build Coastguard Worker       &pAacDecoderChannelInfo[L]->pComData->jointStereoData;
557*e5436536SAndroid Build Coastguard Worker   CCplxPredictionData *cplxPredictionData =
558*e5436536SAndroid Build Coastguard Worker       pAacDecoderChannelInfo[L]->pComStaticData->cplxPredictionData;
559*e5436536SAndroid Build Coastguard Worker 
560*e5436536SAndroid Build Coastguard Worker   int max_sfb_ste =
561*e5436536SAndroid Build Coastguard Worker       fMax(scaleFactorBandsTransmittedL, scaleFactorBandsTransmittedR);
562*e5436536SAndroid Build Coastguard Worker   int min_sfb_ste =
563*e5436536SAndroid Build Coastguard Worker       fMin(scaleFactorBandsTransmittedL, scaleFactorBandsTransmittedR);
564*e5436536SAndroid Build Coastguard Worker   int scaleFactorBandsTransmitted = min_sfb_ste;
565*e5436536SAndroid Build Coastguard Worker 
566*e5436536SAndroid Build Coastguard Worker   if (pJointStereoData->cplx_pred_flag) {
567*e5436536SAndroid Build Coastguard Worker     int windowLen, groupwin, frameMaxScale;
568*e5436536SAndroid Build Coastguard Worker     CJointStereoPersistentData *pJointStereoPersistentData =
569*e5436536SAndroid Build Coastguard Worker         &pAacDecoderStaticChannelInfo[L]
570*e5436536SAndroid Build Coastguard Worker              ->pCpeStaticData->jointStereoPersistentData;
571*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *const staticSpectralCoeffsL =
572*e5436536SAndroid Build Coastguard Worker         pAacDecoderStaticChannelInfo[L]
573*e5436536SAndroid Build Coastguard Worker             ->pCpeStaticData->jointStereoPersistentData.spectralCoeffs[L];
574*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *const staticSpectralCoeffsR =
575*e5436536SAndroid Build Coastguard Worker         pAacDecoderStaticChannelInfo[L]
576*e5436536SAndroid Build Coastguard Worker             ->pCpeStaticData->jointStereoPersistentData.spectralCoeffs[R];
577*e5436536SAndroid Build Coastguard Worker     SHORT *const staticSpecScaleL =
578*e5436536SAndroid Build Coastguard Worker         pAacDecoderStaticChannelInfo[L]
579*e5436536SAndroid Build Coastguard Worker             ->pCpeStaticData->jointStereoPersistentData.specScale[L];
580*e5436536SAndroid Build Coastguard Worker     SHORT *const staticSpecScaleR =
581*e5436536SAndroid Build Coastguard Worker         pAacDecoderStaticChannelInfo[L]
582*e5436536SAndroid Build Coastguard Worker             ->pCpeStaticData->jointStereoPersistentData.specScale[R];
583*e5436536SAndroid Build Coastguard Worker 
584*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *dmx_re =
585*e5436536SAndroid Build Coastguard Worker         pAacDecoderStaticChannelInfo[L]
586*e5436536SAndroid Build Coastguard Worker             ->pCpeStaticData->jointStereoPersistentData.scratchBuffer;
587*e5436536SAndroid Build Coastguard Worker     FIXP_DBL *dmx_re_prev =
588*e5436536SAndroid Build Coastguard Worker         pAacDecoderStaticChannelInfo[L]
589*e5436536SAndroid Build Coastguard Worker             ->pCpeStaticData->jointStereoPersistentData.scratchBuffer +
590*e5436536SAndroid Build Coastguard Worker         1024;
591*e5436536SAndroid Build Coastguard Worker 
592*e5436536SAndroid Build Coastguard Worker     /* When MS is applied over the main band this value gets computed. Otherwise
593*e5436536SAndroid Build Coastguard Worker      * (for the tiles) it uses the assigned value */
594*e5436536SAndroid Build Coastguard Worker     SHORT dmx_re_prev_e = *store_dmx_re_prev_e;
595*e5436536SAndroid Build Coastguard Worker 
596*e5436536SAndroid Build Coastguard Worker     const FIXP_FILT *pCoeff;
597*e5436536SAndroid Build Coastguard Worker     const FIXP_FILT *pCoeffPrev;
598*e5436536SAndroid Build Coastguard Worker     int coeffPointerOffset;
599*e5436536SAndroid Build Coastguard Worker 
600*e5436536SAndroid Build Coastguard Worker     int previousShape = (int)pJointStereoPersistentData->winShapePrev;
601*e5436536SAndroid Build Coastguard Worker     int currentShape = (int)pAacDecoderChannelInfo[L]->icsInfo.WindowShape;
602*e5436536SAndroid Build Coastguard Worker 
603*e5436536SAndroid Build Coastguard Worker     /* complex stereo prediction */
604*e5436536SAndroid Build Coastguard Worker 
605*e5436536SAndroid Build Coastguard Worker     /* 0. preparations */
606*e5436536SAndroid Build Coastguard Worker 
607*e5436536SAndroid Build Coastguard Worker     /* 0.0. get scratch buffer for downmix MDST */
608*e5436536SAndroid Build Coastguard Worker     C_AALLOC_SCRATCH_START(dmx_im, FIXP_DBL, 1024);
609*e5436536SAndroid Build Coastguard Worker 
610*e5436536SAndroid Build Coastguard Worker     /* 0.1. window lengths */
611*e5436536SAndroid Build Coastguard Worker 
612*e5436536SAndroid Build Coastguard Worker     /* get length of short window for current configuration */
613*e5436536SAndroid Build Coastguard Worker     windowLen =
614*e5436536SAndroid Build Coastguard Worker         pAacDecoderChannelInfo[L]->granuleLength; /* framelength 768 => 96,
615*e5436536SAndroid Build Coastguard Worker                                                      framelength 1024 => 128 */
616*e5436536SAndroid Build Coastguard Worker 
617*e5436536SAndroid Build Coastguard Worker     /* if this is no short-block set length for long-block */
618*e5436536SAndroid Build Coastguard Worker     if (pAacDecoderChannelInfo[L]->icsInfo.WindowSequence != BLOCK_SHORT) {
619*e5436536SAndroid Build Coastguard Worker       windowLen *= 8;
620*e5436536SAndroid Build Coastguard Worker     }
621*e5436536SAndroid Build Coastguard Worker 
622*e5436536SAndroid Build Coastguard Worker     /* 0.2. set pointer to filter-coefficients for MDST excitation including
623*e5436536SAndroid Build Coastguard Worker      * previous frame portions */
624*e5436536SAndroid Build Coastguard Worker     /*      cp. ISO/IEC FDIS 23003-3:2011(E) table 125 */
625*e5436536SAndroid Build Coastguard Worker 
626*e5436536SAndroid Build Coastguard Worker     /* set pointer to default-position */
627*e5436536SAndroid Build Coastguard Worker     pCoeffPrev = mdst_filt_coef_prev[previousShape];
628*e5436536SAndroid Build Coastguard Worker 
629*e5436536SAndroid Build Coastguard Worker     if (cplxPredictionData->complex_coef == 1) {
630*e5436536SAndroid Build Coastguard Worker       switch (pAacDecoderChannelInfo[L]
631*e5436536SAndroid Build Coastguard Worker                   ->icsInfo.WindowSequence) { /* current window sequence */
632*e5436536SAndroid Build Coastguard Worker         case BLOCK_SHORT:
633*e5436536SAndroid Build Coastguard Worker         case BLOCK_LONG:
634*e5436536SAndroid Build Coastguard Worker           pCoeffPrev = mdst_filt_coef_prev[previousShape];
635*e5436536SAndroid Build Coastguard Worker           break;
636*e5436536SAndroid Build Coastguard Worker 
637*e5436536SAndroid Build Coastguard Worker         case BLOCK_START:
638*e5436536SAndroid Build Coastguard Worker           if ((pJointStereoPersistentData->winSeqPrev == BLOCK_SHORT) ||
639*e5436536SAndroid Build Coastguard Worker               (pJointStereoPersistentData->winSeqPrev == BLOCK_START)) {
640*e5436536SAndroid Build Coastguard Worker             /* a stop-start-sequence can only follow on an eight-short-sequence
641*e5436536SAndroid Build Coastguard Worker              * or a start-sequence */
642*e5436536SAndroid Build Coastguard Worker             pCoeffPrev = mdst_filt_coef_prev[2 + previousShape];
643*e5436536SAndroid Build Coastguard Worker           } else {
644*e5436536SAndroid Build Coastguard Worker             pCoeffPrev = mdst_filt_coef_prev[previousShape];
645*e5436536SAndroid Build Coastguard Worker           }
646*e5436536SAndroid Build Coastguard Worker           break;
647*e5436536SAndroid Build Coastguard Worker 
648*e5436536SAndroid Build Coastguard Worker         case BLOCK_STOP:
649*e5436536SAndroid Build Coastguard Worker           pCoeffPrev = mdst_filt_coef_prev[2 + previousShape];
650*e5436536SAndroid Build Coastguard Worker           break;
651*e5436536SAndroid Build Coastguard Worker 
652*e5436536SAndroid Build Coastguard Worker         default:
653*e5436536SAndroid Build Coastguard Worker           pCoeffPrev = mdst_filt_coef_prev[previousShape];
654*e5436536SAndroid Build Coastguard Worker           break;
655*e5436536SAndroid Build Coastguard Worker       }
656*e5436536SAndroid Build Coastguard Worker     }
657*e5436536SAndroid Build Coastguard Worker 
658*e5436536SAndroid Build Coastguard Worker     /* 0.3. set pointer to filter-coefficients for MDST excitation */
659*e5436536SAndroid Build Coastguard Worker 
660*e5436536SAndroid Build Coastguard Worker     /* define offset of pointer to filter-coefficients for MDST exitation
661*e5436536SAndroid Build Coastguard Worker      * employing only the current frame */
662*e5436536SAndroid Build Coastguard Worker     if ((previousShape == SHAPE_SINE) && (currentShape == SHAPE_SINE)) {
663*e5436536SAndroid Build Coastguard Worker       coeffPointerOffset = 0;
664*e5436536SAndroid Build Coastguard Worker     } else if ((previousShape == SHAPE_SINE) && (currentShape == SHAPE_KBD)) {
665*e5436536SAndroid Build Coastguard Worker       coeffPointerOffset = 2;
666*e5436536SAndroid Build Coastguard Worker     } else if ((previousShape == SHAPE_KBD) && (currentShape == SHAPE_KBD)) {
667*e5436536SAndroid Build Coastguard Worker       coeffPointerOffset = 1;
668*e5436536SAndroid Build Coastguard Worker     } else /* if ( (previousShape == SHAPE_KBD) && (currentShape == SHAPE_SINE)
669*e5436536SAndroid Build Coastguard Worker               ) */
670*e5436536SAndroid Build Coastguard Worker     {
671*e5436536SAndroid Build Coastguard Worker       coeffPointerOffset = 3;
672*e5436536SAndroid Build Coastguard Worker     }
673*e5436536SAndroid Build Coastguard Worker 
674*e5436536SAndroid Build Coastguard Worker     /* set pointer to filter-coefficient table cp. ISO/IEC FDIS 23003-3:2011(E)
675*e5436536SAndroid Build Coastguard Worker      * table 124 */
676*e5436536SAndroid Build Coastguard Worker     switch (pAacDecoderChannelInfo[L]
677*e5436536SAndroid Build Coastguard Worker                 ->icsInfo.WindowSequence) { /* current window sequence */
678*e5436536SAndroid Build Coastguard Worker       case BLOCK_SHORT:
679*e5436536SAndroid Build Coastguard Worker       case BLOCK_LONG:
680*e5436536SAndroid Build Coastguard Worker         pCoeff = mdst_filt_coef_curr[coeffPointerOffset];
681*e5436536SAndroid Build Coastguard Worker         break;
682*e5436536SAndroid Build Coastguard Worker 
683*e5436536SAndroid Build Coastguard Worker       case BLOCK_START:
684*e5436536SAndroid Build Coastguard Worker         if ((pJointStereoPersistentData->winSeqPrev == BLOCK_SHORT) ||
685*e5436536SAndroid Build Coastguard Worker             (pJointStereoPersistentData->winSeqPrev == BLOCK_START)) {
686*e5436536SAndroid Build Coastguard Worker           /* a stop-start-sequence can only follow on an eight-short-sequence or
687*e5436536SAndroid Build Coastguard Worker            * a start-sequence */
688*e5436536SAndroid Build Coastguard Worker           pCoeff = mdst_filt_coef_curr[12 + coeffPointerOffset];
689*e5436536SAndroid Build Coastguard Worker         } else {
690*e5436536SAndroid Build Coastguard Worker           pCoeff = mdst_filt_coef_curr[4 + coeffPointerOffset];
691*e5436536SAndroid Build Coastguard Worker         }
692*e5436536SAndroid Build Coastguard Worker         break;
693*e5436536SAndroid Build Coastguard Worker 
694*e5436536SAndroid Build Coastguard Worker       case BLOCK_STOP:
695*e5436536SAndroid Build Coastguard Worker         pCoeff = mdst_filt_coef_curr[8 + coeffPointerOffset];
696*e5436536SAndroid Build Coastguard Worker         break;
697*e5436536SAndroid Build Coastguard Worker 
698*e5436536SAndroid Build Coastguard Worker       default:
699*e5436536SAndroid Build Coastguard Worker         pCoeff = mdst_filt_coef_curr[coeffPointerOffset];
700*e5436536SAndroid Build Coastguard Worker     }
701*e5436536SAndroid Build Coastguard Worker 
702*e5436536SAndroid Build Coastguard Worker     /* 0.4. find maximum common (l/r) band-scaling-factor for whole sequence
703*e5436536SAndroid Build Coastguard Worker      * (all windows) */
704*e5436536SAndroid Build Coastguard Worker     frameMaxScale = 0;
705*e5436536SAndroid Build Coastguard Worker     for (window = 0, group = 0; group < windowGroups; group++) {
706*e5436536SAndroid Build Coastguard Worker       for (groupwin = 0; groupwin < pWindowGroupLength[group];
707*e5436536SAndroid Build Coastguard Worker            groupwin++, window++) {
708*e5436536SAndroid Build Coastguard Worker         SHORT *leftScale = &SFBleftScale[window * 16];
709*e5436536SAndroid Build Coastguard Worker         SHORT *rightScale = &SFBrightScale[window * 16];
710*e5436536SAndroid Build Coastguard Worker         int windowMaxScale = 0;
711*e5436536SAndroid Build Coastguard Worker 
712*e5436536SAndroid Build Coastguard Worker         /* find maximum scaling factor of all bands in this window */
713*e5436536SAndroid Build Coastguard Worker         for (band = 0; band < min_sfb_ste; band++) {
714*e5436536SAndroid Build Coastguard Worker           int lScale = leftScale[band];
715*e5436536SAndroid Build Coastguard Worker           int rScale = rightScale[band];
716*e5436536SAndroid Build Coastguard Worker           int commonScale = ((lScale > rScale) ? lScale : rScale);
717*e5436536SAndroid Build Coastguard Worker           windowMaxScale =
718*e5436536SAndroid Build Coastguard Worker               (windowMaxScale < commonScale) ? commonScale : windowMaxScale;
719*e5436536SAndroid Build Coastguard Worker         }
720*e5436536SAndroid Build Coastguard Worker         if (scaleFactorBandsTransmittedL >
721*e5436536SAndroid Build Coastguard Worker             min_sfb_ste) { /* i.e. scaleFactorBandsTransmittedL == max_sfb_ste
722*e5436536SAndroid Build Coastguard Worker                             */
723*e5436536SAndroid Build Coastguard Worker           for (; band < max_sfb_ste; band++) {
724*e5436536SAndroid Build Coastguard Worker             int lScale = leftScale[band];
725*e5436536SAndroid Build Coastguard Worker             windowMaxScale =
726*e5436536SAndroid Build Coastguard Worker                 (windowMaxScale < lScale) ? lScale : windowMaxScale;
727*e5436536SAndroid Build Coastguard Worker           }
728*e5436536SAndroid Build Coastguard Worker         } else {
729*e5436536SAndroid Build Coastguard Worker           if (scaleFactorBandsTransmittedR >
730*e5436536SAndroid Build Coastguard Worker               min_sfb_ste) { /* i.e. scaleFactorBandsTransmittedR == max_sfb_ste
731*e5436536SAndroid Build Coastguard Worker                               */
732*e5436536SAndroid Build Coastguard Worker             for (; band < max_sfb_ste; band++) {
733*e5436536SAndroid Build Coastguard Worker               int rScale = rightScale[band];
734*e5436536SAndroid Build Coastguard Worker               windowMaxScale =
735*e5436536SAndroid Build Coastguard Worker                   (windowMaxScale < rScale) ? rScale : windowMaxScale;
736*e5436536SAndroid Build Coastguard Worker             }
737*e5436536SAndroid Build Coastguard Worker           }
738*e5436536SAndroid Build Coastguard Worker         }
739*e5436536SAndroid Build Coastguard Worker 
740*e5436536SAndroid Build Coastguard Worker         /* find maximum common SF of all windows */
741*e5436536SAndroid Build Coastguard Worker         frameMaxScale =
742*e5436536SAndroid Build Coastguard Worker             (frameMaxScale < windowMaxScale) ? windowMaxScale : frameMaxScale;
743*e5436536SAndroid Build Coastguard Worker       }
744*e5436536SAndroid Build Coastguard Worker     }
745*e5436536SAndroid Build Coastguard Worker 
746*e5436536SAndroid Build Coastguard Worker     /* add some headroom for overflow protection during filter and add operation
747*e5436536SAndroid Build Coastguard Worker      */
748*e5436536SAndroid Build Coastguard Worker     frameMaxScale += 2;
749*e5436536SAndroid Build Coastguard Worker 
750*e5436536SAndroid Build Coastguard Worker     /* process on window-basis (i.e. iterate over all groups and corresponding
751*e5436536SAndroid Build Coastguard Worker      * windows) */
752*e5436536SAndroid Build Coastguard Worker     for (window = 0, group = 0; group < windowGroups; group++) {
753*e5436536SAndroid Build Coastguard Worker       groupMask = 1 << group;
754*e5436536SAndroid Build Coastguard Worker 
755*e5436536SAndroid Build Coastguard Worker       for (groupwin = 0; groupwin < pWindowGroupLength[group];
756*e5436536SAndroid Build Coastguard Worker            groupwin++, window++) {
757*e5436536SAndroid Build Coastguard Worker         /* initialize the MDST with zeros */
758*e5436536SAndroid Build Coastguard Worker         FDKmemclear(&dmx_im[windowLen * window], windowLen * sizeof(FIXP_DBL));
759*e5436536SAndroid Build Coastguard Worker 
760*e5436536SAndroid Build Coastguard Worker         /* 1. calculate the previous downmix MDCT. We do this once just for the
761*e5436536SAndroid Build Coastguard Worker          * Main band. */
762*e5436536SAndroid Build Coastguard Worker         if (cplxPredictionData->complex_coef == 1) {
763*e5436536SAndroid Build Coastguard Worker           if ((cplxPredictionData->use_prev_frame == 1) && (mainband_flag)) {
764*e5436536SAndroid Build Coastguard Worker             /* if this is a long-block or the first window of a short-block
765*e5436536SAndroid Build Coastguard Worker                calculate the downmix MDCT of the previous frame.
766*e5436536SAndroid Build Coastguard Worker                use_prev_frame is assumed not to change during a frame!
767*e5436536SAndroid Build Coastguard Worker             */
768*e5436536SAndroid Build Coastguard Worker 
769*e5436536SAndroid Build Coastguard Worker             /* first determine shiftfactors to scale left and right channel */
770*e5436536SAndroid Build Coastguard Worker             if ((pAacDecoderChannelInfo[L]->icsInfo.WindowSequence !=
771*e5436536SAndroid Build Coastguard Worker                  BLOCK_SHORT) ||
772*e5436536SAndroid Build Coastguard Worker                 (window == 0)) {
773*e5436536SAndroid Build Coastguard Worker               int index_offset = 0;
774*e5436536SAndroid Build Coastguard Worker               int srLeftChan = 0;
775*e5436536SAndroid Build Coastguard Worker               int srRightChan = 0;
776*e5436536SAndroid Build Coastguard Worker               if (pAacDecoderChannelInfo[L]->icsInfo.WindowSequence ==
777*e5436536SAndroid Build Coastguard Worker                   BLOCK_SHORT) {
778*e5436536SAndroid Build Coastguard Worker                 /* use the last window of the previous frame for MDCT
779*e5436536SAndroid Build Coastguard Worker                  * calculation if this is a short-block. */
780*e5436536SAndroid Build Coastguard Worker                 index_offset = windowLen * 7;
781*e5436536SAndroid Build Coastguard Worker                 if (staticSpecScaleL[7] > staticSpecScaleR[7]) {
782*e5436536SAndroid Build Coastguard Worker                   srRightChan = staticSpecScaleL[7] - staticSpecScaleR[7];
783*e5436536SAndroid Build Coastguard Worker                   dmx_re_prev_e = staticSpecScaleL[7];
784*e5436536SAndroid Build Coastguard Worker                 } else {
785*e5436536SAndroid Build Coastguard Worker                   srLeftChan = staticSpecScaleR[7] - staticSpecScaleL[7];
786*e5436536SAndroid Build Coastguard Worker                   dmx_re_prev_e = staticSpecScaleR[7];
787*e5436536SAndroid Build Coastguard Worker                 }
788*e5436536SAndroid Build Coastguard Worker               } else {
789*e5436536SAndroid Build Coastguard Worker                 if (staticSpecScaleL[0] > staticSpecScaleR[0]) {
790*e5436536SAndroid Build Coastguard Worker                   srRightChan = staticSpecScaleL[0] - staticSpecScaleR[0];
791*e5436536SAndroid Build Coastguard Worker                   dmx_re_prev_e = staticSpecScaleL[0];
792*e5436536SAndroid Build Coastguard Worker                 } else {
793*e5436536SAndroid Build Coastguard Worker                   srLeftChan = staticSpecScaleR[0] - staticSpecScaleL[0];
794*e5436536SAndroid Build Coastguard Worker                   dmx_re_prev_e = staticSpecScaleR[0];
795*e5436536SAndroid Build Coastguard Worker                 }
796*e5436536SAndroid Build Coastguard Worker               }
797*e5436536SAndroid Build Coastguard Worker 
798*e5436536SAndroid Build Coastguard Worker               /* now scale channels and determine downmix MDCT of previous frame
799*e5436536SAndroid Build Coastguard Worker                */
800*e5436536SAndroid Build Coastguard Worker               if (pAacDecoderStaticChannelInfo[L]
801*e5436536SAndroid Build Coastguard Worker                       ->pCpeStaticData->jointStereoPersistentData
802*e5436536SAndroid Build Coastguard Worker                       .clearSpectralCoeffs == 1) {
803*e5436536SAndroid Build Coastguard Worker                 FDKmemclear(dmx_re_prev, windowLen * sizeof(FIXP_DBL));
804*e5436536SAndroid Build Coastguard Worker                 dmx_re_prev_e = 0;
805*e5436536SAndroid Build Coastguard Worker               } else {
806*e5436536SAndroid Build Coastguard Worker                 if (cplxPredictionData->pred_dir == 0) {
807*e5436536SAndroid Build Coastguard Worker                   for (int i = 0; i < windowLen; i++) {
808*e5436536SAndroid Build Coastguard Worker                     dmx_re_prev[i] =
809*e5436536SAndroid Build Coastguard Worker                         ((staticSpectralCoeffsL[index_offset + i] >>
810*e5436536SAndroid Build Coastguard Worker                           fMin(DFRACT_BITS - 1, srLeftChan + 1)) +
811*e5436536SAndroid Build Coastguard Worker                          (staticSpectralCoeffsR[index_offset + i] >>
812*e5436536SAndroid Build Coastguard Worker                           fMin(DFRACT_BITS - 1, srRightChan + 1)));
813*e5436536SAndroid Build Coastguard Worker                   }
814*e5436536SAndroid Build Coastguard Worker                 } else {
815*e5436536SAndroid Build Coastguard Worker                   for (int i = 0; i < windowLen; i++) {
816*e5436536SAndroid Build Coastguard Worker                     dmx_re_prev[i] =
817*e5436536SAndroid Build Coastguard Worker                         ((staticSpectralCoeffsL[index_offset + i] >>
818*e5436536SAndroid Build Coastguard Worker                           fMin(DFRACT_BITS - 1, srLeftChan + 1)) -
819*e5436536SAndroid Build Coastguard Worker                          (staticSpectralCoeffsR[index_offset + i] >>
820*e5436536SAndroid Build Coastguard Worker                           fMin(DFRACT_BITS - 1, srRightChan + 1)));
821*e5436536SAndroid Build Coastguard Worker                   }
822*e5436536SAndroid Build Coastguard Worker                 }
823*e5436536SAndroid Build Coastguard Worker               }
824*e5436536SAndroid Build Coastguard Worker 
825*e5436536SAndroid Build Coastguard Worker               /* In case that we use INF we have to preserve the state of the
826*e5436536SAndroid Build Coastguard Worker               "dmx_re_prev" (original or computed). This is necessary because we
827*e5436536SAndroid Build Coastguard Worker               have to apply MS over the separate IGF tiles. */
828*e5436536SAndroid Build Coastguard Worker               FDKmemcpy(store_dmx_re_prev, &dmx_re_prev[0],
829*e5436536SAndroid Build Coastguard Worker                         windowLen * sizeof(FIXP_DBL));
830*e5436536SAndroid Build Coastguard Worker 
831*e5436536SAndroid Build Coastguard Worker               /* Particular exponent of the computed/original "dmx_re_prev" must
832*e5436536SAndroid Build Coastguard Worker                * be kept for the tile MS calculations if necessary.*/
833*e5436536SAndroid Build Coastguard Worker               *store_dmx_re_prev_e = dmx_re_prev_e;
834*e5436536SAndroid Build Coastguard Worker 
835*e5436536SAndroid Build Coastguard Worker             } /* if ( (pAacDecoderChannelInfo[L]->icsInfo.WindowSequence !=
836*e5436536SAndroid Build Coastguard Worker                  BLOCK_SHORT) || (window == 0) ) */
837*e5436536SAndroid Build Coastguard Worker 
838*e5436536SAndroid Build Coastguard Worker           } /* if ( pJointStereoData->use_prev_frame == 1 ) */
839*e5436536SAndroid Build Coastguard Worker 
840*e5436536SAndroid Build Coastguard Worker         } /* if ( pJointStereoData->complex_coef == 1 ) */
841*e5436536SAndroid Build Coastguard Worker 
842*e5436536SAndroid Build Coastguard Worker         /* 2. calculate downmix MDCT of current frame */
843*e5436536SAndroid Build Coastguard Worker 
844*e5436536SAndroid Build Coastguard Worker         /* set pointer to scale-factor-bands of current window */
845*e5436536SAndroid Build Coastguard Worker         SHORT *leftScale = &SFBleftScale[window * 16];
846*e5436536SAndroid Build Coastguard Worker         SHORT *rightScale = &SFBrightScale[window * 16];
847*e5436536SAndroid Build Coastguard Worker 
848*e5436536SAndroid Build Coastguard Worker         specScaleL[window] = specScaleR[window] = frameMaxScale;
849*e5436536SAndroid Build Coastguard Worker 
850*e5436536SAndroid Build Coastguard Worker         /* adapt scaling-factors to previous frame */
851*e5436536SAndroid Build Coastguard Worker         if (cplxPredictionData->use_prev_frame == 1) {
852*e5436536SAndroid Build Coastguard Worker           if (window == 0) {
853*e5436536SAndroid Build Coastguard Worker             if (dmx_re_prev_e < frameMaxScale) {
854*e5436536SAndroid Build Coastguard Worker               if (mainband_flag == 0) {
855*e5436536SAndroid Build Coastguard Worker                 scaleValues(
856*e5436536SAndroid Build Coastguard Worker                     dmx_re_prev, store_dmx_re_prev, windowLen,
857*e5436536SAndroid Build Coastguard Worker                     -fMin(DFRACT_BITS - 1, (frameMaxScale - dmx_re_prev_e)));
858*e5436536SAndroid Build Coastguard Worker               } else {
859*e5436536SAndroid Build Coastguard Worker                 scaleValues(
860*e5436536SAndroid Build Coastguard Worker                     dmx_re_prev, windowLen,
861*e5436536SAndroid Build Coastguard Worker                     -fMin(DFRACT_BITS - 1, (frameMaxScale - dmx_re_prev_e)));
862*e5436536SAndroid Build Coastguard Worker               }
863*e5436536SAndroid Build Coastguard Worker             } else {
864*e5436536SAndroid Build Coastguard Worker               if (mainband_flag == 0) {
865*e5436536SAndroid Build Coastguard Worker                 FDKmemcpy(dmx_re_prev, store_dmx_re_prev,
866*e5436536SAndroid Build Coastguard Worker                           windowLen * sizeof(FIXP_DBL));
867*e5436536SAndroid Build Coastguard Worker               }
868*e5436536SAndroid Build Coastguard Worker               specScaleL[0] = dmx_re_prev_e;
869*e5436536SAndroid Build Coastguard Worker               specScaleR[0] = dmx_re_prev_e;
870*e5436536SAndroid Build Coastguard Worker             }
871*e5436536SAndroid Build Coastguard Worker           } else { /* window != 0 */
872*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(pAacDecoderChannelInfo[L]->icsInfo.WindowSequence ==
873*e5436536SAndroid Build Coastguard Worker                        BLOCK_SHORT);
874*e5436536SAndroid Build Coastguard Worker             if (specScaleL[window - 1] < frameMaxScale) {
875*e5436536SAndroid Build Coastguard Worker               scaleValues(&dmx_re[windowLen * (window - 1)], windowLen,
876*e5436536SAndroid Build Coastguard Worker                           -fMin(DFRACT_BITS - 1,
877*e5436536SAndroid Build Coastguard Worker                                 (frameMaxScale - specScaleL[window - 1])));
878*e5436536SAndroid Build Coastguard Worker             } else {
879*e5436536SAndroid Build Coastguard Worker               specScaleL[window] = specScaleL[window - 1];
880*e5436536SAndroid Build Coastguard Worker               specScaleR[window] = specScaleR[window - 1];
881*e5436536SAndroid Build Coastguard Worker             }
882*e5436536SAndroid Build Coastguard Worker           }
883*e5436536SAndroid Build Coastguard Worker         } /* if ( pJointStereoData->use_prev_frame == 1 ) */
884*e5436536SAndroid Build Coastguard Worker 
885*e5436536SAndroid Build Coastguard Worker         /* scaling factors of both channels ought to be equal now */
886*e5436536SAndroid Build Coastguard Worker         FDK_ASSERT(specScaleL[window] == specScaleR[window]);
887*e5436536SAndroid Build Coastguard Worker 
888*e5436536SAndroid Build Coastguard Worker         /* rescale signal and calculate downmix MDCT */
889*e5436536SAndroid Build Coastguard Worker         for (band = 0; band < max_sfb_ste; band++) {
890*e5436536SAndroid Build Coastguard Worker           /* first adapt scaling of current band to scaling of current window =>
891*e5436536SAndroid Build Coastguard Worker            * shift signal right */
892*e5436536SAndroid Build Coastguard Worker           int lScale = leftScale[band];
893*e5436536SAndroid Build Coastguard Worker           int rScale = rightScale[band];
894*e5436536SAndroid Build Coastguard Worker 
895*e5436536SAndroid Build Coastguard Worker           lScale = fMin(DFRACT_BITS - 1, specScaleL[window] - lScale);
896*e5436536SAndroid Build Coastguard Worker           rScale = fMin(DFRACT_BITS - 1,
897*e5436536SAndroid Build Coastguard Worker                         specScaleL[window] - rScale); /* L or R doesn't
898*e5436536SAndroid Build Coastguard Worker                                                          matter,
899*e5436536SAndroid Build Coastguard Worker                                                          specScales are
900*e5436536SAndroid Build Coastguard Worker                                                          equal at this
901*e5436536SAndroid Build Coastguard Worker                                                          point */
902*e5436536SAndroid Build Coastguard Worker 
903*e5436536SAndroid Build Coastguard Worker           /* Write back to sfb scale to cover the case when max_sfb_ste <
904*e5436536SAndroid Build Coastguard Worker            * max_sfb */
905*e5436536SAndroid Build Coastguard Worker           leftScale[band] = rightScale[band] = specScaleL[window];
906*e5436536SAndroid Build Coastguard Worker 
907*e5436536SAndroid Build Coastguard Worker           for (int i = pScaleFactorBandOffsets[band];
908*e5436536SAndroid Build Coastguard Worker                i < pScaleFactorBandOffsets[band + 1]; i++) {
909*e5436536SAndroid Build Coastguard Worker             spectrumL[windowLen * window + i] >>= lScale;
910*e5436536SAndroid Build Coastguard Worker             spectrumR[windowLen * window + i] >>= rScale;
911*e5436536SAndroid Build Coastguard Worker           }
912*e5436536SAndroid Build Coastguard Worker 
913*e5436536SAndroid Build Coastguard Worker           /* now calculate downmix MDCT */
914*e5436536SAndroid Build Coastguard Worker           if (pJointStereoData->MsUsed[band] & groupMask) {
915*e5436536SAndroid Build Coastguard Worker             for (int i = pScaleFactorBandOffsets[band];
916*e5436536SAndroid Build Coastguard Worker                  i < pScaleFactorBandOffsets[band + 1]; i++) {
917*e5436536SAndroid Build Coastguard Worker               dmx_re[windowLen * window + i] =
918*e5436536SAndroid Build Coastguard Worker                   spectrumL[windowLen * window + i];
919*e5436536SAndroid Build Coastguard Worker             }
920*e5436536SAndroid Build Coastguard Worker           } else {
921*e5436536SAndroid Build Coastguard Worker             if (cplxPredictionData->pred_dir == 0) {
922*e5436536SAndroid Build Coastguard Worker               for (int i = pScaleFactorBandOffsets[band];
923*e5436536SAndroid Build Coastguard Worker                    i < pScaleFactorBandOffsets[band + 1]; i++) {
924*e5436536SAndroid Build Coastguard Worker                 dmx_re[windowLen * window + i] =
925*e5436536SAndroid Build Coastguard Worker                     (spectrumL[windowLen * window + i] +
926*e5436536SAndroid Build Coastguard Worker                      spectrumR[windowLen * window + i]) >>
927*e5436536SAndroid Build Coastguard Worker                     1;
928*e5436536SAndroid Build Coastguard Worker               }
929*e5436536SAndroid Build Coastguard Worker             } else {
930*e5436536SAndroid Build Coastguard Worker               for (int i = pScaleFactorBandOffsets[band];
931*e5436536SAndroid Build Coastguard Worker                    i < pScaleFactorBandOffsets[band + 1]; i++) {
932*e5436536SAndroid Build Coastguard Worker                 dmx_re[windowLen * window + i] =
933*e5436536SAndroid Build Coastguard Worker                     (spectrumL[windowLen * window + i] -
934*e5436536SAndroid Build Coastguard Worker                      spectrumR[windowLen * window + i]) >>
935*e5436536SAndroid Build Coastguard Worker                     1;
936*e5436536SAndroid Build Coastguard Worker               }
937*e5436536SAndroid Build Coastguard Worker             }
938*e5436536SAndroid Build Coastguard Worker           }
939*e5436536SAndroid Build Coastguard Worker 
940*e5436536SAndroid Build Coastguard Worker         } /* for ( band=0; band<max_sfb_ste; band++ ) */
941*e5436536SAndroid Build Coastguard Worker         /* Clean until the end */
942*e5436536SAndroid Build Coastguard Worker         for (int i = pScaleFactorBandOffsets[max_sfb_ste_outside];
943*e5436536SAndroid Build Coastguard Worker              i < windowLen; i++) {
944*e5436536SAndroid Build Coastguard Worker           dmx_re[windowLen * window + i] = (FIXP_DBL)0;
945*e5436536SAndroid Build Coastguard Worker         }
946*e5436536SAndroid Build Coastguard Worker 
947*e5436536SAndroid Build Coastguard Worker         /* 3. calculate MDST-portion corresponding to the current frame. */
948*e5436536SAndroid Build Coastguard Worker         if (cplxPredictionData->complex_coef == 1) {
949*e5436536SAndroid Build Coastguard Worker           {
950*e5436536SAndroid Build Coastguard Worker             /* 3.1 move pointer in filter-coefficient table in case of short
951*e5436536SAndroid Build Coastguard Worker              * window sequence */
952*e5436536SAndroid Build Coastguard Worker             /*     (other coefficients are utilized for the last 7 short
953*e5436536SAndroid Build Coastguard Worker              * windows)            */
954*e5436536SAndroid Build Coastguard Worker             if ((pAacDecoderChannelInfo[L]->icsInfo.WindowSequence ==
955*e5436536SAndroid Build Coastguard Worker                  BLOCK_SHORT) &&
956*e5436536SAndroid Build Coastguard Worker                 (window != 0)) {
957*e5436536SAndroid Build Coastguard Worker               pCoeff = mdst_filt_coef_curr[currentShape];
958*e5436536SAndroid Build Coastguard Worker               pCoeffPrev = mdst_filt_coef_prev[currentShape];
959*e5436536SAndroid Build Coastguard Worker             }
960*e5436536SAndroid Build Coastguard Worker 
961*e5436536SAndroid Build Coastguard Worker             /* The length of the filter processing must be extended because of
962*e5436536SAndroid Build Coastguard Worker              * filter boundary problems */
963*e5436536SAndroid Build Coastguard Worker             int extended_band = fMin(
964*e5436536SAndroid Build Coastguard Worker                 pScaleFactorBandOffsets[max_sfb_ste_outside] + 7, windowLen);
965*e5436536SAndroid Build Coastguard Worker 
966*e5436536SAndroid Build Coastguard Worker             /* 3.2. estimate downmix MDST from current frame downmix MDCT */
967*e5436536SAndroid Build Coastguard Worker             if ((pAacDecoderChannelInfo[L]->icsInfo.WindowSequence ==
968*e5436536SAndroid Build Coastguard Worker                  BLOCK_SHORT) &&
969*e5436536SAndroid Build Coastguard Worker                 (window != 0)) {
970*e5436536SAndroid Build Coastguard Worker               CJointStereo_filterAndAdd(&dmx_re[windowLen * window],
971*e5436536SAndroid Build Coastguard Worker                                         extended_band, windowLen, pCoeff,
972*e5436536SAndroid Build Coastguard Worker                                         &dmx_im[windowLen * window], 1);
973*e5436536SAndroid Build Coastguard Worker 
974*e5436536SAndroid Build Coastguard Worker               CJointStereo_filterAndAdd(&dmx_re[windowLen * (window - 1)],
975*e5436536SAndroid Build Coastguard Worker                                         extended_band, windowLen, pCoeffPrev,
976*e5436536SAndroid Build Coastguard Worker                                         &dmx_im[windowLen * window], 0);
977*e5436536SAndroid Build Coastguard Worker             } else {
978*e5436536SAndroid Build Coastguard Worker               CJointStereo_filterAndAdd(dmx_re, extended_band, windowLen,
979*e5436536SAndroid Build Coastguard Worker                                         pCoeff, dmx_im, 1);
980*e5436536SAndroid Build Coastguard Worker 
981*e5436536SAndroid Build Coastguard Worker               if (cplxPredictionData->use_prev_frame == 1) {
982*e5436536SAndroid Build Coastguard Worker                 CJointStereo_filterAndAdd(dmx_re_prev, extended_band, windowLen,
983*e5436536SAndroid Build Coastguard Worker                                           pCoeffPrev,
984*e5436536SAndroid Build Coastguard Worker                                           &dmx_im[windowLen * window], 0);
985*e5436536SAndroid Build Coastguard Worker               }
986*e5436536SAndroid Build Coastguard Worker             }
987*e5436536SAndroid Build Coastguard Worker 
988*e5436536SAndroid Build Coastguard Worker           } /* if(pAacDecoderChannelInfo[L]->transform_splitting_active) */
989*e5436536SAndroid Build Coastguard Worker         }   /* if ( pJointStereoData->complex_coef == 1 ) */
990*e5436536SAndroid Build Coastguard Worker 
991*e5436536SAndroid Build Coastguard Worker         /* 4. upmix process */
992*e5436536SAndroid Build Coastguard Worker         LONG pred_dir = cplxPredictionData->pred_dir ? -1 : 1;
993*e5436536SAndroid Build Coastguard Worker         /* 0.1 in Q-3.34 */
994*e5436536SAndroid Build Coastguard Worker         const FIXP_DBL pointOne = 0x66666666; /* 0.8 */
995*e5436536SAndroid Build Coastguard Worker         /* Shift value for the downmix */
996*e5436536SAndroid Build Coastguard Worker         const INT shift_dmx = SF_FNA_COEFFS + 1;
997*e5436536SAndroid Build Coastguard Worker 
998*e5436536SAndroid Build Coastguard Worker         for (band = 0; band < max_sfb_ste_outside; band++) {
999*e5436536SAndroid Build Coastguard Worker           if (pJointStereoData->MsUsed[band] & groupMask) {
1000*e5436536SAndroid Build Coastguard Worker             FIXP_SGL tempRe =
1001*e5436536SAndroid Build Coastguard Worker                 (FIXP_SGL)cplxPredictionData->alpha_q_re[group][band];
1002*e5436536SAndroid Build Coastguard Worker             FIXP_SGL tempIm =
1003*e5436536SAndroid Build Coastguard Worker                 (FIXP_SGL)cplxPredictionData->alpha_q_im[group][band];
1004*e5436536SAndroid Build Coastguard Worker 
1005*e5436536SAndroid Build Coastguard Worker             /* Find the minimum common headroom for alpha_re and alpha_im */
1006*e5436536SAndroid Build Coastguard Worker             int alpha_re_headroom = CountLeadingBits((INT)tempRe) - 16;
1007*e5436536SAndroid Build Coastguard Worker             if (tempRe == (FIXP_SGL)0) alpha_re_headroom = 15;
1008*e5436536SAndroid Build Coastguard Worker             int alpha_im_headroom = CountLeadingBits((INT)tempIm) - 16;
1009*e5436536SAndroid Build Coastguard Worker             if (tempIm == (FIXP_SGL)0) alpha_im_headroom = 15;
1010*e5436536SAndroid Build Coastguard Worker             int val = fMin(alpha_re_headroom, alpha_im_headroom);
1011*e5436536SAndroid Build Coastguard Worker 
1012*e5436536SAndroid Build Coastguard Worker             /* Multiply alpha by 0.1 with maximum precision */
1013*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(val >= 0);
1014*e5436536SAndroid Build Coastguard Worker             FIXP_DBL alpha_re_tmp = fMult((FIXP_SGL)(tempRe << val), pointOne);
1015*e5436536SAndroid Build Coastguard Worker             FIXP_DBL alpha_im_tmp = fMult((FIXP_SGL)(tempIm << val), pointOne);
1016*e5436536SAndroid Build Coastguard Worker 
1017*e5436536SAndroid Build Coastguard Worker             /* Calculate alpha exponent */
1018*e5436536SAndroid Build Coastguard Worker             /* (Q-3.34 * Q15.0) shifted left by "val" */
1019*e5436536SAndroid Build Coastguard Worker             int alpha_re_exp = -3 + 15 - val;
1020*e5436536SAndroid Build Coastguard Worker 
1021*e5436536SAndroid Build Coastguard Worker             int help3_shift = alpha_re_exp + 1;
1022*e5436536SAndroid Build Coastguard Worker 
1023*e5436536SAndroid Build Coastguard Worker             FIXP_DBL *p2CoeffL = &(
1024*e5436536SAndroid Build Coastguard Worker                 spectrumL[windowLen * window + pScaleFactorBandOffsets[band]]);
1025*e5436536SAndroid Build Coastguard Worker             FIXP_DBL *p2CoeffR = &(
1026*e5436536SAndroid Build Coastguard Worker                 spectrumR[windowLen * window + pScaleFactorBandOffsets[band]]);
1027*e5436536SAndroid Build Coastguard Worker             FIXP_DBL *p2dmxIm =
1028*e5436536SAndroid Build Coastguard Worker                 &(dmx_im[windowLen * window + pScaleFactorBandOffsets[band]]);
1029*e5436536SAndroid Build Coastguard Worker             FIXP_DBL *p2dmxRe =
1030*e5436536SAndroid Build Coastguard Worker                 &(dmx_re[windowLen * window + pScaleFactorBandOffsets[band]]);
1031*e5436536SAndroid Build Coastguard Worker 
1032*e5436536SAndroid Build Coastguard Worker             for (int i = pScaleFactorBandOffsets[band];
1033*e5436536SAndroid Build Coastguard Worker                  i < pScaleFactorBandOffsets[band + 1]; i++) {
1034*e5436536SAndroid Build Coastguard Worker               /* Calculating helper term:
1035*e5436536SAndroid Build Coastguard Worker                     side = specR[i] - alpha_re[i] * dmx_re[i] - alpha_im[i] *
1036*e5436536SAndroid Build Coastguard Worker                 dmx_im[i];
1037*e5436536SAndroid Build Coastguard Worker 
1038*e5436536SAndroid Build Coastguard Worker                 Here "dmx_re" may be the same as "specL" or alternatively keep
1039*e5436536SAndroid Build Coastguard Worker                 the downmix. "dmx_re" and "specL" are two different pointers
1040*e5436536SAndroid Build Coastguard Worker                 pointing to separate arrays, which may or may not contain the
1041*e5436536SAndroid Build Coastguard Worker                 same data (with different scaling).
1042*e5436536SAndroid Build Coastguard Worker 
1043*e5436536SAndroid Build Coastguard Worker                 specL[i] =   + (specL[i] + side);
1044*e5436536SAndroid Build Coastguard Worker                 specR[i] = -/+ (specL[i] - side);
1045*e5436536SAndroid Build Coastguard Worker               */
1046*e5436536SAndroid Build Coastguard Worker               FIXP_DBL side, left, right;
1047*e5436536SAndroid Build Coastguard Worker 
1048*e5436536SAndroid Build Coastguard Worker               side = fMultAddDiv2(fMultDiv2(alpha_re_tmp, *p2dmxRe++),
1049*e5436536SAndroid Build Coastguard Worker                                   alpha_im_tmp, (*p2dmxIm++) << shift_dmx);
1050*e5436536SAndroid Build Coastguard Worker               side = ((*p2CoeffR) >> 2) -
1051*e5436536SAndroid Build Coastguard Worker                      (FIXP_DBL)SATURATE_SHIFT(side, -(help3_shift - 2),
1052*e5436536SAndroid Build Coastguard Worker                                               DFRACT_BITS - 2);
1053*e5436536SAndroid Build Coastguard Worker 
1054*e5436536SAndroid Build Coastguard Worker               left = ((*p2CoeffL) >> 2) + side;
1055*e5436536SAndroid Build Coastguard Worker               right = ((*p2CoeffL) >> 2) - side;
1056*e5436536SAndroid Build Coastguard Worker               right = (FIXP_DBL)((LONG)right * pred_dir);
1057*e5436536SAndroid Build Coastguard Worker 
1058*e5436536SAndroid Build Coastguard Worker               *p2CoeffL++ = SATURATE_LEFT_SHIFT_ALT(left, 2, DFRACT_BITS);
1059*e5436536SAndroid Build Coastguard Worker               *p2CoeffR++ = SATURATE_LEFT_SHIFT_ALT(right, 2, DFRACT_BITS);
1060*e5436536SAndroid Build Coastguard Worker             }
1061*e5436536SAndroid Build Coastguard Worker           }
1062*e5436536SAndroid Build Coastguard Worker 
1063*e5436536SAndroid Build Coastguard Worker         } /* for ( band=0; band < max_sfb_ste; band++ ) */
1064*e5436536SAndroid Build Coastguard Worker       }   /* for ( groupwin=0; groupwin<pWindowGroupLength[group]; groupwin++,
1065*e5436536SAndroid Build Coastguard Worker              window++ ) */
1066*e5436536SAndroid Build Coastguard Worker 
1067*e5436536SAndroid Build Coastguard Worker     } /* for ( window = 0, group = 0; group < windowGroups; group++ ) */
1068*e5436536SAndroid Build Coastguard Worker 
1069*e5436536SAndroid Build Coastguard Worker     /* free scratch buffer */
1070*e5436536SAndroid Build Coastguard Worker     C_AALLOC_SCRATCH_END(dmx_im, FIXP_DBL, 1024);
1071*e5436536SAndroid Build Coastguard Worker 
1072*e5436536SAndroid Build Coastguard Worker   } else {
1073*e5436536SAndroid Build Coastguard Worker     /* MS stereo */
1074*e5436536SAndroid Build Coastguard Worker 
1075*e5436536SAndroid Build Coastguard Worker     for (window = 0, group = 0; group < windowGroups; group++) {
1076*e5436536SAndroid Build Coastguard Worker       groupMask = 1 << group;
1077*e5436536SAndroid Build Coastguard Worker 
1078*e5436536SAndroid Build Coastguard Worker       for (int groupwin = 0; groupwin < pWindowGroupLength[group];
1079*e5436536SAndroid Build Coastguard Worker            groupwin++, window++) {
1080*e5436536SAndroid Build Coastguard Worker         FIXP_DBL *leftSpectrum, *rightSpectrum;
1081*e5436536SAndroid Build Coastguard Worker         SHORT *leftScale = &SFBleftScale[window * 16];
1082*e5436536SAndroid Build Coastguard Worker         SHORT *rightScale = &SFBrightScale[window * 16];
1083*e5436536SAndroid Build Coastguard Worker 
1084*e5436536SAndroid Build Coastguard Worker         leftSpectrum =
1085*e5436536SAndroid Build Coastguard Worker             SPEC(spectrumL, window, pAacDecoderChannelInfo[L]->granuleLength);
1086*e5436536SAndroid Build Coastguard Worker         rightSpectrum =
1087*e5436536SAndroid Build Coastguard Worker             SPEC(spectrumR, window, pAacDecoderChannelInfo[R]->granuleLength);
1088*e5436536SAndroid Build Coastguard Worker 
1089*e5436536SAndroid Build Coastguard Worker         for (band = 0; band < max_sfb_ste_outside; band++) {
1090*e5436536SAndroid Build Coastguard Worker           if (pJointStereoData->MsUsed[band] & groupMask) {
1091*e5436536SAndroid Build Coastguard Worker             int lScale = leftScale[band];
1092*e5436536SAndroid Build Coastguard Worker             int rScale = rightScale[band];
1093*e5436536SAndroid Build Coastguard Worker             int commonScale = lScale > rScale ? lScale : rScale;
1094*e5436536SAndroid Build Coastguard Worker             unsigned int offsetCurrBand, offsetNextBand;
1095*e5436536SAndroid Build Coastguard Worker 
1096*e5436536SAndroid Build Coastguard Worker             /* ISO/IEC 14496-3 Chapter 4.6.8.1.1 :
1097*e5436536SAndroid Build Coastguard Worker                M/S joint channel coding can only be used if common_window is 1.
1098*e5436536SAndroid Build Coastguard Worker              */
1099*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(GetWindowSequence(&pAacDecoderChannelInfo[L]->icsInfo) ==
1100*e5436536SAndroid Build Coastguard Worker                        GetWindowSequence(&pAacDecoderChannelInfo[R]->icsInfo));
1101*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(GetWindowShape(&pAacDecoderChannelInfo[L]->icsInfo) ==
1102*e5436536SAndroid Build Coastguard Worker                        GetWindowShape(&pAacDecoderChannelInfo[R]->icsInfo));
1103*e5436536SAndroid Build Coastguard Worker 
1104*e5436536SAndroid Build Coastguard Worker             commonScale++;
1105*e5436536SAndroid Build Coastguard Worker             leftScale[band] = commonScale;
1106*e5436536SAndroid Build Coastguard Worker             rightScale[band] = commonScale;
1107*e5436536SAndroid Build Coastguard Worker 
1108*e5436536SAndroid Build Coastguard Worker             lScale = fMin(DFRACT_BITS - 1, commonScale - lScale);
1109*e5436536SAndroid Build Coastguard Worker             rScale = fMin(DFRACT_BITS - 1, commonScale - rScale);
1110*e5436536SAndroid Build Coastguard Worker 
1111*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(lScale >= 0 && rScale >= 0);
1112*e5436536SAndroid Build Coastguard Worker 
1113*e5436536SAndroid Build Coastguard Worker             offsetCurrBand = pScaleFactorBandOffsets[band];
1114*e5436536SAndroid Build Coastguard Worker             offsetNextBand = pScaleFactorBandOffsets[band + 1];
1115*e5436536SAndroid Build Coastguard Worker 
1116*e5436536SAndroid Build Coastguard Worker             CJointStereo_GenerateMSOutput(&(leftSpectrum[offsetCurrBand]),
1117*e5436536SAndroid Build Coastguard Worker                                           &(rightSpectrum[offsetCurrBand]),
1118*e5436536SAndroid Build Coastguard Worker                                           lScale, rScale,
1119*e5436536SAndroid Build Coastguard Worker                                           offsetNextBand - offsetCurrBand);
1120*e5436536SAndroid Build Coastguard Worker           }
1121*e5436536SAndroid Build Coastguard Worker         }
1122*e5436536SAndroid Build Coastguard Worker         if (scaleFactorBandsTransmittedL > scaleFactorBandsTransmitted) {
1123*e5436536SAndroid Build Coastguard Worker           for (; band < scaleFactorBandsTransmittedL; band++) {
1124*e5436536SAndroid Build Coastguard Worker             if (pJointStereoData->MsUsed[band] & groupMask) {
1125*e5436536SAndroid Build Coastguard Worker               rightScale[band] = leftScale[band];
1126*e5436536SAndroid Build Coastguard Worker 
1127*e5436536SAndroid Build Coastguard Worker               for (int index = pScaleFactorBandOffsets[band];
1128*e5436536SAndroid Build Coastguard Worker                    index < pScaleFactorBandOffsets[band + 1]; index++) {
1129*e5436536SAndroid Build Coastguard Worker                 FIXP_DBL leftCoefficient = leftSpectrum[index];
1130*e5436536SAndroid Build Coastguard Worker                 /* FIXP_DBL rightCoefficient = (FIXP_DBL)0; */
1131*e5436536SAndroid Build Coastguard Worker                 rightSpectrum[index] = leftCoefficient;
1132*e5436536SAndroid Build Coastguard Worker               }
1133*e5436536SAndroid Build Coastguard Worker             }
1134*e5436536SAndroid Build Coastguard Worker           }
1135*e5436536SAndroid Build Coastguard Worker         } else if (scaleFactorBandsTransmittedR > scaleFactorBandsTransmitted) {
1136*e5436536SAndroid Build Coastguard Worker           for (; band < scaleFactorBandsTransmittedR; band++) {
1137*e5436536SAndroid Build Coastguard Worker             if (pJointStereoData->MsUsed[band] & groupMask) {
1138*e5436536SAndroid Build Coastguard Worker               leftScale[band] = rightScale[band];
1139*e5436536SAndroid Build Coastguard Worker 
1140*e5436536SAndroid Build Coastguard Worker               for (int index = pScaleFactorBandOffsets[band];
1141*e5436536SAndroid Build Coastguard Worker                    index < pScaleFactorBandOffsets[band + 1]; index++) {
1142*e5436536SAndroid Build Coastguard Worker                 /* FIXP_DBL leftCoefficient  = (FIXP_DBL)0; */
1143*e5436536SAndroid Build Coastguard Worker                 FIXP_DBL rightCoefficient = rightSpectrum[index];
1144*e5436536SAndroid Build Coastguard Worker 
1145*e5436536SAndroid Build Coastguard Worker                 leftSpectrum[index] = rightCoefficient;
1146*e5436536SAndroid Build Coastguard Worker                 rightSpectrum[index] = -rightCoefficient;
1147*e5436536SAndroid Build Coastguard Worker               }
1148*e5436536SAndroid Build Coastguard Worker             }
1149*e5436536SAndroid Build Coastguard Worker           }
1150*e5436536SAndroid Build Coastguard Worker         }
1151*e5436536SAndroid Build Coastguard Worker       }
1152*e5436536SAndroid Build Coastguard Worker     }
1153*e5436536SAndroid Build Coastguard Worker 
1154*e5436536SAndroid Build Coastguard Worker     /* Reset MsUsed flags if no explicit signalling was transmitted. Necessary
1155*e5436536SAndroid Build Coastguard Worker        for intensity coding. PNS correlation signalling was mapped before
1156*e5436536SAndroid Build Coastguard Worker        calling CJointStereo_ApplyMS(). */
1157*e5436536SAndroid Build Coastguard Worker     if (pJointStereoData->MsMaskPresent == 2) {
1158*e5436536SAndroid Build Coastguard Worker       FDKmemclear(pJointStereoData->MsUsed,
1159*e5436536SAndroid Build Coastguard Worker                   JointStereoMaximumBands * sizeof(UCHAR));
1160*e5436536SAndroid Build Coastguard Worker     }
1161*e5436536SAndroid Build Coastguard Worker   }
1162*e5436536SAndroid Build Coastguard Worker }
1163*e5436536SAndroid Build Coastguard Worker 
CJointStereo_ApplyIS(CAacDecoderChannelInfo * pAacDecoderChannelInfo[2],const SHORT * pScaleFactorBandOffsets,const UCHAR * pWindowGroupLength,const int windowGroups,const int scaleFactorBandsTransmitted)1164*e5436536SAndroid Build Coastguard Worker void CJointStereo_ApplyIS(CAacDecoderChannelInfo *pAacDecoderChannelInfo[2],
1165*e5436536SAndroid Build Coastguard Worker                           const SHORT *pScaleFactorBandOffsets,
1166*e5436536SAndroid Build Coastguard Worker                           const UCHAR *pWindowGroupLength,
1167*e5436536SAndroid Build Coastguard Worker                           const int windowGroups,
1168*e5436536SAndroid Build Coastguard Worker                           const int scaleFactorBandsTransmitted) {
1169*e5436536SAndroid Build Coastguard Worker   CJointStereoData *pJointStereoData =
1170*e5436536SAndroid Build Coastguard Worker       &pAacDecoderChannelInfo[L]->pComData->jointStereoData;
1171*e5436536SAndroid Build Coastguard Worker 
1172*e5436536SAndroid Build Coastguard Worker   for (int window = 0, group = 0; group < windowGroups; group++) {
1173*e5436536SAndroid Build Coastguard Worker     UCHAR *CodeBook;
1174*e5436536SAndroid Build Coastguard Worker     SHORT *ScaleFactor;
1175*e5436536SAndroid Build Coastguard Worker     UCHAR groupMask = 1 << group;
1176*e5436536SAndroid Build Coastguard Worker 
1177*e5436536SAndroid Build Coastguard Worker     CodeBook = &pAacDecoderChannelInfo[R]->pDynData->aCodeBook[group * 16];
1178*e5436536SAndroid Build Coastguard Worker     ScaleFactor =
1179*e5436536SAndroid Build Coastguard Worker         &pAacDecoderChannelInfo[R]->pDynData->aScaleFactor[group * 16];
1180*e5436536SAndroid Build Coastguard Worker 
1181*e5436536SAndroid Build Coastguard Worker     for (int groupwin = 0; groupwin < pWindowGroupLength[group];
1182*e5436536SAndroid Build Coastguard Worker          groupwin++, window++) {
1183*e5436536SAndroid Build Coastguard Worker       FIXP_DBL *leftSpectrum, *rightSpectrum;
1184*e5436536SAndroid Build Coastguard Worker       SHORT *leftScale =
1185*e5436536SAndroid Build Coastguard Worker           &pAacDecoderChannelInfo[L]->pDynData->aSfbScale[window * 16];
1186*e5436536SAndroid Build Coastguard Worker       SHORT *rightScale =
1187*e5436536SAndroid Build Coastguard Worker           &pAacDecoderChannelInfo[R]->pDynData->aSfbScale[window * 16];
1188*e5436536SAndroid Build Coastguard Worker       int band;
1189*e5436536SAndroid Build Coastguard Worker 
1190*e5436536SAndroid Build Coastguard Worker       leftSpectrum = SPEC(pAacDecoderChannelInfo[L]->pSpectralCoefficient,
1191*e5436536SAndroid Build Coastguard Worker                           window, pAacDecoderChannelInfo[L]->granuleLength);
1192*e5436536SAndroid Build Coastguard Worker       rightSpectrum = SPEC(pAacDecoderChannelInfo[R]->pSpectralCoefficient,
1193*e5436536SAndroid Build Coastguard Worker                            window, pAacDecoderChannelInfo[R]->granuleLength);
1194*e5436536SAndroid Build Coastguard Worker 
1195*e5436536SAndroid Build Coastguard Worker       for (band = 0; band < scaleFactorBandsTransmitted; band++) {
1196*e5436536SAndroid Build Coastguard Worker         if ((CodeBook[band] == INTENSITY_HCB) ||
1197*e5436536SAndroid Build Coastguard Worker             (CodeBook[band] == INTENSITY_HCB2)) {
1198*e5436536SAndroid Build Coastguard Worker           int bandScale = -(ScaleFactor[band] + 100);
1199*e5436536SAndroid Build Coastguard Worker 
1200*e5436536SAndroid Build Coastguard Worker           int msb = bandScale >> 2;
1201*e5436536SAndroid Build Coastguard Worker           int lsb = bandScale & 0x03;
1202*e5436536SAndroid Build Coastguard Worker 
1203*e5436536SAndroid Build Coastguard Worker           /* exponent of MantissaTable[lsb][0] is 1, thus msb+1 below. */
1204*e5436536SAndroid Build Coastguard Worker           FIXP_DBL scale = MantissaTable[lsb][0];
1205*e5436536SAndroid Build Coastguard Worker 
1206*e5436536SAndroid Build Coastguard Worker           /* ISO/IEC 14496-3 Chapter 4.6.8.2.3 :
1207*e5436536SAndroid Build Coastguard Worker              The use of intensity stereo coding is signaled by the use of the
1208*e5436536SAndroid Build Coastguard Worker              pseudo codebooks INTENSITY_HCB and INTENSITY_HCB2 (15 and 14) only
1209*e5436536SAndroid Build Coastguard Worker              in the right channel of a channel_pair_element() having a common
1210*e5436536SAndroid Build Coastguard Worker              ics_info() (common_window == 1). */
1211*e5436536SAndroid Build Coastguard Worker           FDK_ASSERT(GetWindowSequence(&pAacDecoderChannelInfo[L]->icsInfo) ==
1212*e5436536SAndroid Build Coastguard Worker                      GetWindowSequence(&pAacDecoderChannelInfo[R]->icsInfo));
1213*e5436536SAndroid Build Coastguard Worker           FDK_ASSERT(GetWindowShape(&pAacDecoderChannelInfo[L]->icsInfo) ==
1214*e5436536SAndroid Build Coastguard Worker                      GetWindowShape(&pAacDecoderChannelInfo[R]->icsInfo));
1215*e5436536SAndroid Build Coastguard Worker 
1216*e5436536SAndroid Build Coastguard Worker           rightScale[band] = leftScale[band] + msb + 1;
1217*e5436536SAndroid Build Coastguard Worker 
1218*e5436536SAndroid Build Coastguard Worker           if (pJointStereoData->MsUsed[band] & groupMask) {
1219*e5436536SAndroid Build Coastguard Worker             if (CodeBook[band] == INTENSITY_HCB) /* _NOT_ in-phase */
1220*e5436536SAndroid Build Coastguard Worker             {
1221*e5436536SAndroid Build Coastguard Worker               scale = -scale;
1222*e5436536SAndroid Build Coastguard Worker             }
1223*e5436536SAndroid Build Coastguard Worker           } else {
1224*e5436536SAndroid Build Coastguard Worker             if (CodeBook[band] == INTENSITY_HCB2) /* out-of-phase */
1225*e5436536SAndroid Build Coastguard Worker             {
1226*e5436536SAndroid Build Coastguard Worker               scale = -scale;
1227*e5436536SAndroid Build Coastguard Worker             }
1228*e5436536SAndroid Build Coastguard Worker           }
1229*e5436536SAndroid Build Coastguard Worker 
1230*e5436536SAndroid Build Coastguard Worker           for (int index = pScaleFactorBandOffsets[band];
1231*e5436536SAndroid Build Coastguard Worker                index < pScaleFactorBandOffsets[band + 1]; index++) {
1232*e5436536SAndroid Build Coastguard Worker             rightSpectrum[index] = fMult(leftSpectrum[index], scale);
1233*e5436536SAndroid Build Coastguard Worker           }
1234*e5436536SAndroid Build Coastguard Worker         }
1235*e5436536SAndroid Build Coastguard Worker       }
1236*e5436536SAndroid Build Coastguard Worker     }
1237*e5436536SAndroid Build Coastguard Worker   }
1238*e5436536SAndroid Build Coastguard Worker }
1239