xref: /aosp_15_r20/external/aac/libPCMutils/src/pcmdmx_lib.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 - 2021 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 /**************************** PCM utility library ******************************
96*e5436536SAndroid Build Coastguard Worker 
97*e5436536SAndroid Build Coastguard Worker    Author(s):   Christian Griebel
98*e5436536SAndroid Build Coastguard Worker 
99*e5436536SAndroid Build Coastguard Worker    Description: Defines functions that perform downmixing or a simple channel
100*e5436536SAndroid Build Coastguard Worker                 expansion in the PCM time domain.
101*e5436536SAndroid Build Coastguard Worker 
102*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
103*e5436536SAndroid Build Coastguard Worker 
104*e5436536SAndroid Build Coastguard Worker #include "pcmdmx_lib.h"
105*e5436536SAndroid Build Coastguard Worker 
106*e5436536SAndroid Build Coastguard Worker #include "genericStds.h"
107*e5436536SAndroid Build Coastguard Worker #include "fixpoint_math.h"
108*e5436536SAndroid Build Coastguard Worker #include "FDK_core.h"
109*e5436536SAndroid Build Coastguard Worker 
110*e5436536SAndroid Build Coastguard Worker /* library version */
111*e5436536SAndroid Build Coastguard Worker #include "version.h"
112*e5436536SAndroid Build Coastguard Worker /* library title */
113*e5436536SAndroid Build Coastguard Worker #define PCMDMX_LIB_TITLE "PCM Downmix Lib"
114*e5436536SAndroid Build Coastguard Worker 
115*e5436536SAndroid Build Coastguard Worker #define FALSE 0
116*e5436536SAndroid Build Coastguard Worker #define TRUE 1
117*e5436536SAndroid Build Coastguard Worker #define IN 0
118*e5436536SAndroid Build Coastguard Worker #define OUT 1
119*e5436536SAndroid Build Coastguard Worker 
120*e5436536SAndroid Build Coastguard Worker /* Type definitions: */
121*e5436536SAndroid Build Coastguard Worker #define FIXP_DMX FIXP_SGL
122*e5436536SAndroid Build Coastguard Worker #define FX_DMX2FX_DBL(x) FX_SGL2FX_DBL((FIXP_SGL)(x))
123*e5436536SAndroid Build Coastguard Worker #define FX_DBL2FX_DMX(x) FX_DBL2FX_SGL(x)
124*e5436536SAndroid Build Coastguard Worker #define FL2FXCONST_DMX(x) FL2FXCONST_SGL(x)
125*e5436536SAndroid Build Coastguard Worker #define MAXVAL_DMX MAXVAL_SGL
126*e5436536SAndroid Build Coastguard Worker #define FX_DMX2SHRT(x) ((SHORT)(x))
127*e5436536SAndroid Build Coastguard Worker #define FX_DMX2FL(x) FX_DBL2FL(FX_DMX2FX_DBL(x))
128*e5436536SAndroid Build Coastguard Worker 
129*e5436536SAndroid Build Coastguard Worker /* Fixed and unique channel group indices.
130*e5436536SAndroid Build Coastguard Worker  * The last group index has to be smaller than ( 4 ). */
131*e5436536SAndroid Build Coastguard Worker #define CH_GROUP_FRONT (0)
132*e5436536SAndroid Build Coastguard Worker #define CH_GROUP_SIDE (1)
133*e5436536SAndroid Build Coastguard Worker #define CH_GROUP_REAR (2)
134*e5436536SAndroid Build Coastguard Worker #define CH_GROUP_LFE (3)
135*e5436536SAndroid Build Coastguard Worker 
136*e5436536SAndroid Build Coastguard Worker /* Fixed and unique channel plain indices. */
137*e5436536SAndroid Build Coastguard Worker #define CH_PLAIN_NORMAL (0)
138*e5436536SAndroid Build Coastguard Worker #define CH_PLAIN_TOP (1)
139*e5436536SAndroid Build Coastguard Worker #define CH_PLAIN_BOTTOM (2)
140*e5436536SAndroid Build Coastguard Worker 
141*e5436536SAndroid Build Coastguard Worker /* The ordering of the following fixed channel labels has to be in MPEG-4 style.
142*e5436536SAndroid Build Coastguard Worker  * From the center to the back with left and right channel interleaved (starting
143*e5436536SAndroid Build Coastguard Worker  * with left). The last channel label index has to be smaller than ( 8 ). */
144*e5436536SAndroid Build Coastguard Worker #define CENTER_FRONT_CHANNEL (0) /* C  */
145*e5436536SAndroid Build Coastguard Worker #define LEFT_FRONT_CHANNEL (1)   /* L  */
146*e5436536SAndroid Build Coastguard Worker #define RIGHT_FRONT_CHANNEL (2)  /* R  */
147*e5436536SAndroid Build Coastguard Worker #define LEFT_REAR_CHANNEL \
148*e5436536SAndroid Build Coastguard Worker   (3) /* Lr (aka left back channel) or center back channel */
149*e5436536SAndroid Build Coastguard Worker #define RIGHT_REAR_CHANNEL (4)      /* Rr (aka right back channel) */
150*e5436536SAndroid Build Coastguard Worker #define LOW_FREQUENCY_CHANNEL (5)   /* Lf */
151*e5436536SAndroid Build Coastguard Worker #define LEFT_MULTIPRPS_CHANNEL (6)  /* Left multipurpose channel */
152*e5436536SAndroid Build Coastguard Worker #define RIGHT_MULTIPRPS_CHANNEL (7) /* Right multipurpose channel */
153*e5436536SAndroid Build Coastguard Worker 
154*e5436536SAndroid Build Coastguard Worker /* 22.2 channel specific fixed channel lables: */
155*e5436536SAndroid Build Coastguard Worker #define LEFT_SIDE_CHANNEL (8)            /* Lss  */
156*e5436536SAndroid Build Coastguard Worker #define RIGHT_SIDE_CHANNEL (9)           /* Rss  */
157*e5436536SAndroid Build Coastguard Worker #define CENTER_REAR_CHANNEL (10)         /* Cs   */
158*e5436536SAndroid Build Coastguard Worker #define CENTER_FRONT_CHANNEL_TOP (11)    /* Cv   */
159*e5436536SAndroid Build Coastguard Worker #define LEFT_FRONT_CHANNEL_TOP (12)      /* Lv   */
160*e5436536SAndroid Build Coastguard Worker #define RIGHT_FRONT_CHANNEL_TOP (13)     /* Rv   */
161*e5436536SAndroid Build Coastguard Worker #define LEFT_SIDE_CHANNEL_TOP (14)       /* Lvss */
162*e5436536SAndroid Build Coastguard Worker #define RIGHT_SIDE_CHANNEL_TOP (15)      /* Rvss */
163*e5436536SAndroid Build Coastguard Worker #define CENTER_SIDE_CHANNEL_TOP (16)     /* Ts   */
164*e5436536SAndroid Build Coastguard Worker #define LEFT_REAR_CHANNEL_TOP (17)       /* Lvr  */
165*e5436536SAndroid Build Coastguard Worker #define RIGHT_REAR_CHANNEL_TOP (18)      /* Rvr  */
166*e5436536SAndroid Build Coastguard Worker #define CENTER_REAR_CHANNEL_TOP (19)     /* Cvr  */
167*e5436536SAndroid Build Coastguard Worker #define CENTER_FRONT_CHANNEL_BOTTOM (20) /* Cb   */
168*e5436536SAndroid Build Coastguard Worker #define LEFT_FRONT_CHANNEL_BOTTOM (21)   /* Lb   */
169*e5436536SAndroid Build Coastguard Worker #define RIGHT_FRONT_CHANNEL_BOTTOM (22)  /* Rb   */
170*e5436536SAndroid Build Coastguard Worker #define LOW_FREQUENCY_CHANNEL_2 (23)     /* LFE2 */
171*e5436536SAndroid Build Coastguard Worker 
172*e5436536SAndroid Build Coastguard Worker /* More constants */
173*e5436536SAndroid Build Coastguard Worker #define ONE_CHANNEL (1)
174*e5436536SAndroid Build Coastguard Worker #define TWO_CHANNEL (2)
175*e5436536SAndroid Build Coastguard Worker #define SIX_CHANNEL (6)
176*e5436536SAndroid Build Coastguard Worker #define EIGHT_CHANNEL (8)
177*e5436536SAndroid Build Coastguard Worker #define TWENTY_FOUR_CHANNEL (24)
178*e5436536SAndroid Build Coastguard Worker 
179*e5436536SAndroid Build Coastguard Worker #define PCMDMX_THRESHOLD_MAP_HEAT_1 (0) /* Store only exact matches */
180*e5436536SAndroid Build Coastguard Worker #define PCMDMX_THRESHOLD_MAP_HEAT_2 (20)
181*e5436536SAndroid Build Coastguard Worker #define PCMDMX_THRESHOLD_MAP_HEAT_3 \
182*e5436536SAndroid Build Coastguard Worker   (256) /* Do not assign normal channels to LFE */
183*e5436536SAndroid Build Coastguard Worker 
184*e5436536SAndroid Build Coastguard Worker #define SP_Z_NRM (0)
185*e5436536SAndroid Build Coastguard Worker #define SP_Z_TOP (2)
186*e5436536SAndroid Build Coastguard Worker #define SP_Z_BOT (-2)
187*e5436536SAndroid Build Coastguard Worker #define SP_Z_LFE (-18)
188*e5436536SAndroid Build Coastguard Worker #define SP_Z_MUL (8) /* Should be smaller than SP_Z_LFE */
189*e5436536SAndroid Build Coastguard Worker 
190*e5436536SAndroid Build Coastguard Worker typedef struct {
191*e5436536SAndroid Build Coastguard Worker   SCHAR x; /* horizontal position:  center (0), left (-), right (+) */
192*e5436536SAndroid Build Coastguard Worker   SCHAR y; /* deepth position:      front, side, back, position */
193*e5436536SAndroid Build Coastguard Worker   SCHAR z; /* heigth positions:     normal, top, bottom, lfe */
194*e5436536SAndroid Build Coastguard Worker } PCM_DMX_SPEAKER_POSITION;
195*e5436536SAndroid Build Coastguard Worker 
196*e5436536SAndroid Build Coastguard Worker /* CAUTION: The maximum x-value should be less or equal to
197*e5436536SAndroid Build Coastguard Worker  * PCMDMX_SPKR_POS_X_MAX_WIDTH. */
198*e5436536SAndroid Build Coastguard Worker static const PCM_DMX_SPEAKER_POSITION spkrSlotPos[] = {
199*e5436536SAndroid Build Coastguard Worker     /*  x,  y,  z  */
200*e5436536SAndroid Build Coastguard Worker     {0, 0, SP_Z_NRM},  /* 0  CENTER_FRONT_CHANNEL        */
201*e5436536SAndroid Build Coastguard Worker     {-2, 0, SP_Z_NRM}, /* 1  LEFT_FRONT_CHANNEL          */
202*e5436536SAndroid Build Coastguard Worker     {2, 0, SP_Z_NRM},  /* 2  RIGHT_FRONT_CHANNEL         */
203*e5436536SAndroid Build Coastguard Worker     {-3, 4, SP_Z_NRM}, /* 3  LEFT_REAR_CHANNEL           */
204*e5436536SAndroid Build Coastguard Worker     {3, 4, SP_Z_NRM},  /* 4  RIGHT_REAR_CHANNEL          */
205*e5436536SAndroid Build Coastguard Worker     {0, 0, SP_Z_LFE},  /* 5  LOW_FREQUENCY_CHANNEL       */
206*e5436536SAndroid Build Coastguard Worker     {-2, 2, SP_Z_MUL}, /* 6  LEFT_MULTIPRPS_CHANNEL      */
207*e5436536SAndroid Build Coastguard Worker     {2, 2, SP_Z_MUL}   /* 7  RIGHT_MULTIPRPS_CHANNEL     */
208*e5436536SAndroid Build Coastguard Worker };
209*e5436536SAndroid Build Coastguard Worker 
210*e5436536SAndroid Build Coastguard Worker /* List of packed channel modes */
211*e5436536SAndroid Build Coastguard Worker typedef enum { /* CH_MODE_<numFrontCh>_<numSideCh>_<numBackCh>_<numLfCh> */
212*e5436536SAndroid Build Coastguard Worker                CH_MODE_UNDEFINED = 0x0000,
213*e5436536SAndroid Build Coastguard Worker                /* 1 channel */
214*e5436536SAndroid Build Coastguard Worker                CH_MODE_1_0_0_0 = 0x0001, /* chCfg 1 */
215*e5436536SAndroid Build Coastguard Worker                /* 2 channels */
216*e5436536SAndroid Build Coastguard Worker                CH_MODE_2_0_0_0 = 0x0002 /* chCfg 2 */
217*e5436536SAndroid Build Coastguard Worker                                         /* 3 channels */
218*e5436536SAndroid Build Coastguard Worker                ,
219*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_0_0_0 = 0x0003, /* chCfg 3 */
220*e5436536SAndroid Build Coastguard Worker                CH_MODE_2_0_1_0 = 0x0102,
221*e5436536SAndroid Build Coastguard Worker                CH_MODE_2_0_0_1 = 0x1002,
222*e5436536SAndroid Build Coastguard Worker                /* 4 channels */
223*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_0_1_0 = 0x0103, /* chCfg 4 */
224*e5436536SAndroid Build Coastguard Worker                CH_MODE_2_0_2_0 = 0x0202,
225*e5436536SAndroid Build Coastguard Worker                CH_MODE_2_0_1_1 = 0x1102,
226*e5436536SAndroid Build Coastguard Worker                CH_MODE_4_0_0_0 = 0x0004,
227*e5436536SAndroid Build Coastguard Worker                /* 5 channels */
228*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_0_2_0 = 0x0203, /* chCfg 5 */
229*e5436536SAndroid Build Coastguard Worker                CH_MODE_2_0_2_1 = 0x1202,
230*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_0_1_1 = 0x1103,
231*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_2_0_0 = 0x0023,
232*e5436536SAndroid Build Coastguard Worker                CH_MODE_5_0_0_0 = 0x0005,
233*e5436536SAndroid Build Coastguard Worker                /* 6 channels */
234*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_0_2_1 = 0x1203, /* chCfg 6 */
235*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_2_0_1 = 0x1023,
236*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_2_1_0 = 0x0123,
237*e5436536SAndroid Build Coastguard Worker                CH_MODE_5_0_1_0 = 0x0105,
238*e5436536SAndroid Build Coastguard Worker                CH_MODE_6_0_0_0 = 0x0006,
239*e5436536SAndroid Build Coastguard Worker                /* 7 channels */
240*e5436536SAndroid Build Coastguard Worker                CH_MODE_2_2_2_1 = 0x1222,
241*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_0_3_1 = 0x1303, /* chCfg 11 */
242*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_2_1_1 = 0x1123,
243*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_2_2_0 = 0x0223,
244*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_0_2_2 = 0x2203,
245*e5436536SAndroid Build Coastguard Worker                CH_MODE_5_0_2_0 = 0x0205,
246*e5436536SAndroid Build Coastguard Worker                CH_MODE_5_0_1_1 = 0x1105,
247*e5436536SAndroid Build Coastguard Worker                CH_MODE_7_0_0_0 = 0x0007,
248*e5436536SAndroid Build Coastguard Worker                /* 8 channels */
249*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_2_2_1 = 0x1223,
250*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_0_4_1 = 0x1403, /* chCfg 12 */
251*e5436536SAndroid Build Coastguard Worker                CH_MODE_5_0_2_1 = 0x1205, /* chCfg 7 + 14 */
252*e5436536SAndroid Build Coastguard Worker                CH_MODE_5_2_1_0 = 0x0125,
253*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_2_1_2 = 0x2123,
254*e5436536SAndroid Build Coastguard Worker                CH_MODE_2_2_2_2 = 0x2222,
255*e5436536SAndroid Build Coastguard Worker                CH_MODE_3_0_3_2 = 0x2303,
256*e5436536SAndroid Build Coastguard Worker                CH_MODE_8_0_0_0 = 0x0008
257*e5436536SAndroid Build Coastguard Worker 
258*e5436536SAndroid Build Coastguard Worker } PCM_DMX_CHANNEL_MODE;
259*e5436536SAndroid Build Coastguard Worker 
260*e5436536SAndroid Build Coastguard Worker /* These are the channel configurations linked to
261*e5436536SAndroid Build Coastguard Worker    the number of output channels give by the user: */
262*e5436536SAndroid Build Coastguard Worker static const PCM_DMX_CHANNEL_MODE outChModeTable[(8) + 1] = {
263*e5436536SAndroid Build Coastguard Worker     CH_MODE_UNDEFINED,
264*e5436536SAndroid Build Coastguard Worker     CH_MODE_1_0_0_0, /* 1 channel  */
265*e5436536SAndroid Build Coastguard Worker     CH_MODE_2_0_0_0  /* 2 channels */
266*e5436536SAndroid Build Coastguard Worker     ,
267*e5436536SAndroid Build Coastguard Worker     CH_MODE_3_0_0_0, /* 3 channels */
268*e5436536SAndroid Build Coastguard Worker     CH_MODE_3_0_1_0, /* 4 channels */
269*e5436536SAndroid Build Coastguard Worker     CH_MODE_3_0_2_0, /* 5 channels */
270*e5436536SAndroid Build Coastguard Worker     CH_MODE_3_0_2_1  /* 6 channels */
271*e5436536SAndroid Build Coastguard Worker     ,
272*e5436536SAndroid Build Coastguard Worker     CH_MODE_3_0_3_1, /* 7 channels */
273*e5436536SAndroid Build Coastguard Worker     CH_MODE_3_0_4_1  /* 8 channels */
274*e5436536SAndroid Build Coastguard Worker };
275*e5436536SAndroid Build Coastguard Worker 
276*e5436536SAndroid Build Coastguard Worker static const FIXP_DMX abMixLvlValueTab[8] = {
277*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.500f), /* scaled by 1 */
278*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.841f), FL2FXCONST_DMX(0.707f), FL2FXCONST_DMX(0.596f),
279*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.500f), FL2FXCONST_DMX(0.422f), FL2FXCONST_DMX(0.355f),
280*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.0f)};
281*e5436536SAndroid Build Coastguard Worker 
282*e5436536SAndroid Build Coastguard Worker static const FIXP_DMX lfeMixLvlValueTab[16] = {
283*e5436536SAndroid Build Coastguard Worker     /*             value,        scale */
284*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.7905f), /*     2 */
285*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.5000f), /*     2 */
286*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.8395f), /*     1 */
287*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.7065f), /*     1 */
288*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.5945f), /*     1 */
289*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.500f),  /*     1 */
290*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.841f),  /*     0 */
291*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.707f),  /*     0 */
292*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.596f),  /*     0 */
293*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.500f),  /*     0 */
294*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.316f),  /*     0 */
295*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.178f),  /*     0 */
296*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.100f),  /*     0 */
297*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.032f),  /*     0 */
298*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.010f),  /*     0 */
299*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.000f)   /*     0 */
300*e5436536SAndroid Build Coastguard Worker };
301*e5436536SAndroid Build Coastguard Worker 
302*e5436536SAndroid Build Coastguard Worker /* MPEG matrix mixdown:
303*e5436536SAndroid Build Coastguard Worker     Set 1:  L' = (1 + 2^-0.5 + A )^-1 * [L + C * 2^-0.5 + A * Ls];
304*e5436536SAndroid Build Coastguard Worker             R' = (1 + 2^-0.5 + A )^-1 * [R + C * 2^-0.5 + A * Rs];
305*e5436536SAndroid Build Coastguard Worker 
306*e5436536SAndroid Build Coastguard Worker     Set 2:  L' = (1 + 2^-0.5 + 2A )^-1 * [L + C * 2^-0.5 - A * (Ls + Rs)];
307*e5436536SAndroid Build Coastguard Worker             R' = (1 + 2^-0.5 + 2A )^-1 * [R + C * 2^-0.5 + A * (Ls + Rs)];
308*e5436536SAndroid Build Coastguard Worker 
309*e5436536SAndroid Build Coastguard Worker     M = (3 + 2A)^-1 * [L + C + R + A*(Ls + Rs)];
310*e5436536SAndroid Build Coastguard Worker */
311*e5436536SAndroid Build Coastguard Worker static const FIXP_DMX mpegMixDownIdx2Coef[4] = {
312*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.70710678f), FL2FXCONST_DMX(0.5f),
313*e5436536SAndroid Build Coastguard Worker     FL2FXCONST_DMX(0.35355339f), FL2FXCONST_DMX(0.0f)};
314*e5436536SAndroid Build Coastguard Worker 
315*e5436536SAndroid Build Coastguard Worker static const FIXP_DMX mpegMixDownIdx2PreFact[3][4] = {
316*e5436536SAndroid Build Coastguard Worker     {/* Set 1: */
317*e5436536SAndroid Build Coastguard Worker      FL2FXCONST_DMX(0.4142135623730950f), FL2FXCONST_DMX(0.4530818393219728f),
318*e5436536SAndroid Build Coastguard Worker      FL2FXCONST_DMX(0.4852813742385703f), FL2FXCONST_DMX(0.5857864376269050f)},
319*e5436536SAndroid Build Coastguard Worker     {/* Set 2: */
320*e5436536SAndroid Build Coastguard Worker      FL2FXCONST_DMX(0.3203772410170407f), FL2FXCONST_DMX(0.3693980625181293f),
321*e5436536SAndroid Build Coastguard Worker      FL2FXCONST_DMX(0.4142135623730950f), FL2FXCONST_DMX(0.5857864376269050f)},
322*e5436536SAndroid Build Coastguard Worker     {/* Mono DMX set: */
323*e5436536SAndroid Build Coastguard Worker      FL2FXCONST_DMX(0.2265409196609864f), FL2FXCONST_DMX(0.25f),
324*e5436536SAndroid Build Coastguard Worker      FL2FXCONST_DMX(0.2697521433898179f), FL2FXCONST_DMX(0.3333333333333333f)}};
325*e5436536SAndroid Build Coastguard Worker 
326*e5436536SAndroid Build Coastguard Worker #define TYPE_NONE (0x00)
327*e5436536SAndroid Build Coastguard Worker #define TYPE_PCE_DATA (0x01)
328*e5436536SAndroid Build Coastguard Worker #define TYPE_DSE_CLEV_DATA (0x02)
329*e5436536SAndroid Build Coastguard Worker #define TYPE_DSE_SLEV_DATA (0x04)
330*e5436536SAndroid Build Coastguard Worker #define TYPE_DSE_DMIX_AB_DATA (0x08)
331*e5436536SAndroid Build Coastguard Worker #define TYPE_DSE_DMIX_LFE_DATA (0x10)
332*e5436536SAndroid Build Coastguard Worker #define TYPE_DSE_DMX_GAIN_DATA (0x20)
333*e5436536SAndroid Build Coastguard Worker #define TYPE_DSE_DMX_CGL_DATA (0x40)
334*e5436536SAndroid Build Coastguard Worker #define TYPE_DSE_DATA (0x7E)
335*e5436536SAndroid Build Coastguard Worker 
336*e5436536SAndroid Build Coastguard Worker typedef struct {
337*e5436536SAndroid Build Coastguard Worker   UINT typeFlags;
338*e5436536SAndroid Build Coastguard Worker   /* From DSE */
339*e5436536SAndroid Build Coastguard Worker   UCHAR cLevIdx;
340*e5436536SAndroid Build Coastguard Worker   UCHAR sLevIdx;
341*e5436536SAndroid Build Coastguard Worker   UCHAR dmixIdxA;
342*e5436536SAndroid Build Coastguard Worker   UCHAR dmixIdxB;
343*e5436536SAndroid Build Coastguard Worker   UCHAR dmixIdxLfe;
344*e5436536SAndroid Build Coastguard Worker   UCHAR dmxGainIdx2;
345*e5436536SAndroid Build Coastguard Worker   UCHAR dmxGainIdx5;
346*e5436536SAndroid Build Coastguard Worker   /* From PCE */
347*e5436536SAndroid Build Coastguard Worker   UCHAR matrixMixdownIdx;
348*e5436536SAndroid Build Coastguard Worker   /* Attributes: */
349*e5436536SAndroid Build Coastguard Worker   SCHAR pseudoSurround; /*!< If set to 1 the signal is pseudo surround
350*e5436536SAndroid Build Coastguard Worker                            compatible. The value 0 tells that it is not. If the
351*e5436536SAndroid Build Coastguard Worker                            value is -1 the information is not available.  */
352*e5436536SAndroid Build Coastguard Worker   UINT expiryCount; /*!< Counter to monitor the life time of a meta data set. */
353*e5436536SAndroid Build Coastguard Worker 
354*e5436536SAndroid Build Coastguard Worker } DMX_BS_META_DATA;
355*e5436536SAndroid Build Coastguard Worker 
356*e5436536SAndroid Build Coastguard Worker /* Default metadata */
357*e5436536SAndroid Build Coastguard Worker static const DMX_BS_META_DATA dfltMetaData = {0, 2, 2, 2,  2, 15,
358*e5436536SAndroid Build Coastguard Worker                                               0, 0, 0, -1, 0};
359*e5436536SAndroid Build Coastguard Worker 
360*e5436536SAndroid Build Coastguard Worker /* Dynamic (user) params:
361*e5436536SAndroid Build Coastguard Worker      See the definition of PCMDMX_PARAM for details on the specific fields. */
362*e5436536SAndroid Build Coastguard Worker typedef struct {
363*e5436536SAndroid Build Coastguard Worker   DMX_PROFILE_TYPE dmxProfile; /*!< Linked to DMX_PRFL_STANDARD              */
364*e5436536SAndroid Build Coastguard Worker   UINT expiryFrame;            /*!< Linked to DMX_BS_DATA_EXPIRY_FRAME       */
365*e5436536SAndroid Build Coastguard Worker   DUAL_CHANNEL_MODE dualChannelMode; /*!< Linked to DMX_DUAL_CHANNEL_MODE */
366*e5436536SAndroid Build Coastguard Worker   PSEUDO_SURROUND_MODE
367*e5436536SAndroid Build Coastguard Worker   pseudoSurrMode;          /*!< Linked to DMX_PSEUDO_SURROUND_MODE       */
368*e5436536SAndroid Build Coastguard Worker   SHORT numOutChannelsMin; /*!< Linked to MIN_NUMBER_OF_OUTPUT_CHANNELS  */
369*e5436536SAndroid Build Coastguard Worker   SHORT numOutChannelsMax; /*!< Linked to MAX_NUMBER_OF_OUTPUT_CHANNELS  */
370*e5436536SAndroid Build Coastguard Worker   UCHAR frameDelay;        /*!< Linked to DMX_BS_DATA_DELAY              */
371*e5436536SAndroid Build Coastguard Worker 
372*e5436536SAndroid Build Coastguard Worker } PCM_DMX_USER_PARAMS;
373*e5436536SAndroid Build Coastguard Worker 
374*e5436536SAndroid Build Coastguard Worker /* Modules main data structure: */
375*e5436536SAndroid Build Coastguard Worker struct PCM_DMX_INSTANCE {
376*e5436536SAndroid Build Coastguard Worker   /* Metadata */
377*e5436536SAndroid Build Coastguard Worker   DMX_BS_META_DATA bsMetaData[(1) + 1];
378*e5436536SAndroid Build Coastguard Worker   PCM_DMX_USER_PARAMS userParams;
379*e5436536SAndroid Build Coastguard Worker 
380*e5436536SAndroid Build Coastguard Worker   UCHAR applyProcessing; /*!< Flag to en-/disable modules processing.
381*e5436536SAndroid Build Coastguard Worker                               The max channel limiting is done independently. */
382*e5436536SAndroid Build Coastguard Worker };
383*e5436536SAndroid Build Coastguard Worker 
384*e5436536SAndroid Build Coastguard Worker /* Memory allocation macro */
385*e5436536SAndroid Build Coastguard Worker C_ALLOC_MEM(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
386*e5436536SAndroid Build Coastguard Worker 
getSpeakerDistance(PCM_DMX_SPEAKER_POSITION posA,PCM_DMX_SPEAKER_POSITION posB)387*e5436536SAndroid Build Coastguard Worker static UINT getSpeakerDistance(PCM_DMX_SPEAKER_POSITION posA,
388*e5436536SAndroid Build Coastguard Worker                                PCM_DMX_SPEAKER_POSITION posB) {
389*e5436536SAndroid Build Coastguard Worker   PCM_DMX_SPEAKER_POSITION diff;
390*e5436536SAndroid Build Coastguard Worker 
391*e5436536SAndroid Build Coastguard Worker   diff.x = posA.x - posB.x;
392*e5436536SAndroid Build Coastguard Worker   diff.y = posA.y - posB.y;
393*e5436536SAndroid Build Coastguard Worker   diff.z = posA.z - posB.z;
394*e5436536SAndroid Build Coastguard Worker 
395*e5436536SAndroid Build Coastguard Worker   return ((diff.x * diff.x) + (diff.y * diff.y) + (diff.z * diff.z));
396*e5436536SAndroid Build Coastguard Worker }
397*e5436536SAndroid Build Coastguard Worker 
getSpeakerPos(AUDIO_CHANNEL_TYPE chType,UCHAR chIndex,UCHAR numChInGrp)398*e5436536SAndroid Build Coastguard Worker static PCM_DMX_SPEAKER_POSITION getSpeakerPos(AUDIO_CHANNEL_TYPE chType,
399*e5436536SAndroid Build Coastguard Worker                                               UCHAR chIndex, UCHAR numChInGrp) {
400*e5436536SAndroid Build Coastguard Worker #define PCMDMX_SPKR_POS_X_MAX_WIDTH (3)
401*e5436536SAndroid Build Coastguard Worker #define PCMDMX_SPKR_POS_Y_SPREAD (2)
402*e5436536SAndroid Build Coastguard Worker #define PCMDMX_SPKR_POS_Z_SPREAD (2)
403*e5436536SAndroid Build Coastguard Worker 
404*e5436536SAndroid Build Coastguard Worker   PCM_DMX_SPEAKER_POSITION spkrPos = {0, 0, 0};
405*e5436536SAndroid Build Coastguard Worker   AUDIO_CHANNEL_TYPE chGrp = (AUDIO_CHANNEL_TYPE)(chType & 0x0F);
406*e5436536SAndroid Build Coastguard Worker   unsigned fHasCenter = numChInGrp & 0x1;
407*e5436536SAndroid Build Coastguard Worker   unsigned chGrpWidth = numChInGrp >> 1;
408*e5436536SAndroid Build Coastguard Worker   unsigned fIsCenter = 0;
409*e5436536SAndroid Build Coastguard Worker   unsigned fIsLfe = (chType == ACT_LFE) ? 1 : 0;
410*e5436536SAndroid Build Coastguard Worker   int offset = 0;
411*e5436536SAndroid Build Coastguard Worker 
412*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(chIndex < numChInGrp);
413*e5436536SAndroid Build Coastguard Worker 
414*e5436536SAndroid Build Coastguard Worker   if ((chGrp == ACT_FRONT) && fHasCenter) {
415*e5436536SAndroid Build Coastguard Worker     if (chIndex == 0) fIsCenter = 1;
416*e5436536SAndroid Build Coastguard Worker     chIndex = (UCHAR)fMax(0, chIndex - 1);
417*e5436536SAndroid Build Coastguard Worker   } else if (fHasCenter && (chIndex == numChInGrp - 1)) {
418*e5436536SAndroid Build Coastguard Worker     fIsCenter = 1;
419*e5436536SAndroid Build Coastguard Worker   }
420*e5436536SAndroid Build Coastguard Worker   /* now all even indices are left (-) */
421*e5436536SAndroid Build Coastguard Worker   if (!fIsCenter) {
422*e5436536SAndroid Build Coastguard Worker     offset = chIndex >> 1;
423*e5436536SAndroid Build Coastguard Worker     if ((chGrp > ACT_FRONT) && (chType != ACT_SIDE) && !fIsLfe) {
424*e5436536SAndroid Build Coastguard Worker       /* the higher the index the lower the distance to the center position */
425*e5436536SAndroid Build Coastguard Worker       offset = chGrpWidth - fHasCenter - offset;
426*e5436536SAndroid Build Coastguard Worker     }
427*e5436536SAndroid Build Coastguard Worker     if ((chIndex & 0x1) == 0) { /* even */
428*e5436536SAndroid Build Coastguard Worker       offset = -(offset + 1);
429*e5436536SAndroid Build Coastguard Worker     } else {
430*e5436536SAndroid Build Coastguard Worker       offset += 1;
431*e5436536SAndroid Build Coastguard Worker     }
432*e5436536SAndroid Build Coastguard Worker   }
433*e5436536SAndroid Build Coastguard Worker   /* apply the offset */
434*e5436536SAndroid Build Coastguard Worker   if (chType == ACT_SIDE) {
435*e5436536SAndroid Build Coastguard Worker     spkrPos.x = (offset < 0) ? -PCMDMX_SPKR_POS_X_MAX_WIDTH
436*e5436536SAndroid Build Coastguard Worker                              : PCMDMX_SPKR_POS_X_MAX_WIDTH;
437*e5436536SAndroid Build Coastguard Worker     spkrPos.y = /* 1x */ PCMDMX_SPKR_POS_Y_SPREAD + (SCHAR)fAbs(offset) - 1;
438*e5436536SAndroid Build Coastguard Worker     spkrPos.z = 0;
439*e5436536SAndroid Build Coastguard Worker   } else {
440*e5436536SAndroid Build Coastguard Worker     unsigned spread =
441*e5436536SAndroid Build Coastguard Worker         ((chGrpWidth == 1) && (!fIsLfe)) ? PCMDMX_SPKR_POS_X_MAX_WIDTH - 1 : 1;
442*e5436536SAndroid Build Coastguard Worker     spkrPos.x = (SCHAR)offset * (SCHAR)spread;
443*e5436536SAndroid Build Coastguard Worker     if (fIsLfe) {
444*e5436536SAndroid Build Coastguard Worker       spkrPos.y = 0;
445*e5436536SAndroid Build Coastguard Worker       spkrPos.z = SP_Z_LFE;
446*e5436536SAndroid Build Coastguard Worker     } else {
447*e5436536SAndroid Build Coastguard Worker       spkrPos.y = (SCHAR)fMax((SCHAR)chGrp - 1, 0) * PCMDMX_SPKR_POS_Y_SPREAD;
448*e5436536SAndroid Build Coastguard Worker       spkrPos.z = (SCHAR)chType >> 4;
449*e5436536SAndroid Build Coastguard Worker       if (spkrPos.z == 2) { /* ACT_BOTTOM */
450*e5436536SAndroid Build Coastguard Worker         spkrPos.z = -1;
451*e5436536SAndroid Build Coastguard Worker       }
452*e5436536SAndroid Build Coastguard Worker       spkrPos.z *= PCMDMX_SPKR_POS_Z_SPREAD;
453*e5436536SAndroid Build Coastguard Worker     }
454*e5436536SAndroid Build Coastguard Worker   }
455*e5436536SAndroid Build Coastguard Worker   return spkrPos;
456*e5436536SAndroid Build Coastguard Worker }
457*e5436536SAndroid Build Coastguard Worker 
458*e5436536SAndroid Build Coastguard Worker /** Return the channel mode of a given horizontal channel plain (normal, top,
459*e5436536SAndroid Build Coastguard Worker  *bottom) for a given channel configuration. NOTE: This function shall get
460*e5436536SAndroid Build Coastguard Worker  *obsolete once the channel mode has been changed to be nonambiguous.
461*e5436536SAndroid Build Coastguard Worker  * @param [in] Index of the requested channel plain.
462*e5436536SAndroid Build Coastguard Worker  * @param [in] The packed channel mode for the complete channel configuration
463*e5436536SAndroid Build Coastguard Worker  *(all plains).
464*e5436536SAndroid Build Coastguard Worker  * @param [in] The MPEG-4 channel configuration index which is necessary in
465*e5436536SAndroid Build Coastguard Worker  *cases where the (packed) channel mode is ambiguous.
466*e5436536SAndroid Build Coastguard Worker  * @returns Returns the packed channel mode of the requested channel plain.
467*e5436536SAndroid Build Coastguard Worker  **/
getChMode4Plain(const int plainIndex,const PCM_DMX_CHANNEL_MODE totChMode,const int chCfg)468*e5436536SAndroid Build Coastguard Worker static PCM_DMX_CHANNEL_MODE getChMode4Plain(
469*e5436536SAndroid Build Coastguard Worker     const int plainIndex, const PCM_DMX_CHANNEL_MODE totChMode,
470*e5436536SAndroid Build Coastguard Worker     const int chCfg) {
471*e5436536SAndroid Build Coastguard Worker   PCM_DMX_CHANNEL_MODE plainChMode = totChMode;
472*e5436536SAndroid Build Coastguard Worker 
473*e5436536SAndroid Build Coastguard Worker   switch (totChMode) {
474*e5436536SAndroid Build Coastguard Worker     case CH_MODE_5_0_2_1:
475*e5436536SAndroid Build Coastguard Worker       if (chCfg == 14) {
476*e5436536SAndroid Build Coastguard Worker         switch (plainIndex) {
477*e5436536SAndroid Build Coastguard Worker           case CH_PLAIN_BOTTOM:
478*e5436536SAndroid Build Coastguard Worker             plainChMode = (PCM_DMX_CHANNEL_MODE)0x0000;
479*e5436536SAndroid Build Coastguard Worker             break;
480*e5436536SAndroid Build Coastguard Worker           case CH_PLAIN_TOP:
481*e5436536SAndroid Build Coastguard Worker             plainChMode = CH_MODE_2_0_0_0;
482*e5436536SAndroid Build Coastguard Worker             break;
483*e5436536SAndroid Build Coastguard Worker           case CH_PLAIN_NORMAL:
484*e5436536SAndroid Build Coastguard Worker           default:
485*e5436536SAndroid Build Coastguard Worker             plainChMode = CH_MODE_3_0_2_1;
486*e5436536SAndroid Build Coastguard Worker             break;
487*e5436536SAndroid Build Coastguard Worker         }
488*e5436536SAndroid Build Coastguard Worker       }
489*e5436536SAndroid Build Coastguard Worker       break;
490*e5436536SAndroid Build Coastguard Worker     default:
491*e5436536SAndroid Build Coastguard Worker       break;
492*e5436536SAndroid Build Coastguard Worker   }
493*e5436536SAndroid Build Coastguard Worker 
494*e5436536SAndroid Build Coastguard Worker   return plainChMode;
495*e5436536SAndroid Build Coastguard Worker }
496*e5436536SAndroid Build Coastguard Worker 
497*e5436536SAndroid Build Coastguard Worker /** Validates the channel indices of all channels present in the bitstream.
498*e5436536SAndroid Build Coastguard Worker  * The channel indices have to be consecutive and unique for each audio channel
499*e5436536SAndroid Build Coastguard Worker  *type.
500*e5436536SAndroid Build Coastguard Worker  * @param [in] The total number of channels of the given configuration.
501*e5436536SAndroid Build Coastguard Worker  * @param [in] The total number of channels of the current audio channel type of
502*e5436536SAndroid Build Coastguard Worker  *the given configuration.
503*e5436536SAndroid Build Coastguard Worker  * @param [in] Audio channel type to be examined.
504*e5436536SAndroid Build Coastguard Worker  * @param [in] Array holding the corresponding channel types for each channel.
505*e5436536SAndroid Build Coastguard Worker  * @param [in] Array holding the corresponding channel type indices for each
506*e5436536SAndroid Build Coastguard Worker  *channel.
507*e5436536SAndroid Build Coastguard Worker  * @returns Returns 1 on success, returns 0 on error.
508*e5436536SAndroid Build Coastguard Worker  **/
validateIndices(UINT numChannels,UINT numChannelsPlaneAndGrp,AUDIO_CHANNEL_TYPE aChType,const AUDIO_CHANNEL_TYPE channelType[],const UCHAR channelIndices[])509*e5436536SAndroid Build Coastguard Worker static UINT validateIndices(UINT numChannels, UINT numChannelsPlaneAndGrp,
510*e5436536SAndroid Build Coastguard Worker                             AUDIO_CHANNEL_TYPE aChType,
511*e5436536SAndroid Build Coastguard Worker                             const AUDIO_CHANNEL_TYPE channelType[],
512*e5436536SAndroid Build Coastguard Worker                             const UCHAR channelIndices[]) {
513*e5436536SAndroid Build Coastguard Worker   for (UINT reqValue = 0; reqValue < numChannelsPlaneAndGrp; reqValue++) {
514*e5436536SAndroid Build Coastguard Worker     int found = FALSE;
515*e5436536SAndroid Build Coastguard Worker     for (UINT i = 0; i < numChannels; i++) {
516*e5436536SAndroid Build Coastguard Worker       if (channelType[i] == aChType) {
517*e5436536SAndroid Build Coastguard Worker         if (channelIndices[i] == reqValue) {
518*e5436536SAndroid Build Coastguard Worker           if (found == TRUE) {
519*e5436536SAndroid Build Coastguard Worker             return 0; /* Found channel index a second time */
520*e5436536SAndroid Build Coastguard Worker           } else {
521*e5436536SAndroid Build Coastguard Worker             found = TRUE; /* Found channel index */
522*e5436536SAndroid Build Coastguard Worker           }
523*e5436536SAndroid Build Coastguard Worker         }
524*e5436536SAndroid Build Coastguard Worker       }
525*e5436536SAndroid Build Coastguard Worker     }
526*e5436536SAndroid Build Coastguard Worker     if (found == FALSE) {
527*e5436536SAndroid Build Coastguard Worker       return 0; /* Did not find channel index */
528*e5436536SAndroid Build Coastguard Worker     }
529*e5436536SAndroid Build Coastguard Worker   }
530*e5436536SAndroid Build Coastguard Worker   return 1; /* Successfully validated channel indices */
531*e5436536SAndroid Build Coastguard Worker }
532*e5436536SAndroid Build Coastguard Worker 
533*e5436536SAndroid Build Coastguard Worker /** Evaluate a given channel configuration and extract a packed channel mode. In
534*e5436536SAndroid Build Coastguard Worker  *addition the function generates a channel offset table for the mapping to the
535*e5436536SAndroid Build Coastguard Worker  *internal representation. This function is the inverse to the
536*e5436536SAndroid Build Coastguard Worker  *getChannelDescription() routine.
537*e5436536SAndroid Build Coastguard Worker  * @param [in] The total number of channels of the given configuration.
538*e5436536SAndroid Build Coastguard Worker  * @param [in] Array holding the corresponding channel types for each channel.
539*e5436536SAndroid Build Coastguard Worker  * @param [in] Array holding the corresponding channel type indices for each
540*e5436536SAndroid Build Coastguard Worker  *channel.
541*e5436536SAndroid Build Coastguard Worker  * @param [out] Array where the buffer offsets for each channel are stored into.
542*e5436536SAndroid Build Coastguard Worker  * @param [out] The generated packed channel mode that represents the given
543*e5436536SAndroid Build Coastguard Worker  *input configuration.
544*e5436536SAndroid Build Coastguard Worker  * @returns Returns an error code.
545*e5436536SAndroid Build Coastguard Worker  **/
getChannelMode(const UINT numChannels,const AUDIO_CHANNEL_TYPE channelType[],UCHAR channelIndices[],UCHAR offsetTable[(8)],PCM_DMX_CHANNEL_MODE * chMode)546*e5436536SAndroid Build Coastguard Worker static PCMDMX_ERROR getChannelMode(
547*e5436536SAndroid Build Coastguard Worker     const UINT numChannels,                 /* in */
548*e5436536SAndroid Build Coastguard Worker     const AUDIO_CHANNEL_TYPE channelType[], /* in */
549*e5436536SAndroid Build Coastguard Worker     UCHAR channelIndices[],                 /* in */
550*e5436536SAndroid Build Coastguard Worker     UCHAR offsetTable[(8)],                 /* out */
551*e5436536SAndroid Build Coastguard Worker     PCM_DMX_CHANNEL_MODE *chMode            /* out */
552*e5436536SAndroid Build Coastguard Worker ) {
553*e5436536SAndroid Build Coastguard Worker   UCHAR numCh[(3)][(4)];
554*e5436536SAndroid Build Coastguard Worker   UCHAR mapped[(8)];
555*e5436536SAndroid Build Coastguard Worker   PCM_DMX_SPEAKER_POSITION spkrPos[(8)];
556*e5436536SAndroid Build Coastguard Worker   PCMDMX_ERROR err = PCMDMX_OK;
557*e5436536SAndroid Build Coastguard Worker   unsigned ch, numMappedInChs = 0;
558*e5436536SAndroid Build Coastguard Worker   unsigned startSlot;
559*e5436536SAndroid Build Coastguard Worker   unsigned stopSlot = LOW_FREQUENCY_CHANNEL;
560*e5436536SAndroid Build Coastguard Worker 
561*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(channelType != NULL);
562*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(channelIndices != NULL);
563*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(offsetTable != NULL);
564*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(chMode != NULL);
565*e5436536SAndroid Build Coastguard Worker 
566*e5436536SAndroid Build Coastguard Worker   /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
567*e5436536SAndroid Build Coastguard Worker   FDKmemclear(numCh, (3) * (4) * sizeof(UCHAR));
568*e5436536SAndroid Build Coastguard Worker   FDKmemclear(mapped, (8) * sizeof(UCHAR));
569*e5436536SAndroid Build Coastguard Worker   FDKmemclear(spkrPos, (8) * sizeof(PCM_DMX_SPEAKER_POSITION));
570*e5436536SAndroid Build Coastguard Worker   /* Init output */
571*e5436536SAndroid Build Coastguard Worker   FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
572*e5436536SAndroid Build Coastguard Worker   *chMode = CH_MODE_UNDEFINED;
573*e5436536SAndroid Build Coastguard Worker 
574*e5436536SAndroid Build Coastguard Worker   /* Determine how many channels are assigned to each channels each group: */
575*e5436536SAndroid Build Coastguard Worker   for (ch = 0; ch < numChannels; ch += 1) {
576*e5436536SAndroid Build Coastguard Worker     unsigned chGrp = fMax(
577*e5436536SAndroid Build Coastguard Worker         (channelType[ch] & 0x0F) - 1,
578*e5436536SAndroid Build Coastguard Worker         0); /* Assign all undefined channels (ACT_NONE) to front channels. */
579*e5436536SAndroid Build Coastguard Worker     numCh[channelType[ch] >> 4][chGrp] += 1;
580*e5436536SAndroid Build Coastguard Worker   }
581*e5436536SAndroid Build Coastguard Worker 
582*e5436536SAndroid Build Coastguard Worker   {
583*e5436536SAndroid Build Coastguard Worker     int chGrp;
584*e5436536SAndroid Build Coastguard Worker     /* Sanity check on the indices */
585*e5436536SAndroid Build Coastguard Worker     for (chGrp = 0; chGrp < (4); chGrp += 1) {
586*e5436536SAndroid Build Coastguard Worker       int plane;
587*e5436536SAndroid Build Coastguard Worker       for (plane = 0; plane < (3); plane += 1) {
588*e5436536SAndroid Build Coastguard Worker         if (numCh[plane][chGrp] == 0) continue;
589*e5436536SAndroid Build Coastguard Worker         AUDIO_CHANNEL_TYPE aChType =
590*e5436536SAndroid Build Coastguard Worker             (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF));
591*e5436536SAndroid Build Coastguard Worker         if (!validateIndices(numChannels, numCh[plane][chGrp], aChType,
592*e5436536SAndroid Build Coastguard Worker                              channelType, channelIndices)) {
593*e5436536SAndroid Build Coastguard Worker           unsigned idxCnt = 0;
594*e5436536SAndroid Build Coastguard Worker           for (ch = 0; ch < numChannels; ch += 1) {
595*e5436536SAndroid Build Coastguard Worker             if (channelType[ch] == aChType) {
596*e5436536SAndroid Build Coastguard Worker               channelIndices[ch] = idxCnt++;
597*e5436536SAndroid Build Coastguard Worker             }
598*e5436536SAndroid Build Coastguard Worker           }
599*e5436536SAndroid Build Coastguard Worker           err = PCMDMX_INVALID_CH_CONFIG;
600*e5436536SAndroid Build Coastguard Worker         }
601*e5436536SAndroid Build Coastguard Worker       }
602*e5436536SAndroid Build Coastguard Worker     }
603*e5436536SAndroid Build Coastguard Worker   }
604*e5436536SAndroid Build Coastguard Worker   /* Mapping HEAT 1:
605*e5436536SAndroid Build Coastguard Worker    *   Determine the speaker position of each input channel and map it to a
606*e5436536SAndroid Build Coastguard Worker    * internal slot if it matches exactly (with zero distance). */
607*e5436536SAndroid Build Coastguard Worker   for (ch = 0; ch < numChannels; ch += 1) {
608*e5436536SAndroid Build Coastguard Worker     UINT mapDist = (unsigned)-1;
609*e5436536SAndroid Build Coastguard Worker     unsigned mapCh, mapPos = (unsigned)-1;
610*e5436536SAndroid Build Coastguard Worker     unsigned chGrp = fMax(
611*e5436536SAndroid Build Coastguard Worker         (channelType[ch] & 0x0F) - 1,
612*e5436536SAndroid Build Coastguard Worker         0); /* Assign all undefined channels (ACT_NONE) to front channels. */
613*e5436536SAndroid Build Coastguard Worker 
614*e5436536SAndroid Build Coastguard Worker     spkrPos[ch] = getSpeakerPos(channelType[ch], channelIndices[ch],
615*e5436536SAndroid Build Coastguard Worker                                 numCh[channelType[ch] >> 4][chGrp]);
616*e5436536SAndroid Build Coastguard Worker 
617*e5436536SAndroid Build Coastguard Worker     for (mapCh = 0; mapCh <= stopSlot; mapCh += 1) {
618*e5436536SAndroid Build Coastguard Worker       if (offsetTable[mapCh] == 255) {
619*e5436536SAndroid Build Coastguard Worker         UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
620*e5436536SAndroid Build Coastguard Worker         if (dist < mapDist) {
621*e5436536SAndroid Build Coastguard Worker           mapPos = mapCh;
622*e5436536SAndroid Build Coastguard Worker           mapDist = dist;
623*e5436536SAndroid Build Coastguard Worker         }
624*e5436536SAndroid Build Coastguard Worker       }
625*e5436536SAndroid Build Coastguard Worker     }
626*e5436536SAndroid Build Coastguard Worker     if (mapDist <= PCMDMX_THRESHOLD_MAP_HEAT_1) {
627*e5436536SAndroid Build Coastguard Worker       offsetTable[mapPos] = (UCHAR)ch;
628*e5436536SAndroid Build Coastguard Worker       mapped[ch] = 1;
629*e5436536SAndroid Build Coastguard Worker       numMappedInChs += 1;
630*e5436536SAndroid Build Coastguard Worker     }
631*e5436536SAndroid Build Coastguard Worker   }
632*e5436536SAndroid Build Coastguard Worker 
633*e5436536SAndroid Build Coastguard Worker   /* Mapping HEAT 2:
634*e5436536SAndroid Build Coastguard Worker    *   Go through the unmapped input channels and assign them to the internal
635*e5436536SAndroid Build Coastguard Worker    * slots that matches best (least distance). But assign center channels to
636*e5436536SAndroid Build Coastguard Worker    * center slots only. */
637*e5436536SAndroid Build Coastguard Worker   startSlot =
638*e5436536SAndroid Build Coastguard Worker       ((numCh[CH_PLAIN_NORMAL][CH_GROUP_FRONT] & 0x1) || (numChannels >= (8)))
639*e5436536SAndroid Build Coastguard Worker           ? 0
640*e5436536SAndroid Build Coastguard Worker           : 1;
641*e5436536SAndroid Build Coastguard Worker   for (ch = 0; ch < (unsigned)numChannels; ch += 1) {
642*e5436536SAndroid Build Coastguard Worker     if (!mapped[ch]) {
643*e5436536SAndroid Build Coastguard Worker       UINT mapDist = (unsigned)-1;
644*e5436536SAndroid Build Coastguard Worker       unsigned mapCh, mapPos = (unsigned)-1;
645*e5436536SAndroid Build Coastguard Worker 
646*e5436536SAndroid Build Coastguard Worker       for (mapCh = startSlot; mapCh <= stopSlot; mapCh += 1) {
647*e5436536SAndroid Build Coastguard Worker         if (offsetTable[mapCh] == 255) {
648*e5436536SAndroid Build Coastguard Worker           UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
649*e5436536SAndroid Build Coastguard Worker           if (dist < mapDist) {
650*e5436536SAndroid Build Coastguard Worker             mapPos = mapCh;
651*e5436536SAndroid Build Coastguard Worker             mapDist = dist;
652*e5436536SAndroid Build Coastguard Worker           }
653*e5436536SAndroid Build Coastguard Worker         }
654*e5436536SAndroid Build Coastguard Worker       }
655*e5436536SAndroid Build Coastguard Worker       if ((mapPos <= stopSlot) && (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_2) &&
656*e5436536SAndroid Build Coastguard Worker           (((spkrPos[ch].x != 0) && (spkrSlotPos[mapPos].x != 0)) /* XOR */
657*e5436536SAndroid Build Coastguard Worker            || ((spkrPos[ch].x == 0) &&
658*e5436536SAndroid Build Coastguard Worker                (spkrSlotPos[mapPos].x ==
659*e5436536SAndroid Build Coastguard Worker                 0)))) { /* Assign center channels to center slots only. */
660*e5436536SAndroid Build Coastguard Worker         offsetTable[mapPos] = (UCHAR)ch;
661*e5436536SAndroid Build Coastguard Worker         mapped[ch] = 1;
662*e5436536SAndroid Build Coastguard Worker         numMappedInChs += 1;
663*e5436536SAndroid Build Coastguard Worker       }
664*e5436536SAndroid Build Coastguard Worker     }
665*e5436536SAndroid Build Coastguard Worker   }
666*e5436536SAndroid Build Coastguard Worker 
667*e5436536SAndroid Build Coastguard Worker   /* Mapping HEAT 3:
668*e5436536SAndroid Build Coastguard Worker    *   Assign the rest by searching for the nearest input channel for each
669*e5436536SAndroid Build Coastguard Worker    * internal slot. */
670*e5436536SAndroid Build Coastguard Worker   for (ch = startSlot; (ch < (8)) && (numMappedInChs < numChannels); ch += 1) {
671*e5436536SAndroid Build Coastguard Worker     if (offsetTable[ch] == 255) {
672*e5436536SAndroid Build Coastguard Worker       UINT mapDist = (unsigned)-1;
673*e5436536SAndroid Build Coastguard Worker       unsigned mapCh, mapPos = (unsigned)-1;
674*e5436536SAndroid Build Coastguard Worker 
675*e5436536SAndroid Build Coastguard Worker       for (mapCh = 0; mapCh < (unsigned)numChannels; mapCh += 1) {
676*e5436536SAndroid Build Coastguard Worker         if (!mapped[mapCh]) {
677*e5436536SAndroid Build Coastguard Worker           UINT dist = getSpeakerDistance(spkrPos[mapCh], spkrSlotPos[ch]);
678*e5436536SAndroid Build Coastguard Worker           if (dist < mapDist) {
679*e5436536SAndroid Build Coastguard Worker             mapPos = mapCh;
680*e5436536SAndroid Build Coastguard Worker             mapDist = dist;
681*e5436536SAndroid Build Coastguard Worker           }
682*e5436536SAndroid Build Coastguard Worker         }
683*e5436536SAndroid Build Coastguard Worker       }
684*e5436536SAndroid Build Coastguard Worker       if (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_3) {
685*e5436536SAndroid Build Coastguard Worker         offsetTable[ch] = (UCHAR)mapPos;
686*e5436536SAndroid Build Coastguard Worker         mapped[mapPos] = 1;
687*e5436536SAndroid Build Coastguard Worker         numMappedInChs += 1;
688*e5436536SAndroid Build Coastguard Worker         if ((spkrPos[mapPos].x == 0) && (spkrSlotPos[ch].x != 0) &&
689*e5436536SAndroid Build Coastguard Worker             (numChannels <
690*e5436536SAndroid Build Coastguard Worker              (8))) { /* Skip the paired slot if we assigned a center channel. */
691*e5436536SAndroid Build Coastguard Worker           ch += 1;
692*e5436536SAndroid Build Coastguard Worker         }
693*e5436536SAndroid Build Coastguard Worker       }
694*e5436536SAndroid Build Coastguard Worker     }
695*e5436536SAndroid Build Coastguard Worker   }
696*e5436536SAndroid Build Coastguard Worker 
697*e5436536SAndroid Build Coastguard Worker   /* Finaly compose the channel mode */
698*e5436536SAndroid Build Coastguard Worker   for (ch = 0; ch < (4); ch += 1) {
699*e5436536SAndroid Build Coastguard Worker     int plane, numChInGrp = 0;
700*e5436536SAndroid Build Coastguard Worker     for (plane = 0; plane < (3); plane += 1) {
701*e5436536SAndroid Build Coastguard Worker       numChInGrp += numCh[plane][ch];
702*e5436536SAndroid Build Coastguard Worker     }
703*e5436536SAndroid Build Coastguard Worker     *chMode = (PCM_DMX_CHANNEL_MODE)(*chMode | (numChInGrp << (ch * 4)));
704*e5436536SAndroid Build Coastguard Worker   }
705*e5436536SAndroid Build Coastguard Worker 
706*e5436536SAndroid Build Coastguard Worker   return err;
707*e5436536SAndroid Build Coastguard Worker }
708*e5436536SAndroid Build Coastguard Worker 
709*e5436536SAndroid Build Coastguard Worker /** Generate a channel offset table and complete channel description for a given
710*e5436536SAndroid Build Coastguard Worker  *(packed) channel mode. This function is the inverse to the getChannelMode()
711*e5436536SAndroid Build Coastguard Worker  *routine but does not support weird channel configurations.
712*e5436536SAndroid Build Coastguard Worker  * @param [in] The packed channel mode of the configuration to be processed.
713*e5436536SAndroid Build Coastguard Worker  * @param [in] Array containing the channel mapping to be used (From MPEG PCE
714*e5436536SAndroid Build Coastguard Worker  *ordering to whatever is required).
715*e5436536SAndroid Build Coastguard Worker  * @param [out] Array where corresponding channel types for each channels are
716*e5436536SAndroid Build Coastguard Worker  *stored into.
717*e5436536SAndroid Build Coastguard Worker  * @param [out] Array where corresponding channel type indices for each output
718*e5436536SAndroid Build Coastguard Worker  *channel are stored into.
719*e5436536SAndroid Build Coastguard Worker  * @param [out] Array where the buffer offsets for each channel are stored into.
720*e5436536SAndroid Build Coastguard Worker  * @returns None.
721*e5436536SAndroid Build Coastguard Worker  **/
getChannelDescription(const PCM_DMX_CHANNEL_MODE chMode,const FDK_channelMapDescr * const mapDescr,AUDIO_CHANNEL_TYPE channelType[],UCHAR channelIndices[],UCHAR offsetTable[(8)])722*e5436536SAndroid Build Coastguard Worker static void getChannelDescription(
723*e5436536SAndroid Build Coastguard Worker     const PCM_DMX_CHANNEL_MODE chMode,         /* in */
724*e5436536SAndroid Build Coastguard Worker     const FDK_channelMapDescr *const mapDescr, /* in */
725*e5436536SAndroid Build Coastguard Worker     AUDIO_CHANNEL_TYPE channelType[],          /* out */
726*e5436536SAndroid Build Coastguard Worker     UCHAR channelIndices[],                    /* out */
727*e5436536SAndroid Build Coastguard Worker     UCHAR offsetTable[(8)]                     /* out */
728*e5436536SAndroid Build Coastguard Worker ) {
729*e5436536SAndroid Build Coastguard Worker   int grpIdx, plainIdx, numPlains = 1, numTotalChannels = 0;
730*e5436536SAndroid Build Coastguard Worker   int chCfg, ch = 0;
731*e5436536SAndroid Build Coastguard Worker 
732*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(channelType != NULL);
733*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(channelIndices != NULL);
734*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(mapDescr != NULL);
735*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(offsetTable != NULL);
736*e5436536SAndroid Build Coastguard Worker 
737*e5436536SAndroid Build Coastguard Worker   /* Init output arrays */
738*e5436536SAndroid Build Coastguard Worker   FDKmemclear(channelType, (8) * sizeof(AUDIO_CHANNEL_TYPE));
739*e5436536SAndroid Build Coastguard Worker   FDKmemclear(channelIndices, (8) * sizeof(UCHAR));
740*e5436536SAndroid Build Coastguard Worker   FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
741*e5436536SAndroid Build Coastguard Worker 
742*e5436536SAndroid Build Coastguard Worker   /* Summerize to get the total number of channels */
743*e5436536SAndroid Build Coastguard Worker   for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
744*e5436536SAndroid Build Coastguard Worker     numTotalChannels += (chMode >> (grpIdx * 4)) & 0xF;
745*e5436536SAndroid Build Coastguard Worker   }
746*e5436536SAndroid Build Coastguard Worker 
747*e5436536SAndroid Build Coastguard Worker   /* Get the appropriate channel map */
748*e5436536SAndroid Build Coastguard Worker   switch (chMode) {
749*e5436536SAndroid Build Coastguard Worker     case CH_MODE_1_0_0_0:
750*e5436536SAndroid Build Coastguard Worker     case CH_MODE_2_0_0_0:
751*e5436536SAndroid Build Coastguard Worker     case CH_MODE_3_0_0_0:
752*e5436536SAndroid Build Coastguard Worker     case CH_MODE_3_0_1_0:
753*e5436536SAndroid Build Coastguard Worker     case CH_MODE_3_0_2_0:
754*e5436536SAndroid Build Coastguard Worker     case CH_MODE_3_0_2_1:
755*e5436536SAndroid Build Coastguard Worker       chCfg = numTotalChannels;
756*e5436536SAndroid Build Coastguard Worker       break;
757*e5436536SAndroid Build Coastguard Worker     case CH_MODE_3_0_3_1:
758*e5436536SAndroid Build Coastguard Worker       chCfg = 11;
759*e5436536SAndroid Build Coastguard Worker       break;
760*e5436536SAndroid Build Coastguard Worker     case CH_MODE_3_0_4_1:
761*e5436536SAndroid Build Coastguard Worker       chCfg = 12;
762*e5436536SAndroid Build Coastguard Worker       break;
763*e5436536SAndroid Build Coastguard Worker     case CH_MODE_5_0_2_1:
764*e5436536SAndroid Build Coastguard Worker       chCfg = 7;
765*e5436536SAndroid Build Coastguard Worker       break;
766*e5436536SAndroid Build Coastguard Worker     default:
767*e5436536SAndroid Build Coastguard Worker       /* fallback */
768*e5436536SAndroid Build Coastguard Worker       chCfg = 0;
769*e5436536SAndroid Build Coastguard Worker       break;
770*e5436536SAndroid Build Coastguard Worker   }
771*e5436536SAndroid Build Coastguard Worker 
772*e5436536SAndroid Build Coastguard Worker   /* Compose channel offset table */
773*e5436536SAndroid Build Coastguard Worker 
774*e5436536SAndroid Build Coastguard Worker   for (plainIdx = 0; plainIdx < numPlains; plainIdx += 1) {
775*e5436536SAndroid Build Coastguard Worker     PCM_DMX_CHANNEL_MODE plainChMode;
776*e5436536SAndroid Build Coastguard Worker     UCHAR numChInGrp[(4)];
777*e5436536SAndroid Build Coastguard Worker 
778*e5436536SAndroid Build Coastguard Worker     plainChMode = getChMode4Plain(plainIdx, chMode, chCfg);
779*e5436536SAndroid Build Coastguard Worker 
780*e5436536SAndroid Build Coastguard Worker     /* Extract the number of channels per group */
781*e5436536SAndroid Build Coastguard Worker     numChInGrp[CH_GROUP_FRONT] = plainChMode & 0xF;
782*e5436536SAndroid Build Coastguard Worker     numChInGrp[CH_GROUP_SIDE] = (plainChMode >> 4) & 0xF;
783*e5436536SAndroid Build Coastguard Worker     numChInGrp[CH_GROUP_REAR] = (plainChMode >> 8) & 0xF;
784*e5436536SAndroid Build Coastguard Worker     numChInGrp[CH_GROUP_LFE] = (plainChMode >> 12) & 0xF;
785*e5436536SAndroid Build Coastguard Worker 
786*e5436536SAndroid Build Coastguard Worker     /* Non-symmetric channels */
787*e5436536SAndroid Build Coastguard Worker     if ((numChInGrp[CH_GROUP_FRONT] & 0x1) && (plainIdx == CH_PLAIN_NORMAL)) {
788*e5436536SAndroid Build Coastguard Worker       /* Odd number of front channels -> we have a center channel.
789*e5436536SAndroid Build Coastguard Worker          In MPEG-4 the center has the index 0. */
790*e5436536SAndroid Build Coastguard Worker       int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
791*e5436536SAndroid Build Coastguard Worker       offsetTable[CENTER_FRONT_CHANNEL] = (UCHAR)mappedIdx;
792*e5436536SAndroid Build Coastguard Worker       channelType[mappedIdx] = ACT_FRONT;
793*e5436536SAndroid Build Coastguard Worker       channelIndices[mappedIdx] = 0;
794*e5436536SAndroid Build Coastguard Worker       ch += 1;
795*e5436536SAndroid Build Coastguard Worker     }
796*e5436536SAndroid Build Coastguard Worker 
797*e5436536SAndroid Build Coastguard Worker     for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
798*e5436536SAndroid Build Coastguard Worker       AUDIO_CHANNEL_TYPE type = ACT_NONE;
799*e5436536SAndroid Build Coastguard Worker       int chMapPos = 0, maxChannels = 0;
800*e5436536SAndroid Build Coastguard Worker       int chIdx = 0; /* Index of channel within the specific group */
801*e5436536SAndroid Build Coastguard Worker 
802*e5436536SAndroid Build Coastguard Worker       switch (grpIdx) {
803*e5436536SAndroid Build Coastguard Worker         case CH_GROUP_FRONT:
804*e5436536SAndroid Build Coastguard Worker           type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_FRONT);
805*e5436536SAndroid Build Coastguard Worker           switch (plainIdx) {
806*e5436536SAndroid Build Coastguard Worker             default:
807*e5436536SAndroid Build Coastguard Worker               chMapPos = LEFT_FRONT_CHANNEL;
808*e5436536SAndroid Build Coastguard Worker               chIdx = numChInGrp[grpIdx] & 0x1;
809*e5436536SAndroid Build Coastguard Worker               break;
810*e5436536SAndroid Build Coastguard Worker           }
811*e5436536SAndroid Build Coastguard Worker           maxChannels = 3;
812*e5436536SAndroid Build Coastguard Worker           break;
813*e5436536SAndroid Build Coastguard Worker         case CH_GROUP_SIDE:
814*e5436536SAndroid Build Coastguard Worker           /* Always map side channels to the multipurpose group. */
815*e5436536SAndroid Build Coastguard Worker           type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_SIDE);
816*e5436536SAndroid Build Coastguard Worker           if (plainIdx == CH_PLAIN_TOP) {
817*e5436536SAndroid Build Coastguard Worker             chMapPos = LEFT_SIDE_CHANNEL_TOP;
818*e5436536SAndroid Build Coastguard Worker             maxChannels = 3;
819*e5436536SAndroid Build Coastguard Worker           } else {
820*e5436536SAndroid Build Coastguard Worker             chMapPos = LEFT_MULTIPRPS_CHANNEL;
821*e5436536SAndroid Build Coastguard Worker             maxChannels = 2;
822*e5436536SAndroid Build Coastguard Worker           }
823*e5436536SAndroid Build Coastguard Worker           break;
824*e5436536SAndroid Build Coastguard Worker         case CH_GROUP_REAR:
825*e5436536SAndroid Build Coastguard Worker           type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_BACK);
826*e5436536SAndroid Build Coastguard Worker           if (plainIdx == CH_PLAIN_TOP) {
827*e5436536SAndroid Build Coastguard Worker             chMapPos = LEFT_REAR_CHANNEL_TOP;
828*e5436536SAndroid Build Coastguard Worker             maxChannels = 3;
829*e5436536SAndroid Build Coastguard Worker           } else {
830*e5436536SAndroid Build Coastguard Worker             chMapPos = LEFT_REAR_CHANNEL;
831*e5436536SAndroid Build Coastguard Worker             maxChannels = 2;
832*e5436536SAndroid Build Coastguard Worker           }
833*e5436536SAndroid Build Coastguard Worker           break;
834*e5436536SAndroid Build Coastguard Worker         case CH_GROUP_LFE:
835*e5436536SAndroid Build Coastguard Worker           if (plainIdx == CH_PLAIN_NORMAL) {
836*e5436536SAndroid Build Coastguard Worker             type = ACT_LFE;
837*e5436536SAndroid Build Coastguard Worker             chMapPos = LOW_FREQUENCY_CHANNEL;
838*e5436536SAndroid Build Coastguard Worker             maxChannels = 1;
839*e5436536SAndroid Build Coastguard Worker           }
840*e5436536SAndroid Build Coastguard Worker           break;
841*e5436536SAndroid Build Coastguard Worker         default:
842*e5436536SAndroid Build Coastguard Worker           break;
843*e5436536SAndroid Build Coastguard Worker       }
844*e5436536SAndroid Build Coastguard Worker 
845*e5436536SAndroid Build Coastguard Worker       /* Map all channels in this group */
846*e5436536SAndroid Build Coastguard Worker       for (; chIdx < numChInGrp[grpIdx]; chIdx += 1) {
847*e5436536SAndroid Build Coastguard Worker         int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
848*e5436536SAndroid Build Coastguard Worker         if ((chIdx == maxChannels) || (offsetTable[chMapPos] < 255)) {
849*e5436536SAndroid Build Coastguard Worker           /* No space left in this channel group! */
850*e5436536SAndroid Build Coastguard Worker           if (offsetTable[LEFT_MULTIPRPS_CHANNEL] ==
851*e5436536SAndroid Build Coastguard Worker               255) { /* Use the multipurpose group: */
852*e5436536SAndroid Build Coastguard Worker             chMapPos = LEFT_MULTIPRPS_CHANNEL;
853*e5436536SAndroid Build Coastguard Worker           } else {
854*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(0);
855*e5436536SAndroid Build Coastguard Worker           }
856*e5436536SAndroid Build Coastguard Worker         }
857*e5436536SAndroid Build Coastguard Worker         offsetTable[chMapPos] = (UCHAR)mappedIdx;
858*e5436536SAndroid Build Coastguard Worker         channelType[mappedIdx] = type;
859*e5436536SAndroid Build Coastguard Worker         channelIndices[mappedIdx] = (UCHAR)chIdx;
860*e5436536SAndroid Build Coastguard Worker         chMapPos += 1;
861*e5436536SAndroid Build Coastguard Worker         ch += 1;
862*e5436536SAndroid Build Coastguard Worker       }
863*e5436536SAndroid Build Coastguard Worker     }
864*e5436536SAndroid Build Coastguard Worker   }
865*e5436536SAndroid Build Coastguard Worker }
866*e5436536SAndroid Build Coastguard Worker 
867*e5436536SAndroid Build Coastguard Worker /** Private helper function for downmix matrix manipulation that initializes
868*e5436536SAndroid Build Coastguard Worker  *  one row in a given downmix matrix (corresponding to one output channel).
869*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to fixed-point parts of the downmix matrix.
870*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to scale factor matrix associated to the downmix
871*e5436536SAndroid Build Coastguard Worker  *factors.
872*e5436536SAndroid Build Coastguard Worker  * @param [in]    Index of channel (row) to be initialized.
873*e5436536SAndroid Build Coastguard Worker  * @returns       Nothing to return.
874*e5436536SAndroid Build Coastguard Worker  **/
dmxInitChannel(FIXP_DMX mixFactors[(8)][(8)],INT mixScales[(8)][(8)],const unsigned int outCh)875*e5436536SAndroid Build Coastguard Worker static void dmxInitChannel(FIXP_DMX mixFactors[(8)][(8)],
876*e5436536SAndroid Build Coastguard Worker                            INT mixScales[(8)][(8)], const unsigned int outCh) {
877*e5436536SAndroid Build Coastguard Worker   unsigned int inCh;
878*e5436536SAndroid Build Coastguard Worker   for (inCh = 0; inCh < (8); inCh += 1) {
879*e5436536SAndroid Build Coastguard Worker     if (inCh == outCh) {
880*e5436536SAndroid Build Coastguard Worker       mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.5f);
881*e5436536SAndroid Build Coastguard Worker       mixScales[outCh][inCh] = 1;
882*e5436536SAndroid Build Coastguard Worker     } else {
883*e5436536SAndroid Build Coastguard Worker       mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.0f);
884*e5436536SAndroid Build Coastguard Worker       mixScales[outCh][inCh] = 0;
885*e5436536SAndroid Build Coastguard Worker     }
886*e5436536SAndroid Build Coastguard Worker   }
887*e5436536SAndroid Build Coastguard Worker }
888*e5436536SAndroid Build Coastguard Worker 
889*e5436536SAndroid Build Coastguard Worker /** Private helper function for downmix matrix manipulation that does a reset
890*e5436536SAndroid Build Coastguard Worker  *  of one row in a given downmix matrix (corresponding to one output channel).
891*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to fixed-point parts of the downmix matrix.
892*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to scale factor matrix associated to the downmix
893*e5436536SAndroid Build Coastguard Worker  *factors.
894*e5436536SAndroid Build Coastguard Worker  * @param [in]    Index of channel (row) to be cleared/reset.
895*e5436536SAndroid Build Coastguard Worker  * @returns       Nothing to return.
896*e5436536SAndroid Build Coastguard Worker  **/
dmxClearChannel(FIXP_DMX mixFactors[(8)][(8)],INT mixScales[(8)][(8)],const unsigned int outCh)897*e5436536SAndroid Build Coastguard Worker static void dmxClearChannel(FIXP_DMX mixFactors[(8)][(8)],
898*e5436536SAndroid Build Coastguard Worker                             INT mixScales[(8)][(8)], const unsigned int outCh) {
899*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT((outCh >= 0) && (outCh < (8)));
900*e5436536SAndroid Build Coastguard Worker   FDKmemclear(&mixFactors[outCh], (8) * sizeof(FIXP_DMX));
901*e5436536SAndroid Build Coastguard Worker   FDKmemclear(&mixScales[outCh], (8) * sizeof(INT));
902*e5436536SAndroid Build Coastguard Worker }
903*e5436536SAndroid Build Coastguard Worker 
904*e5436536SAndroid Build Coastguard Worker /** Private helper function for downmix matrix manipulation that applies a
905*e5436536SAndroid Build Coastguard Worker  *source channel (row) scaled by a given mix factor to a destination channel
906*e5436536SAndroid Build Coastguard Worker  *(row) in a given downmix matrix. Existing mix factors of the destination
907*e5436536SAndroid Build Coastguard Worker  *channel (row) will get overwritten.
908*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to fixed-point parts of the downmix matrix.
909*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to scale factor matrix associated to the downmix
910*e5436536SAndroid Build Coastguard Worker  *factors.
911*e5436536SAndroid Build Coastguard Worker  * @param [in]    Index of source channel (row).
912*e5436536SAndroid Build Coastguard Worker  * @param [in]    Index of destination channel (row).
913*e5436536SAndroid Build Coastguard Worker  * @param [in]    Fixed-point part of mix factor to be applied.
914*e5436536SAndroid Build Coastguard Worker  * @param [in]    Scale factor of mix factor to be applied.
915*e5436536SAndroid Build Coastguard Worker  * @returns       Nothing to return.
916*e5436536SAndroid Build Coastguard Worker  **/
dmxSetChannel(FIXP_DMX mixFactors[(8)][(8)],INT mixScales[(8)][(8)],const unsigned int dstCh,const unsigned int srcCh,const FIXP_DMX factor,const INT scale)917*e5436536SAndroid Build Coastguard Worker static void dmxSetChannel(FIXP_DMX mixFactors[(8)][(8)],
918*e5436536SAndroid Build Coastguard Worker                           INT mixScales[(8)][(8)], const unsigned int dstCh,
919*e5436536SAndroid Build Coastguard Worker                           const unsigned int srcCh, const FIXP_DMX factor,
920*e5436536SAndroid Build Coastguard Worker                           const INT scale) {
921*e5436536SAndroid Build Coastguard Worker   int ch;
922*e5436536SAndroid Build Coastguard Worker   for (ch = 0; ch < (8); ch += 1) {
923*e5436536SAndroid Build Coastguard Worker     if (mixFactors[srcCh][ch] != (FIXP_DMX)0) {
924*e5436536SAndroid Build Coastguard Worker       mixFactors[dstCh][ch] =
925*e5436536SAndroid Build Coastguard Worker           FX_DBL2FX_DMX(fMult(mixFactors[srcCh][ch], factor));
926*e5436536SAndroid Build Coastguard Worker       mixScales[dstCh][ch] = mixScales[srcCh][ch] + scale;
927*e5436536SAndroid Build Coastguard Worker     }
928*e5436536SAndroid Build Coastguard Worker   }
929*e5436536SAndroid Build Coastguard Worker }
930*e5436536SAndroid Build Coastguard Worker 
931*e5436536SAndroid Build Coastguard Worker /** Private helper function for downmix matrix manipulation that adds a source
932*e5436536SAndroid Build Coastguard Worker  *channel (row) scaled by a given mix factor to a destination channel (row) in a
933*e5436536SAndroid Build Coastguard Worker  *given downmix matrix.
934*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to fixed-point parts of the downmix matrix.
935*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to scale factor matrix associated to the downmix
936*e5436536SAndroid Build Coastguard Worker  *factors.
937*e5436536SAndroid Build Coastguard Worker  * @param [in]    Index of source channel (row).
938*e5436536SAndroid Build Coastguard Worker  * @param [in]    Index of destination channel (row).
939*e5436536SAndroid Build Coastguard Worker  * @param [in]    Fixed-point part of mix factor to be applied.
940*e5436536SAndroid Build Coastguard Worker  * @param [in]    Scale factor of mix factor to be applied.
941*e5436536SAndroid Build Coastguard Worker  * @returns       Nothing to return.
942*e5436536SAndroid Build Coastguard Worker  **/
dmxAddChannel(FIXP_DMX mixFactors[(8)][(8)],INT mixScales[(8)][(8)],const unsigned int dstCh,const unsigned int srcCh,const FIXP_DMX factor,const INT scale)943*e5436536SAndroid Build Coastguard Worker static void dmxAddChannel(FIXP_DMX mixFactors[(8)][(8)],
944*e5436536SAndroid Build Coastguard Worker                           INT mixScales[(8)][(8)], const unsigned int dstCh,
945*e5436536SAndroid Build Coastguard Worker                           const unsigned int srcCh, const FIXP_DMX factor,
946*e5436536SAndroid Build Coastguard Worker                           const INT scale) {
947*e5436536SAndroid Build Coastguard Worker   int ch;
948*e5436536SAndroid Build Coastguard Worker   for (ch = 0; ch < (8); ch += 1) {
949*e5436536SAndroid Build Coastguard Worker     FIXP_DBL addFact = fMult(mixFactors[srcCh][ch], factor);
950*e5436536SAndroid Build Coastguard Worker     if (addFact != (FIXP_DMX)0) {
951*e5436536SAndroid Build Coastguard Worker       INT newScale = mixScales[srcCh][ch] + scale;
952*e5436536SAndroid Build Coastguard Worker       if (mixFactors[dstCh][ch] != (FIXP_DMX)0) {
953*e5436536SAndroid Build Coastguard Worker         if (newScale > mixScales[dstCh][ch]) {
954*e5436536SAndroid Build Coastguard Worker           mixFactors[dstCh][ch] >>= newScale - mixScales[dstCh][ch];
955*e5436536SAndroid Build Coastguard Worker         } else {
956*e5436536SAndroid Build Coastguard Worker           addFact >>= mixScales[dstCh][ch] - newScale;
957*e5436536SAndroid Build Coastguard Worker           newScale = mixScales[dstCh][ch];
958*e5436536SAndroid Build Coastguard Worker         }
959*e5436536SAndroid Build Coastguard Worker       }
960*e5436536SAndroid Build Coastguard Worker       mixFactors[dstCh][ch] += FX_DBL2FX_DMX(addFact);
961*e5436536SAndroid Build Coastguard Worker       mixScales[dstCh][ch] = newScale;
962*e5436536SAndroid Build Coastguard Worker     }
963*e5436536SAndroid Build Coastguard Worker   }
964*e5436536SAndroid Build Coastguard Worker }
965*e5436536SAndroid Build Coastguard Worker 
966*e5436536SAndroid Build Coastguard Worker /** Private function that creates a downmix factor matrix depending on the input
967*e5436536SAndroid Build Coastguard Worker  and output
968*e5436536SAndroid Build Coastguard Worker  *  configuration, the user parameters as well as the given metadata. This
969*e5436536SAndroid Build Coastguard Worker  function is the modules
970*e5436536SAndroid Build Coastguard Worker  *  brain and hold all downmix algorithms.
971*e5436536SAndroid Build Coastguard Worker  * @param [in]  Flag that indicates if inChMode holds a real (packed) channel
972*e5436536SAndroid Build Coastguard Worker  mode or has been converted to a MPEG-4 channel configuration index.
973*e5436536SAndroid Build Coastguard Worker  * @param [in]  Dependent on the inModeIsCfg flag this field hands in a (packed)
974*e5436536SAndroid Build Coastguard Worker  channel mode or the corresponding MPEG-4 channel configuration index.of the
975*e5436536SAndroid Build Coastguard Worker  input configuration.
976*e5436536SAndroid Build Coastguard Worker  * @param [in]  The (packed) channel mode of the output configuration.
977*e5436536SAndroid Build Coastguard Worker  * @param [in]  Pointer to structure holding all current user parameter.
978*e5436536SAndroid Build Coastguard Worker  * @param [in]  Pointer to field holding all current meta data.
979*e5436536SAndroid Build Coastguard Worker  * @param [out] Pointer to fixed-point parts of the downmix matrix. Normalized
980*e5436536SAndroid Build Coastguard Worker  to one scale factor.
981*e5436536SAndroid Build Coastguard Worker  * @param [out] The common scale factor of the downmix matrix.
982*e5436536SAndroid Build Coastguard Worker  * @returns     An error code.
983*e5436536SAndroid Build Coastguard Worker  **/
getMixFactors(const UCHAR inModeIsCfg,PCM_DMX_CHANNEL_MODE inChMode,const PCM_DMX_CHANNEL_MODE outChMode,const PCM_DMX_USER_PARAMS * pParams,const DMX_BS_META_DATA * pMetaData,FIXP_DMX mixFactors[(8)][(8)],INT * pOutScale)984*e5436536SAndroid Build Coastguard Worker static PCMDMX_ERROR getMixFactors(const UCHAR inModeIsCfg,
985*e5436536SAndroid Build Coastguard Worker                                   PCM_DMX_CHANNEL_MODE inChMode,
986*e5436536SAndroid Build Coastguard Worker                                   const PCM_DMX_CHANNEL_MODE outChMode,
987*e5436536SAndroid Build Coastguard Worker                                   const PCM_DMX_USER_PARAMS *pParams,
988*e5436536SAndroid Build Coastguard Worker                                   const DMX_BS_META_DATA *pMetaData,
989*e5436536SAndroid Build Coastguard Worker                                   FIXP_DMX mixFactors[(8)][(8)],
990*e5436536SAndroid Build Coastguard Worker                                   INT *pOutScale) {
991*e5436536SAndroid Build Coastguard Worker   PCMDMX_ERROR err = PCMDMX_OK;
992*e5436536SAndroid Build Coastguard Worker   INT mixScales[(8)][(8)];
993*e5436536SAndroid Build Coastguard Worker   INT maxScale = 0;
994*e5436536SAndroid Build Coastguard Worker   int numInChannel;
995*e5436536SAndroid Build Coastguard Worker   int numOutChannel;
996*e5436536SAndroid Build Coastguard Worker   int dmxMethod;
997*e5436536SAndroid Build Coastguard Worker   unsigned int outCh, inChCfg = 0;
998*e5436536SAndroid Build Coastguard Worker   unsigned int valid[(8)] = {0};
999*e5436536SAndroid Build Coastguard Worker 
1000*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(pMetaData != NULL);
1001*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(mixFactors != NULL);
1002*e5436536SAndroid Build Coastguard Worker   /* Check on a supported output configuration.
1003*e5436536SAndroid Build Coastguard Worker      Add new one only after extensive testing! */
1004*e5436536SAndroid Build Coastguard Worker   if (!((outChMode == CH_MODE_1_0_0_0) || (outChMode == CH_MODE_2_0_0_0) ||
1005*e5436536SAndroid Build Coastguard Worker         (outChMode == CH_MODE_3_0_2_1) || (outChMode == CH_MODE_3_0_4_1) ||
1006*e5436536SAndroid Build Coastguard Worker         (outChMode == CH_MODE_5_0_2_1))) {
1007*e5436536SAndroid Build Coastguard Worker     FDK_ASSERT(0);
1008*e5436536SAndroid Build Coastguard Worker   }
1009*e5436536SAndroid Build Coastguard Worker 
1010*e5436536SAndroid Build Coastguard Worker   if (inModeIsCfg) {
1011*e5436536SAndroid Build Coastguard Worker     /* Convert channel config to channel mode: */
1012*e5436536SAndroid Build Coastguard Worker     inChCfg = (unsigned int)inChMode;
1013*e5436536SAndroid Build Coastguard Worker     switch (inChCfg) {
1014*e5436536SAndroid Build Coastguard Worker       case 1:
1015*e5436536SAndroid Build Coastguard Worker       case 2:
1016*e5436536SAndroid Build Coastguard Worker       case 3:
1017*e5436536SAndroid Build Coastguard Worker       case 4:
1018*e5436536SAndroid Build Coastguard Worker       case 5:
1019*e5436536SAndroid Build Coastguard Worker       case 6:
1020*e5436536SAndroid Build Coastguard Worker         inChMode = outChModeTable[inChCfg];
1021*e5436536SAndroid Build Coastguard Worker         break;
1022*e5436536SAndroid Build Coastguard Worker       case 11:
1023*e5436536SAndroid Build Coastguard Worker         inChMode = CH_MODE_3_0_3_1;
1024*e5436536SAndroid Build Coastguard Worker         break;
1025*e5436536SAndroid Build Coastguard Worker       case 12:
1026*e5436536SAndroid Build Coastguard Worker         inChMode = CH_MODE_3_0_4_1;
1027*e5436536SAndroid Build Coastguard Worker         break;
1028*e5436536SAndroid Build Coastguard Worker       case 7:
1029*e5436536SAndroid Build Coastguard Worker       case 14:
1030*e5436536SAndroid Build Coastguard Worker         inChMode = CH_MODE_5_0_2_1;
1031*e5436536SAndroid Build Coastguard Worker         break;
1032*e5436536SAndroid Build Coastguard Worker       default:
1033*e5436536SAndroid Build Coastguard Worker         FDK_ASSERT(0);
1034*e5436536SAndroid Build Coastguard Worker     }
1035*e5436536SAndroid Build Coastguard Worker   }
1036*e5436536SAndroid Build Coastguard Worker 
1037*e5436536SAndroid Build Coastguard Worker   /* Extract the total number of input channels */
1038*e5436536SAndroid Build Coastguard Worker   numInChannel = (inChMode & 0xF) + ((inChMode >> 4) & 0xF) +
1039*e5436536SAndroid Build Coastguard Worker                  ((inChMode >> 8) & 0xF) + ((inChMode >> 12) & 0xF);
1040*e5436536SAndroid Build Coastguard Worker   /* Extract the total number of output channels */
1041*e5436536SAndroid Build Coastguard Worker   numOutChannel = (outChMode & 0xF) + ((outChMode >> 4) & 0xF) +
1042*e5436536SAndroid Build Coastguard Worker                   ((outChMode >> 8) & 0xF) + ((outChMode >> 12) & 0xF);
1043*e5436536SAndroid Build Coastguard Worker 
1044*e5436536SAndroid Build Coastguard Worker   /* MPEG ammendment 4 aka ETSI metadata and fallback mode: */
1045*e5436536SAndroid Build Coastguard Worker 
1046*e5436536SAndroid Build Coastguard Worker   /* Create identity DMX matrix: */
1047*e5436536SAndroid Build Coastguard Worker   for (outCh = 0; outCh < (8); outCh += 1) {
1048*e5436536SAndroid Build Coastguard Worker     dmxInitChannel(mixFactors, mixScales, outCh);
1049*e5436536SAndroid Build Coastguard Worker   }
1050*e5436536SAndroid Build Coastguard Worker   if (((inChMode >> 12) & 0xF) == 0) {
1051*e5436536SAndroid Build Coastguard Worker     /* Clear empty or wrongly mapped input channel */
1052*e5436536SAndroid Build Coastguard Worker     dmxClearChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL);
1053*e5436536SAndroid Build Coastguard Worker   }
1054*e5436536SAndroid Build Coastguard Worker 
1055*e5436536SAndroid Build Coastguard Worker   /* FIRST STAGE: */
1056*e5436536SAndroid Build Coastguard Worker   if (numInChannel > SIX_CHANNEL) { /* Always use MPEG equations either with
1057*e5436536SAndroid Build Coastguard Worker                                        meta data or with default values. */
1058*e5436536SAndroid Build Coastguard Worker     FIXP_DMX dMixFactA, dMixFactB;
1059*e5436536SAndroid Build Coastguard Worker     INT dMixScaleA, dMixScaleB;
1060*e5436536SAndroid Build Coastguard Worker     int isValidCfg = TRUE;
1061*e5436536SAndroid Build Coastguard Worker 
1062*e5436536SAndroid Build Coastguard Worker     /* Get factors from meta data */
1063*e5436536SAndroid Build Coastguard Worker     dMixFactA = abMixLvlValueTab[pMetaData->dmixIdxA];
1064*e5436536SAndroid Build Coastguard Worker     dMixScaleA = (pMetaData->dmixIdxA == 0) ? 1 : 0;
1065*e5436536SAndroid Build Coastguard Worker     dMixFactB = abMixLvlValueTab[pMetaData->dmixIdxB];
1066*e5436536SAndroid Build Coastguard Worker     dMixScaleB = (pMetaData->dmixIdxB == 0) ? 1 : 0;
1067*e5436536SAndroid Build Coastguard Worker 
1068*e5436536SAndroid Build Coastguard Worker     /* Check if input is in the list of supported configurations */
1069*e5436536SAndroid Build Coastguard Worker     switch (inChMode) {
1070*e5436536SAndroid Build Coastguard Worker       case CH_MODE_3_2_1_1: /* chCfg 11 but with side channels */
1071*e5436536SAndroid Build Coastguard Worker       case CH_MODE_3_2_1_0:
1072*e5436536SAndroid Build Coastguard Worker         isValidCfg = FALSE;
1073*e5436536SAndroid Build Coastguard Worker         err = PCMDMX_INVALID_MODE;
1074*e5436536SAndroid Build Coastguard Worker         FDK_FALLTHROUGH;
1075*e5436536SAndroid Build Coastguard Worker       case CH_MODE_3_0_3_1: /* chCfg 11 */
1076*e5436536SAndroid Build Coastguard Worker         /* 6.1ch:  C' = C;  L' = L;  R' = R;  LFE' = LFE;
1077*e5436536SAndroid Build Coastguard Worker                    Ls' = Ls*dmix_a_idx + Cs*dmix_b_idx;
1078*e5436536SAndroid Build Coastguard Worker                    Rs' = Rs*dmix_a_idx + Cs*dmix_b_idx; */
1079*e5436536SAndroid Build Coastguard Worker         dmxClearChannel(
1080*e5436536SAndroid Build Coastguard Worker             mixFactors, mixScales,
1081*e5436536SAndroid Build Coastguard Worker             RIGHT_MULTIPRPS_CHANNEL); /* clear empty input channel */
1082*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1083*e5436536SAndroid Build Coastguard Worker                       LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1084*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1085*e5436536SAndroid Build Coastguard Worker                       LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1086*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1087*e5436536SAndroid Build Coastguard Worker                       RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1088*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1089*e5436536SAndroid Build Coastguard Worker                       LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1090*e5436536SAndroid Build Coastguard Worker         break;
1091*e5436536SAndroid Build Coastguard Worker       case CH_MODE_3_0_4_1: /* chCfg 12 */
1092*e5436536SAndroid Build Coastguard Worker         /* 7.1ch Surround Back:  C' = C;  L' = L;  R' = R;  LFE' = LFE;
1093*e5436536SAndroid Build Coastguard Worker                                  Ls' = Ls*dmix_a_idx + Lsr*dmix_b_idx;
1094*e5436536SAndroid Build Coastguard Worker                                  Rs' = Rs*dmix_a_idx + Rsr*dmix_b_idx; */
1095*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1096*e5436536SAndroid Build Coastguard Worker                       LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1097*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1098*e5436536SAndroid Build Coastguard Worker                       LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1099*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1100*e5436536SAndroid Build Coastguard Worker                       RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1101*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1102*e5436536SAndroid Build Coastguard Worker                       RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1103*e5436536SAndroid Build Coastguard Worker         break;
1104*e5436536SAndroid Build Coastguard Worker       case CH_MODE_5_0_1_0:
1105*e5436536SAndroid Build Coastguard Worker       case CH_MODE_5_0_1_1:
1106*e5436536SAndroid Build Coastguard Worker         dmxClearChannel(mixFactors, mixScales,
1107*e5436536SAndroid Build Coastguard Worker                         RIGHT_REAR_CHANNEL); /* clear empty input channel */
1108*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1109*e5436536SAndroid Build Coastguard Worker                       LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1110*e5436536SAndroid Build Coastguard Worker         dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1111*e5436536SAndroid Build Coastguard Worker                       LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1112*e5436536SAndroid Build Coastguard Worker         FDK_FALLTHROUGH;
1113*e5436536SAndroid Build Coastguard Worker       case CH_MODE_5_2_1_0:
1114*e5436536SAndroid Build Coastguard Worker         isValidCfg = FALSE;
1115*e5436536SAndroid Build Coastguard Worker         err = PCMDMX_INVALID_MODE;
1116*e5436536SAndroid Build Coastguard Worker         FDK_FALLTHROUGH;
1117*e5436536SAndroid Build Coastguard Worker       case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
1118*e5436536SAndroid Build Coastguard Worker         if (inChCfg == 14) {
1119*e5436536SAndroid Build Coastguard Worker           /* 7.1ch Front Height:  C' = C;  Ls' = Ls;  Rs' = Rs;  LFE' = LFE;
1120*e5436536SAndroid Build Coastguard Worker                                   L' = L*dmix_a_idx + Lv*dmix_b_idx;
1121*e5436536SAndroid Build Coastguard Worker                                   R' = R*dmix_a_idx + Rv*dmix_b_idx; */
1122*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1123*e5436536SAndroid Build Coastguard Worker                         LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1124*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1125*e5436536SAndroid Build Coastguard Worker                         LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1126*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1127*e5436536SAndroid Build Coastguard Worker                         RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1128*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1129*e5436536SAndroid Build Coastguard Worker                         RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1130*e5436536SAndroid Build Coastguard Worker         } else {
1131*e5436536SAndroid Build Coastguard Worker           /* 7.1ch Front:  Ls' = Ls;  Rs' = Rs;  LFE' = LFE;
1132*e5436536SAndroid Build Coastguard Worker                            C' = C + (Lc+Rc)*dmix_a_idx;
1133*e5436536SAndroid Build Coastguard Worker                            L' = L + Lc*dmix_b_idx;
1134*e5436536SAndroid Build Coastguard Worker                            R' = R + Rc*dmix_b_idx; */
1135*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1136*e5436536SAndroid Build Coastguard Worker                         LEFT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1137*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1138*e5436536SAndroid Build Coastguard Worker                         RIGHT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1139*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1140*e5436536SAndroid Build Coastguard Worker                         LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1141*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1142*e5436536SAndroid Build Coastguard Worker                         LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1143*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1144*e5436536SAndroid Build Coastguard Worker                         RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1145*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1146*e5436536SAndroid Build Coastguard Worker                         RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1147*e5436536SAndroid Build Coastguard Worker         }
1148*e5436536SAndroid Build Coastguard Worker         break;
1149*e5436536SAndroid Build Coastguard Worker       default:
1150*e5436536SAndroid Build Coastguard Worker         /* Nothing to do. Just use the identity matrix. */
1151*e5436536SAndroid Build Coastguard Worker         isValidCfg = FALSE;
1152*e5436536SAndroid Build Coastguard Worker         err = PCMDMX_INVALID_MODE;
1153*e5436536SAndroid Build Coastguard Worker         break;
1154*e5436536SAndroid Build Coastguard Worker     }
1155*e5436536SAndroid Build Coastguard Worker 
1156*e5436536SAndroid Build Coastguard Worker     /* Add additional DMX gain */
1157*e5436536SAndroid Build Coastguard Worker     if ((isValidCfg == TRUE) &&
1158*e5436536SAndroid Build Coastguard Worker         (pMetaData->dmxGainIdx5 != 0)) { /* Apply DMX gain 5 */
1159*e5436536SAndroid Build Coastguard Worker       FIXP_DMX dmxGain;
1160*e5436536SAndroid Build Coastguard Worker       INT dmxScale;
1161*e5436536SAndroid Build Coastguard Worker       INT sign = (pMetaData->dmxGainIdx5 & 0x40) ? -1 : 1;
1162*e5436536SAndroid Build Coastguard Worker       INT val = pMetaData->dmxGainIdx5 & 0x3F;
1163*e5436536SAndroid Build Coastguard Worker 
1164*e5436536SAndroid Build Coastguard Worker       /* 10^(dmx_gain_5/80) */
1165*e5436536SAndroid Build Coastguard Worker       dmxGain = FX_DBL2FX_DMX(
1166*e5436536SAndroid Build Coastguard Worker           fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
1167*e5436536SAndroid Build Coastguard Worker                  (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)), 0,
1168*e5436536SAndroid Build Coastguard Worker                  &dmxScale));
1169*e5436536SAndroid Build Coastguard Worker       /* Currently only positive scale factors supported! */
1170*e5436536SAndroid Build Coastguard Worker       if (dmxScale < 0) {
1171*e5436536SAndroid Build Coastguard Worker         dmxGain >>= -dmxScale;
1172*e5436536SAndroid Build Coastguard Worker         dmxScale = 0;
1173*e5436536SAndroid Build Coastguard Worker       }
1174*e5436536SAndroid Build Coastguard Worker 
1175*e5436536SAndroid Build Coastguard Worker       dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1176*e5436536SAndroid Build Coastguard Worker                     CENTER_FRONT_CHANNEL, dmxGain, dmxScale);
1177*e5436536SAndroid Build Coastguard Worker       dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1178*e5436536SAndroid Build Coastguard Worker                     LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
1179*e5436536SAndroid Build Coastguard Worker       dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1180*e5436536SAndroid Build Coastguard Worker                     RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
1181*e5436536SAndroid Build Coastguard Worker       dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL,
1182*e5436536SAndroid Build Coastguard Worker                     dmxGain, dmxScale);
1183*e5436536SAndroid Build Coastguard Worker       dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1184*e5436536SAndroid Build Coastguard Worker                     RIGHT_REAR_CHANNEL, dmxGain, dmxScale);
1185*e5436536SAndroid Build Coastguard Worker       dmxSetChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL,
1186*e5436536SAndroid Build Coastguard Worker                     LOW_FREQUENCY_CHANNEL, dmxGain, dmxScale);
1187*e5436536SAndroid Build Coastguard Worker     }
1188*e5436536SAndroid Build Coastguard Worker 
1189*e5436536SAndroid Build Coastguard Worker     /* Mark the output channels */
1190*e5436536SAndroid Build Coastguard Worker     valid[CENTER_FRONT_CHANNEL] = 1;
1191*e5436536SAndroid Build Coastguard Worker     valid[LEFT_FRONT_CHANNEL] = 1;
1192*e5436536SAndroid Build Coastguard Worker     valid[RIGHT_FRONT_CHANNEL] = 1;
1193*e5436536SAndroid Build Coastguard Worker     valid[LEFT_REAR_CHANNEL] = 1;
1194*e5436536SAndroid Build Coastguard Worker     valid[RIGHT_REAR_CHANNEL] = 1;
1195*e5436536SAndroid Build Coastguard Worker     valid[LOW_FREQUENCY_CHANNEL] = 1;
1196*e5436536SAndroid Build Coastguard Worker 
1197*e5436536SAndroid Build Coastguard Worker     /* Update channel mode for the next stage */
1198*e5436536SAndroid Build Coastguard Worker     inChMode = CH_MODE_3_0_2_1;
1199*e5436536SAndroid Build Coastguard Worker   }
1200*e5436536SAndroid Build Coastguard Worker 
1201*e5436536SAndroid Build Coastguard Worker     /* For the X (> 6) to 6 channel downmix we had no choice.
1202*e5436536SAndroid Build Coastguard Worker        To mix from 6 to 2 (or 1) channel(s) we have several possibilities (MPEG
1203*e5436536SAndroid Build Coastguard Worker        DSE | MPEG PCE | ITU | ARIB | DLB). Use profile and the metadata
1204*e5436536SAndroid Build Coastguard Worker        available flags to determine which equation to use: */
1205*e5436536SAndroid Build Coastguard Worker 
1206*e5436536SAndroid Build Coastguard Worker #define DMX_METHOD_MPEG_AMD4 1
1207*e5436536SAndroid Build Coastguard Worker #define DMX_METHOD_MPEG_LEGACY 2
1208*e5436536SAndroid Build Coastguard Worker #define DMX_METHOD_ARIB_JAPAN 4
1209*e5436536SAndroid Build Coastguard Worker #define DMX_METHOD_ITU_RECOM 8
1210*e5436536SAndroid Build Coastguard Worker #define DMX_METHOD_CUSTOM 16
1211*e5436536SAndroid Build Coastguard Worker 
1212*e5436536SAndroid Build Coastguard Worker   dmxMethod = DMX_METHOD_MPEG_AMD4; /* default */
1213*e5436536SAndroid Build Coastguard Worker 
1214*e5436536SAndroid Build Coastguard Worker   if ((pParams->dmxProfile == DMX_PRFL_FORCE_MATRIX_MIX) &&
1215*e5436536SAndroid Build Coastguard Worker       (pMetaData->typeFlags & TYPE_PCE_DATA)) {
1216*e5436536SAndroid Build Coastguard Worker     dmxMethod = DMX_METHOD_MPEG_LEGACY;
1217*e5436536SAndroid Build Coastguard Worker   } else if (!(pMetaData->typeFlags &
1218*e5436536SAndroid Build Coastguard Worker                (TYPE_DSE_CLEV_DATA | TYPE_DSE_SLEV_DATA))) {
1219*e5436536SAndroid Build Coastguard Worker     switch (pParams->dmxProfile) {
1220*e5436536SAndroid Build Coastguard Worker       default:
1221*e5436536SAndroid Build Coastguard Worker       case DMX_PRFL_STANDARD:
1222*e5436536SAndroid Build Coastguard Worker         /* dmxMethod = DMX_METHOD_MPEG_AMD4; */
1223*e5436536SAndroid Build Coastguard Worker         break;
1224*e5436536SAndroid Build Coastguard Worker       case DMX_PRFL_MATRIX_MIX:
1225*e5436536SAndroid Build Coastguard Worker       case DMX_PRFL_FORCE_MATRIX_MIX:
1226*e5436536SAndroid Build Coastguard Worker         if (pMetaData->typeFlags & TYPE_PCE_DATA) {
1227*e5436536SAndroid Build Coastguard Worker           dmxMethod = DMX_METHOD_MPEG_LEGACY;
1228*e5436536SAndroid Build Coastguard Worker         }
1229*e5436536SAndroid Build Coastguard Worker         break;
1230*e5436536SAndroid Build Coastguard Worker       case DMX_PRFL_ARIB_JAPAN:
1231*e5436536SAndroid Build Coastguard Worker         dmxMethod = DMX_METHOD_ARIB_JAPAN;
1232*e5436536SAndroid Build Coastguard Worker         break;
1233*e5436536SAndroid Build Coastguard Worker     }
1234*e5436536SAndroid Build Coastguard Worker   }
1235*e5436536SAndroid Build Coastguard Worker 
1236*e5436536SAndroid Build Coastguard Worker   /* SECOND STAGE: */
1237*e5436536SAndroid Build Coastguard Worker   if (numOutChannel <= TWO_CHANNEL) {
1238*e5436536SAndroid Build Coastguard Worker     /* Create DMX matrix according to input configuration */
1239*e5436536SAndroid Build Coastguard Worker     switch (inChMode) {
1240*e5436536SAndroid Build Coastguard Worker       case CH_MODE_2_0_0_0: /* chCfg 2 */
1241*e5436536SAndroid Build Coastguard Worker         /* Apply the dual channel mode. */
1242*e5436536SAndroid Build Coastguard Worker         switch (pParams->dualChannelMode) {
1243*e5436536SAndroid Build Coastguard Worker           case CH1_MODE: /* L' = 0.707 * Ch1;
1244*e5436536SAndroid Build Coastguard Worker                             R' = 0.707 * Ch1; */
1245*e5436536SAndroid Build Coastguard Worker             dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1246*e5436536SAndroid Build Coastguard Worker                           LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1247*e5436536SAndroid Build Coastguard Worker             dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1248*e5436536SAndroid Build Coastguard Worker                           LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1249*e5436536SAndroid Build Coastguard Worker             break;
1250*e5436536SAndroid Build Coastguard Worker           case CH2_MODE: /* L' = 0.707 * Ch2;
1251*e5436536SAndroid Build Coastguard Worker                             R' = 0.707 * Ch2; */
1252*e5436536SAndroid Build Coastguard Worker             dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1253*e5436536SAndroid Build Coastguard Worker                           RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1254*e5436536SAndroid Build Coastguard Worker             dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1255*e5436536SAndroid Build Coastguard Worker                           RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1256*e5436536SAndroid Build Coastguard Worker             break;
1257*e5436536SAndroid Build Coastguard Worker           case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2;
1258*e5436536SAndroid Build Coastguard Worker                               R' = 0.5*Ch1 + 0.5*Ch2; */
1259*e5436536SAndroid Build Coastguard Worker             dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1260*e5436536SAndroid Build Coastguard Worker                           LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1261*e5436536SAndroid Build Coastguard Worker             dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1262*e5436536SAndroid Build Coastguard Worker                           RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1263*e5436536SAndroid Build Coastguard Worker             dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1264*e5436536SAndroid Build Coastguard Worker                           LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1265*e5436536SAndroid Build Coastguard Worker             dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1266*e5436536SAndroid Build Coastguard Worker                           RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1267*e5436536SAndroid Build Coastguard Worker             break;
1268*e5436536SAndroid Build Coastguard Worker           default:
1269*e5436536SAndroid Build Coastguard Worker           case STEREO_MODE:
1270*e5436536SAndroid Build Coastguard Worker             /* Nothing to do */
1271*e5436536SAndroid Build Coastguard Worker             break;
1272*e5436536SAndroid Build Coastguard Worker         }
1273*e5436536SAndroid Build Coastguard Worker         break;
1274*e5436536SAndroid Build Coastguard Worker       /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1275*e5436536SAndroid Build Coastguard Worker        * - - - - - - - - - - - - - - - - - - - */
1276*e5436536SAndroid Build Coastguard Worker       case CH_MODE_2_0_1_0: {
1277*e5436536SAndroid Build Coastguard Worker         FIXP_DMX sMixLvl;
1278*e5436536SAndroid Build Coastguard Worker         if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1279*e5436536SAndroid Build Coastguard Worker           /* L' = 0.707*L + 0.5*S;  R' = 0.707*R + 0.5*S; */
1280*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1281*e5436536SAndroid Build Coastguard Worker                         LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1282*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1283*e5436536SAndroid Build Coastguard Worker                         RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1284*e5436536SAndroid Build Coastguard Worker           sMixLvl = FL2FXCONST_DMX(0.5f);
1285*e5436536SAndroid Build Coastguard Worker         } else { /* L' = L + 0.707*S;  R' = R + 0.707*S; */
1286*e5436536SAndroid Build Coastguard Worker           sMixLvl = FL2FXCONST_DMX(0.707f);
1287*e5436536SAndroid Build Coastguard Worker         }
1288*e5436536SAndroid Build Coastguard Worker         dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1289*e5436536SAndroid Build Coastguard Worker                       LEFT_REAR_CHANNEL, sMixLvl, 0);
1290*e5436536SAndroid Build Coastguard Worker         dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1291*e5436536SAndroid Build Coastguard Worker                       LEFT_REAR_CHANNEL, sMixLvl, 0);
1292*e5436536SAndroid Build Coastguard Worker       } break;
1293*e5436536SAndroid Build Coastguard Worker       /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1294*e5436536SAndroid Build Coastguard Worker        * - - - - - - - - - - - - - - - - - - - */
1295*e5436536SAndroid Build Coastguard Worker       case CH_MODE_3_0_0_0: /* chCfg 3 */
1296*e5436536SAndroid Build Coastguard Worker       {
1297*e5436536SAndroid Build Coastguard Worker         FIXP_DMX cMixLvl;
1298*e5436536SAndroid Build Coastguard Worker         if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1299*e5436536SAndroid Build Coastguard Worker           /* L' = 0.707*L + 0.5*C;  R' = 0.707*R + 0.5*C; */
1300*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1301*e5436536SAndroid Build Coastguard Worker                         LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1302*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1303*e5436536SAndroid Build Coastguard Worker                         RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1304*e5436536SAndroid Build Coastguard Worker           cMixLvl = FL2FXCONST_DMX(0.5f);
1305*e5436536SAndroid Build Coastguard Worker         } else { /* L' = L + 0.707*C;  R' = R + 0.707*C; */
1306*e5436536SAndroid Build Coastguard Worker           cMixLvl = FL2FXCONST_DMX(0.707f);
1307*e5436536SAndroid Build Coastguard Worker         }
1308*e5436536SAndroid Build Coastguard Worker         dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1309*e5436536SAndroid Build Coastguard Worker                       CENTER_FRONT_CHANNEL, cMixLvl, 0);
1310*e5436536SAndroid Build Coastguard Worker         dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1311*e5436536SAndroid Build Coastguard Worker                       CENTER_FRONT_CHANNEL, cMixLvl, 0);
1312*e5436536SAndroid Build Coastguard Worker       } break;
1313*e5436536SAndroid Build Coastguard Worker       /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1314*e5436536SAndroid Build Coastguard Worker        * - - - - - - - - - - - - - - - - - - - */
1315*e5436536SAndroid Build Coastguard Worker       case CH_MODE_3_0_1_0: /* chCfg 4 */
1316*e5436536SAndroid Build Coastguard Worker       {
1317*e5436536SAndroid Build Coastguard Worker         FIXP_DMX csMixLvl;
1318*e5436536SAndroid Build Coastguard Worker         if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1319*e5436536SAndroid Build Coastguard Worker           /* L' = 0.707*L + 0.5*C + 0.5*S;  R' = 0.707*R + 0.5*C + 0.5*S; */
1320*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1321*e5436536SAndroid Build Coastguard Worker                         LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1322*e5436536SAndroid Build Coastguard Worker           dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1323*e5436536SAndroid Build Coastguard Worker                         RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1324*e5436536SAndroid Build Coastguard Worker           csMixLvl = FL2FXCONST_DMX(0.5f);
1325*e5436536SAndroid Build Coastguard Worker         } else { /* L' = L + 0.707*C + 0.707*S;
1326*e5436536SAndroid Build Coastguard Worker                     R' = R + 0.707*C + 0.707*S; */
1327*e5436536SAndroid Build Coastguard Worker           csMixLvl = FL2FXCONST_DMX(0.707f);
1328*e5436536SAndroid Build Coastguard Worker         }
1329*e5436536SAndroid Build Coastguard Worker         dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1330*e5436536SAndroid Build Coastguard Worker                       CENTER_FRONT_CHANNEL, csMixLvl, 0);
1331*e5436536SAndroid Build Coastguard Worker         dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1332*e5436536SAndroid Build Coastguard Worker                       LEFT_REAR_CHANNEL, csMixLvl, 0);
1333*e5436536SAndroid Build Coastguard Worker         dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1334*e5436536SAndroid Build Coastguard Worker                       CENTER_FRONT_CHANNEL, csMixLvl, 0);
1335*e5436536SAndroid Build Coastguard Worker         dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1336*e5436536SAndroid Build Coastguard Worker                       LEFT_REAR_CHANNEL, csMixLvl, 0);
1337*e5436536SAndroid Build Coastguard Worker       } break;
1338*e5436536SAndroid Build Coastguard Worker       /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1339*e5436536SAndroid Build Coastguard Worker        * - - - - - - - - - - - - - - - - - - - */
1340*e5436536SAndroid Build Coastguard Worker       case CH_MODE_3_0_2_0: /* chCfg 5 */
1341*e5436536SAndroid Build Coastguard Worker       case CH_MODE_3_0_2_1: /* chCfg 6 */
1342*e5436536SAndroid Build Coastguard Worker       {
1343*e5436536SAndroid Build Coastguard Worker         switch (dmxMethod) {
1344*e5436536SAndroid Build Coastguard Worker           default:
1345*e5436536SAndroid Build Coastguard Worker           case DMX_METHOD_MPEG_AMD4: {
1346*e5436536SAndroid Build Coastguard Worker             FIXP_DMX cMixLvl, sMixLvl, lMixLvl;
1347*e5436536SAndroid Build Coastguard Worker             INT cMixScale, sMixScale, lMixScale;
1348*e5436536SAndroid Build Coastguard Worker 
1349*e5436536SAndroid Build Coastguard Worker             /* Get factors from meta data */
1350*e5436536SAndroid Build Coastguard Worker             cMixLvl = abMixLvlValueTab[pMetaData->cLevIdx];
1351*e5436536SAndroid Build Coastguard Worker             cMixScale = (pMetaData->cLevIdx == 0) ? 1 : 0;
1352*e5436536SAndroid Build Coastguard Worker             sMixLvl = abMixLvlValueTab[pMetaData->sLevIdx];
1353*e5436536SAndroid Build Coastguard Worker             sMixScale = (pMetaData->sLevIdx == 0) ? 1 : 0;
1354*e5436536SAndroid Build Coastguard Worker             lMixLvl = lfeMixLvlValueTab[pMetaData->dmixIdxLfe];
1355*e5436536SAndroid Build Coastguard Worker             if (pMetaData->dmixIdxLfe <= 1) {
1356*e5436536SAndroid Build Coastguard Worker               lMixScale = 2;
1357*e5436536SAndroid Build Coastguard Worker             } else if (pMetaData->dmixIdxLfe <= 5) {
1358*e5436536SAndroid Build Coastguard Worker               lMixScale = 1;
1359*e5436536SAndroid Build Coastguard Worker             } else {
1360*e5436536SAndroid Build Coastguard Worker               lMixScale = 0;
1361*e5436536SAndroid Build Coastguard Worker             }
1362*e5436536SAndroid Build Coastguard Worker             /* Setup the DMX matrix */
1363*e5436536SAndroid Build Coastguard Worker             if ((pParams->pseudoSurrMode == FORCE_PS_DMX) ||
1364*e5436536SAndroid Build Coastguard Worker                 ((pParams->pseudoSurrMode == AUTO_PS_DMX) &&
1365*e5436536SAndroid Build Coastguard Worker                  (pMetaData->pseudoSurround ==
1366*e5436536SAndroid Build Coastguard Worker                   1))) { /* L' = L + C*clev - (Ls+Rs)*slev + LFE*lflev;
1367*e5436536SAndroid Build Coastguard Worker                             R' = R + C*clev + (Ls+Rs)*slev + LFE*lflev; */
1368*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1369*e5436536SAndroid Build Coastguard Worker                             CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1370*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1371*e5436536SAndroid Build Coastguard Worker                             LEFT_REAR_CHANNEL, -sMixLvl, sMixScale);
1372*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1373*e5436536SAndroid Build Coastguard Worker                             RIGHT_REAR_CHANNEL, -sMixLvl, sMixScale);
1374*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1375*e5436536SAndroid Build Coastguard Worker                             LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1376*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1377*e5436536SAndroid Build Coastguard Worker                             CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1378*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1379*e5436536SAndroid Build Coastguard Worker                             LEFT_REAR_CHANNEL, sMixLvl, sMixScale);
1380*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1381*e5436536SAndroid Build Coastguard Worker                             RIGHT_REAR_CHANNEL, sMixLvl, sMixScale);
1382*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1383*e5436536SAndroid Build Coastguard Worker                             LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1384*e5436536SAndroid Build Coastguard Worker             } else { /* L' = L + C*clev + Ls*slev + LFE*llev;
1385*e5436536SAndroid Build Coastguard Worker                         R' = R + C*clev + Rs*slev + LFE*llev; */
1386*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1387*e5436536SAndroid Build Coastguard Worker                             CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1388*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1389*e5436536SAndroid Build Coastguard Worker                             LEFT_REAR_CHANNEL, sMixLvl, sMixScale);
1390*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1391*e5436536SAndroid Build Coastguard Worker                             LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1392*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1393*e5436536SAndroid Build Coastguard Worker                             CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1394*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1395*e5436536SAndroid Build Coastguard Worker                             RIGHT_REAR_CHANNEL, sMixLvl, sMixScale);
1396*e5436536SAndroid Build Coastguard Worker               dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1397*e5436536SAndroid Build Coastguard Worker                             LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1398*e5436536SAndroid Build Coastguard Worker             }
1399*e5436536SAndroid Build Coastguard Worker 
1400*e5436536SAndroid Build Coastguard Worker             /* Add additional DMX gain */
1401*e5436536SAndroid Build Coastguard Worker             if (pMetaData->dmxGainIdx2 != 0) { /* Apply DMX gain 2 */
1402*e5436536SAndroid Build Coastguard Worker               FIXP_DMX dmxGain;
1403*e5436536SAndroid Build Coastguard Worker               INT dmxScale;
1404*e5436536SAndroid Build Coastguard Worker               INT sign = (pMetaData->dmxGainIdx2 & 0x40) ? -1 : 1;
1405*e5436536SAndroid Build Coastguard Worker               INT val = pMetaData->dmxGainIdx2 & 0x3F;
1406*e5436536SAndroid Build Coastguard Worker 
1407*e5436536SAndroid Build Coastguard Worker               /* 10^(dmx_gain_2/80) */
1408*e5436536SAndroid Build Coastguard Worker               dmxGain = FX_DBL2FX_DMX(
1409*e5436536SAndroid Build Coastguard Worker                   fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
1410*e5436536SAndroid Build Coastguard Worker                          (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)),
1411*e5436536SAndroid Build Coastguard Worker                          0, &dmxScale));
1412*e5436536SAndroid Build Coastguard Worker               /* Currently only positive scale factors supported! */
1413*e5436536SAndroid Build Coastguard Worker               if (dmxScale < 0) {
1414*e5436536SAndroid Build Coastguard Worker                 dmxGain >>= -dmxScale;
1415*e5436536SAndroid Build Coastguard Worker                 dmxScale = 0;
1416*e5436536SAndroid Build Coastguard Worker               }
1417*e5436536SAndroid Build Coastguard Worker 
1418*e5436536SAndroid Build Coastguard Worker               dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1419*e5436536SAndroid Build Coastguard Worker                             LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
1420*e5436536SAndroid Build Coastguard Worker               dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1421*e5436536SAndroid Build Coastguard Worker                             RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
1422*e5436536SAndroid Build Coastguard Worker             }
1423*e5436536SAndroid Build Coastguard Worker           } break;
1424*e5436536SAndroid Build Coastguard Worker           case DMX_METHOD_ARIB_JAPAN:
1425*e5436536SAndroid Build Coastguard Worker           case DMX_METHOD_MPEG_LEGACY: {
1426*e5436536SAndroid Build Coastguard Worker             FIXP_DMX flev, clev, slevLL, slevLR, slevRL, slevRR;
1427*e5436536SAndroid Build Coastguard Worker             FIXP_DMX mtrxMixDwnCoef =
1428*e5436536SAndroid Build Coastguard Worker                 mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx];
1429*e5436536SAndroid Build Coastguard Worker 
1430*e5436536SAndroid Build Coastguard Worker             if ((pParams->pseudoSurrMode == FORCE_PS_DMX) ||
1431*e5436536SAndroid Build Coastguard Worker                 ((pParams->pseudoSurrMode == AUTO_PS_DMX) &&
1432*e5436536SAndroid Build Coastguard Worker                  (pMetaData->pseudoSurround == 1))) {
1433*e5436536SAndroid Build Coastguard Worker               if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1434*e5436536SAndroid Build Coastguard Worker                 /* 3/2 input: L' = 0.707 * [L+0.707*C-k*Ls-k*Rs];
1435*e5436536SAndroid Build Coastguard Worker                               R' = 0.707 * [R+0.707*C+k*Ls+k*Rs]; */
1436*e5436536SAndroid Build Coastguard Worker                 flev = mpegMixDownIdx2Coef[0]; /* a = 0.707 */
1437*e5436536SAndroid Build Coastguard Worker               } else { /* 3/2 input: L' = (1.707+2*A)^-1 *
1438*e5436536SAndroid Build Coastguard Worker                           [L+0.707*C-A*Ls-A*Rs]; R' = (1.707+2*A)^-1 *
1439*e5436536SAndroid Build Coastguard Worker                           [R+0.707*C+A*Ls+A*Rs]; */
1440*e5436536SAndroid Build Coastguard Worker                 flev = mpegMixDownIdx2PreFact[1][pMetaData->matrixMixdownIdx];
1441*e5436536SAndroid Build Coastguard Worker               }
1442*e5436536SAndroid Build Coastguard Worker               slevRR = slevRL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
1443*e5436536SAndroid Build Coastguard Worker               slevLL = slevLR = -slevRL;
1444*e5436536SAndroid Build Coastguard Worker             } else {
1445*e5436536SAndroid Build Coastguard Worker               if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1446*e5436536SAndroid Build Coastguard Worker                 /* 3/2 input: L' = 0.707 * [L+0.707*C+k*Ls];
1447*e5436536SAndroid Build Coastguard Worker                               R' = 0.707 * [R+0.707*C+k*Rs]; */
1448*e5436536SAndroid Build Coastguard Worker                 flev = mpegMixDownIdx2Coef[0]; /* a = 0.707 */
1449*e5436536SAndroid Build Coastguard Worker               } else { /* 3/2 input: L' = (1.707+A)^-1 * [L+0.707*C+A*Ls];
1450*e5436536SAndroid Build Coastguard Worker                                      R' = (1.707+A)^-1 * [R+0.707*C+A*Rs]; */
1451*e5436536SAndroid Build Coastguard Worker                 flev = mpegMixDownIdx2PreFact[0][pMetaData->matrixMixdownIdx];
1452*e5436536SAndroid Build Coastguard Worker               }
1453*e5436536SAndroid Build Coastguard Worker               slevRR = slevLL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
1454*e5436536SAndroid Build Coastguard Worker               slevLR = slevRL = (FIXP_DMX)0;
1455*e5436536SAndroid Build Coastguard Worker             }
1456*e5436536SAndroid Build Coastguard Worker             /* common factor */
1457*e5436536SAndroid Build Coastguard Worker             clev =
1458*e5436536SAndroid Build Coastguard Worker                 FX_DBL2FX_DMX(fMult(flev, mpegMixDownIdx2Coef[0] /* 0.707 */));
1459*e5436536SAndroid Build Coastguard Worker 
1460*e5436536SAndroid Build Coastguard Worker             dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1461*e5436536SAndroid Build Coastguard Worker                           LEFT_FRONT_CHANNEL, flev, 0);
1462*e5436536SAndroid Build Coastguard Worker             dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1463*e5436536SAndroid Build Coastguard Worker                           CENTER_FRONT_CHANNEL, clev, 0);
1464*e5436536SAndroid Build Coastguard Worker             dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1465*e5436536SAndroid Build Coastguard Worker                           LEFT_REAR_CHANNEL, slevLL, 0);
1466*e5436536SAndroid Build Coastguard Worker             dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1467*e5436536SAndroid Build Coastguard Worker                           RIGHT_REAR_CHANNEL, slevLR, 0);
1468*e5436536SAndroid Build Coastguard Worker 
1469*e5436536SAndroid Build Coastguard Worker             dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1470*e5436536SAndroid Build Coastguard Worker                           RIGHT_FRONT_CHANNEL, flev, 0);
1471*e5436536SAndroid Build Coastguard Worker             dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1472*e5436536SAndroid Build Coastguard Worker                           CENTER_FRONT_CHANNEL, clev, 0);
1473*e5436536SAndroid Build Coastguard Worker             dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1474*e5436536SAndroid Build Coastguard Worker                           LEFT_REAR_CHANNEL, slevRL, 0);
1475*e5436536SAndroid Build Coastguard Worker             dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1476*e5436536SAndroid Build Coastguard Worker                           RIGHT_REAR_CHANNEL, slevRR, 0);
1477*e5436536SAndroid Build Coastguard Worker           } break;
1478*e5436536SAndroid Build Coastguard Worker         } /* switch (dmxMethod) */
1479*e5436536SAndroid Build Coastguard Worker       } break;
1480*e5436536SAndroid Build Coastguard Worker       default:
1481*e5436536SAndroid Build Coastguard Worker         /* This configuration does not fit to any known downmix equation! */
1482*e5436536SAndroid Build Coastguard Worker         err = PCMDMX_INVALID_MODE;
1483*e5436536SAndroid Build Coastguard Worker         break;
1484*e5436536SAndroid Build Coastguard Worker     } /* switch (inChMode) */
1485*e5436536SAndroid Build Coastguard Worker 
1486*e5436536SAndroid Build Coastguard Worker     /* Mark the output channels */
1487*e5436536SAndroid Build Coastguard Worker     FDKmemclear(valid, (8) * sizeof(unsigned int));
1488*e5436536SAndroid Build Coastguard Worker     valid[LEFT_FRONT_CHANNEL] = 1;
1489*e5436536SAndroid Build Coastguard Worker     valid[RIGHT_FRONT_CHANNEL] = 1;
1490*e5436536SAndroid Build Coastguard Worker   }
1491*e5436536SAndroid Build Coastguard Worker 
1492*e5436536SAndroid Build Coastguard Worker   if (numOutChannel == ONE_CHANNEL) {
1493*e5436536SAndroid Build Coastguard Worker     FIXP_DMX monoMixLevel;
1494*e5436536SAndroid Build Coastguard Worker     INT monoMixScale = 0;
1495*e5436536SAndroid Build Coastguard Worker 
1496*e5436536SAndroid Build Coastguard Worker     dmxClearChannel(mixFactors, mixScales,
1497*e5436536SAndroid Build Coastguard Worker                     CENTER_FRONT_CHANNEL); /* C is not in the mix */
1498*e5436536SAndroid Build Coastguard Worker 
1499*e5436536SAndroid Build Coastguard Worker     if (dmxMethod ==
1500*e5436536SAndroid Build Coastguard Worker         DMX_METHOD_MPEG_LEGACY) { /* C' = (3+2*A)^-1 * [C+L+R+A*Ls+A+Rs]; */
1501*e5436536SAndroid Build Coastguard Worker       monoMixLevel = mpegMixDownIdx2PreFact[2][pMetaData->matrixMixdownIdx];
1502*e5436536SAndroid Build Coastguard Worker 
1503*e5436536SAndroid Build Coastguard Worker       mixFactors[CENTER_FRONT_CHANNEL][CENTER_FRONT_CHANNEL] = monoMixLevel;
1504*e5436536SAndroid Build Coastguard Worker       mixFactors[CENTER_FRONT_CHANNEL][LEFT_FRONT_CHANNEL] = monoMixLevel;
1505*e5436536SAndroid Build Coastguard Worker       mixFactors[CENTER_FRONT_CHANNEL][RIGHT_FRONT_CHANNEL] = monoMixLevel;
1506*e5436536SAndroid Build Coastguard Worker       monoMixLevel = FX_DBL2FX_DMX(fMult(
1507*e5436536SAndroid Build Coastguard Worker           monoMixLevel, mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx]));
1508*e5436536SAndroid Build Coastguard Worker       mixFactors[CENTER_FRONT_CHANNEL][LEFT_REAR_CHANNEL] = monoMixLevel;
1509*e5436536SAndroid Build Coastguard Worker       mixFactors[CENTER_FRONT_CHANNEL][RIGHT_REAR_CHANNEL] = monoMixLevel;
1510*e5436536SAndroid Build Coastguard Worker     } else {
1511*e5436536SAndroid Build Coastguard Worker       switch (dmxMethod) {
1512*e5436536SAndroid Build Coastguard Worker         case DMX_METHOD_MPEG_AMD4:
1513*e5436536SAndroid Build Coastguard Worker           /* C' = L + R; */
1514*e5436536SAndroid Build Coastguard Worker           monoMixLevel = FL2FXCONST_DMX(0.5f);
1515*e5436536SAndroid Build Coastguard Worker           monoMixScale = 1;
1516*e5436536SAndroid Build Coastguard Worker           break;
1517*e5436536SAndroid Build Coastguard Worker         default:
1518*e5436536SAndroid Build Coastguard Worker           /* C' = 0.5*L + 0.5*R; */
1519*e5436536SAndroid Build Coastguard Worker           monoMixLevel = FL2FXCONST_DMX(0.5f);
1520*e5436536SAndroid Build Coastguard Worker           monoMixScale = 0;
1521*e5436536SAndroid Build Coastguard Worker           break;
1522*e5436536SAndroid Build Coastguard Worker       }
1523*e5436536SAndroid Build Coastguard Worker       dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1524*e5436536SAndroid Build Coastguard Worker                     LEFT_FRONT_CHANNEL, monoMixLevel, monoMixScale);
1525*e5436536SAndroid Build Coastguard Worker       dmxAddChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1526*e5436536SAndroid Build Coastguard Worker                     RIGHT_FRONT_CHANNEL, monoMixLevel, monoMixScale);
1527*e5436536SAndroid Build Coastguard Worker     }
1528*e5436536SAndroid Build Coastguard Worker 
1529*e5436536SAndroid Build Coastguard Worker     /* Mark the output channel */
1530*e5436536SAndroid Build Coastguard Worker     FDKmemclear(valid, (8) * sizeof(unsigned int));
1531*e5436536SAndroid Build Coastguard Worker     valid[CENTER_FRONT_CHANNEL] = 1;
1532*e5436536SAndroid Build Coastguard Worker   }
1533*e5436536SAndroid Build Coastguard Worker 
1534*e5436536SAndroid Build Coastguard Worker #define MAX_SEARCH_START_VAL (-7)
1535*e5436536SAndroid Build Coastguard Worker 
1536*e5436536SAndroid Build Coastguard Worker   {
1537*e5436536SAndroid Build Coastguard Worker     LONG chSum[(8)];
1538*e5436536SAndroid Build Coastguard Worker     INT chSumMax = MAX_SEARCH_START_VAL;
1539*e5436536SAndroid Build Coastguard Worker 
1540*e5436536SAndroid Build Coastguard Worker     /* Determine the current maximum scale factor */
1541*e5436536SAndroid Build Coastguard Worker     for (outCh = 0; outCh < (8); outCh += 1) {
1542*e5436536SAndroid Build Coastguard Worker       if (valid[outCh] != 0) {
1543*e5436536SAndroid Build Coastguard Worker         unsigned int inCh;
1544*e5436536SAndroid Build Coastguard Worker         for (inCh = 0; inCh < (8); inCh += 1) {
1545*e5436536SAndroid Build Coastguard Worker           if (mixScales[outCh][inCh] > maxScale) { /* Store the new maximum */
1546*e5436536SAndroid Build Coastguard Worker             maxScale = mixScales[outCh][inCh];
1547*e5436536SAndroid Build Coastguard Worker           }
1548*e5436536SAndroid Build Coastguard Worker         }
1549*e5436536SAndroid Build Coastguard Worker       }
1550*e5436536SAndroid Build Coastguard Worker     }
1551*e5436536SAndroid Build Coastguard Worker 
1552*e5436536SAndroid Build Coastguard Worker     /* Individualy analyse output chanal levels */
1553*e5436536SAndroid Build Coastguard Worker     for (outCh = 0; outCh < (8); outCh += 1) {
1554*e5436536SAndroid Build Coastguard Worker       chSum[outCh] = MAX_SEARCH_START_VAL;
1555*e5436536SAndroid Build Coastguard Worker       if (valid[outCh] != 0) {
1556*e5436536SAndroid Build Coastguard Worker         int ovrflwProtScale = 0;
1557*e5436536SAndroid Build Coastguard Worker         unsigned int inCh;
1558*e5436536SAndroid Build Coastguard Worker 
1559*e5436536SAndroid Build Coastguard Worker         /* Accumulate all factors for each output channel */
1560*e5436536SAndroid Build Coastguard Worker         chSum[outCh] = 0;
1561*e5436536SAndroid Build Coastguard Worker         for (inCh = 0; inCh < (8); inCh += 1) {
1562*e5436536SAndroid Build Coastguard Worker           SHORT addFact = FX_DMX2SHRT(mixFactors[outCh][inCh]);
1563*e5436536SAndroid Build Coastguard Worker           if (mixScales[outCh][inCh] <= maxScale) {
1564*e5436536SAndroid Build Coastguard Worker             addFact >>= maxScale - mixScales[outCh][inCh];
1565*e5436536SAndroid Build Coastguard Worker           } else {
1566*e5436536SAndroid Build Coastguard Worker             addFact <<= mixScales[outCh][inCh] - maxScale;
1567*e5436536SAndroid Build Coastguard Worker           }
1568*e5436536SAndroid Build Coastguard Worker           chSum[outCh] += addFact;
1569*e5436536SAndroid Build Coastguard Worker         }
1570*e5436536SAndroid Build Coastguard Worker         if (chSum[outCh] > (LONG)MAXVAL_SGL) {
1571*e5436536SAndroid Build Coastguard Worker           while (chSum[outCh] > (LONG)MAXVAL_SGL) {
1572*e5436536SAndroid Build Coastguard Worker             ovrflwProtScale += 1;
1573*e5436536SAndroid Build Coastguard Worker             chSum[outCh] >>= 1;
1574*e5436536SAndroid Build Coastguard Worker           }
1575*e5436536SAndroid Build Coastguard Worker         } else if (chSum[outCh] > 0) {
1576*e5436536SAndroid Build Coastguard Worker           while ((chSum[outCh] << 1) <= (LONG)MAXVAL_SGL) {
1577*e5436536SAndroid Build Coastguard Worker             ovrflwProtScale -= 1;
1578*e5436536SAndroid Build Coastguard Worker             chSum[outCh] <<= 1;
1579*e5436536SAndroid Build Coastguard Worker           }
1580*e5436536SAndroid Build Coastguard Worker         }
1581*e5436536SAndroid Build Coastguard Worker         /* Store the differential scaling in the same array */
1582*e5436536SAndroid Build Coastguard Worker         chSum[outCh] = ovrflwProtScale;
1583*e5436536SAndroid Build Coastguard Worker       }
1584*e5436536SAndroid Build Coastguard Worker     }
1585*e5436536SAndroid Build Coastguard Worker 
1586*e5436536SAndroid Build Coastguard Worker     for (outCh = 0; outCh < (8); outCh += 1) {
1587*e5436536SAndroid Build Coastguard Worker       if ((valid[outCh] != 0) &&
1588*e5436536SAndroid Build Coastguard Worker           (chSum[outCh] > chSumMax)) { /* Store the new maximum */
1589*e5436536SAndroid Build Coastguard Worker         chSumMax = chSum[outCh];
1590*e5436536SAndroid Build Coastguard Worker       }
1591*e5436536SAndroid Build Coastguard Worker     }
1592*e5436536SAndroid Build Coastguard Worker     maxScale = fMax(maxScale + chSumMax, 0);
1593*e5436536SAndroid Build Coastguard Worker 
1594*e5436536SAndroid Build Coastguard Worker     /* Normalize all factors */
1595*e5436536SAndroid Build Coastguard Worker     for (outCh = 0; outCh < (8); outCh += 1) {
1596*e5436536SAndroid Build Coastguard Worker       if (valid[outCh] != 0) {
1597*e5436536SAndroid Build Coastguard Worker         unsigned int inCh;
1598*e5436536SAndroid Build Coastguard Worker         for (inCh = 0; inCh < (8); inCh += 1) {
1599*e5436536SAndroid Build Coastguard Worker           if (mixFactors[outCh][inCh] != (FIXP_DMX)0) {
1600*e5436536SAndroid Build Coastguard Worker             if (mixScales[outCh][inCh] <= maxScale) {
1601*e5436536SAndroid Build Coastguard Worker               mixFactors[outCh][inCh] >>= maxScale - mixScales[outCh][inCh];
1602*e5436536SAndroid Build Coastguard Worker             } else {
1603*e5436536SAndroid Build Coastguard Worker               mixFactors[outCh][inCh] <<= mixScales[outCh][inCh] - maxScale;
1604*e5436536SAndroid Build Coastguard Worker             }
1605*e5436536SAndroid Build Coastguard Worker             mixScales[outCh][inCh] = maxScale;
1606*e5436536SAndroid Build Coastguard Worker           }
1607*e5436536SAndroid Build Coastguard Worker         }
1608*e5436536SAndroid Build Coastguard Worker       }
1609*e5436536SAndroid Build Coastguard Worker     }
1610*e5436536SAndroid Build Coastguard Worker   }
1611*e5436536SAndroid Build Coastguard Worker 
1612*e5436536SAndroid Build Coastguard Worker   /* return the scale factor */
1613*e5436536SAndroid Build Coastguard Worker   *pOutScale = maxScale;
1614*e5436536SAndroid Build Coastguard Worker 
1615*e5436536SAndroid Build Coastguard Worker   return (err);
1616*e5436536SAndroid Build Coastguard Worker }
1617*e5436536SAndroid Build Coastguard Worker 
1618*e5436536SAndroid Build Coastguard Worker /** Open and initialize an instance of the PCM downmix module
1619*e5436536SAndroid Build Coastguard Worker  * @param [out] Pointer to a buffer receiving the handle of the new instance.
1620*e5436536SAndroid Build Coastguard Worker  * @returns Returns an error code.
1621*e5436536SAndroid Build Coastguard Worker  **/
pcmDmx_Open(HANDLE_PCM_DOWNMIX * pSelf)1622*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_Open(HANDLE_PCM_DOWNMIX *pSelf) {
1623*e5436536SAndroid Build Coastguard Worker   HANDLE_PCM_DOWNMIX self;
1624*e5436536SAndroid Build Coastguard Worker 
1625*e5436536SAndroid Build Coastguard Worker   if (pSelf == NULL) {
1626*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_HANDLE);
1627*e5436536SAndroid Build Coastguard Worker   }
1628*e5436536SAndroid Build Coastguard Worker 
1629*e5436536SAndroid Build Coastguard Worker   *pSelf = NULL;
1630*e5436536SAndroid Build Coastguard Worker 
1631*e5436536SAndroid Build Coastguard Worker   self = (HANDLE_PCM_DOWNMIX)GetPcmDmxInstance(0);
1632*e5436536SAndroid Build Coastguard Worker   if (self == NULL) {
1633*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_OUT_OF_MEMORY);
1634*e5436536SAndroid Build Coastguard Worker   }
1635*e5436536SAndroid Build Coastguard Worker 
1636*e5436536SAndroid Build Coastguard Worker   /* Reset the full instance */
1637*e5436536SAndroid Build Coastguard Worker   pcmDmx_Reset(self, PCMDMX_RESET_FULL);
1638*e5436536SAndroid Build Coastguard Worker 
1639*e5436536SAndroid Build Coastguard Worker   *pSelf = self;
1640*e5436536SAndroid Build Coastguard Worker 
1641*e5436536SAndroid Build Coastguard Worker   return (PCMDMX_OK);
1642*e5436536SAndroid Build Coastguard Worker }
1643*e5436536SAndroid Build Coastguard Worker 
1644*e5436536SAndroid Build Coastguard Worker /** Reset all static values like e.g. mixdown coefficients.
1645*e5436536SAndroid Build Coastguard Worker  * @param [in] Handle of PCM downmix module instance.
1646*e5436536SAndroid Build Coastguard Worker  * @param [in] Flags telling which parts of the module shall be reset.
1647*e5436536SAndroid Build Coastguard Worker  * @returns Returns an error code.
1648*e5436536SAndroid Build Coastguard Worker  **/
pcmDmx_Reset(HANDLE_PCM_DOWNMIX self,UINT flags)1649*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_Reset(HANDLE_PCM_DOWNMIX self, UINT flags) {
1650*e5436536SAndroid Build Coastguard Worker   if (self == NULL) {
1651*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_HANDLE);
1652*e5436536SAndroid Build Coastguard Worker   }
1653*e5436536SAndroid Build Coastguard Worker 
1654*e5436536SAndroid Build Coastguard Worker   if (flags & PCMDMX_RESET_PARAMS) {
1655*e5436536SAndroid Build Coastguard Worker     PCM_DMX_USER_PARAMS *pParams = &self->userParams;
1656*e5436536SAndroid Build Coastguard Worker 
1657*e5436536SAndroid Build Coastguard Worker     pParams->dualChannelMode = STEREO_MODE;
1658*e5436536SAndroid Build Coastguard Worker     pParams->pseudoSurrMode = NEVER_DO_PS_DMX;
1659*e5436536SAndroid Build Coastguard Worker     pParams->numOutChannelsMax = (6);
1660*e5436536SAndroid Build Coastguard Worker     pParams->numOutChannelsMin = (0);
1661*e5436536SAndroid Build Coastguard Worker     pParams->frameDelay = 0;
1662*e5436536SAndroid Build Coastguard Worker     pParams->expiryFrame = (0);
1663*e5436536SAndroid Build Coastguard Worker 
1664*e5436536SAndroid Build Coastguard Worker     self->applyProcessing = 0;
1665*e5436536SAndroid Build Coastguard Worker   }
1666*e5436536SAndroid Build Coastguard Worker 
1667*e5436536SAndroid Build Coastguard Worker   if (flags & PCMDMX_RESET_BS_DATA) {
1668*e5436536SAndroid Build Coastguard Worker     int slot;
1669*e5436536SAndroid Build Coastguard Worker     /* Init all slots with a default set */
1670*e5436536SAndroid Build Coastguard Worker     for (slot = 0; slot <= (1); slot += 1) {
1671*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(&self->bsMetaData[slot], &dfltMetaData,
1672*e5436536SAndroid Build Coastguard Worker                 sizeof(DMX_BS_META_DATA));
1673*e5436536SAndroid Build Coastguard Worker     }
1674*e5436536SAndroid Build Coastguard Worker   }
1675*e5436536SAndroid Build Coastguard Worker 
1676*e5436536SAndroid Build Coastguard Worker   return (PCMDMX_OK);
1677*e5436536SAndroid Build Coastguard Worker }
1678*e5436536SAndroid Build Coastguard Worker 
1679*e5436536SAndroid Build Coastguard Worker /** Set one parameter for one instance of the PCM downmix module.
1680*e5436536SAndroid Build Coastguard Worker  * @param [in] Handle of PCM downmix module instance.
1681*e5436536SAndroid Build Coastguard Worker  * @param [in] Parameter to be set.
1682*e5436536SAndroid Build Coastguard Worker  * @param [in] Parameter value.
1683*e5436536SAndroid Build Coastguard Worker  * @returns Returns an error code.
1684*e5436536SAndroid Build Coastguard Worker  **/
pcmDmx_SetParam(HANDLE_PCM_DOWNMIX self,const PCMDMX_PARAM param,const INT value)1685*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_SetParam(HANDLE_PCM_DOWNMIX self, const PCMDMX_PARAM param,
1686*e5436536SAndroid Build Coastguard Worker                              const INT value) {
1687*e5436536SAndroid Build Coastguard Worker   switch (param) {
1688*e5436536SAndroid Build Coastguard Worker     case DMX_PROFILE_SETTING:
1689*e5436536SAndroid Build Coastguard Worker       switch ((DMX_PROFILE_TYPE)value) {
1690*e5436536SAndroid Build Coastguard Worker         case DMX_PRFL_STANDARD:
1691*e5436536SAndroid Build Coastguard Worker         case DMX_PRFL_MATRIX_MIX:
1692*e5436536SAndroid Build Coastguard Worker         case DMX_PRFL_FORCE_MATRIX_MIX:
1693*e5436536SAndroid Build Coastguard Worker         case DMX_PRFL_ARIB_JAPAN:
1694*e5436536SAndroid Build Coastguard Worker           break;
1695*e5436536SAndroid Build Coastguard Worker         default:
1696*e5436536SAndroid Build Coastguard Worker           return (PCMDMX_UNABLE_TO_SET_PARAM);
1697*e5436536SAndroid Build Coastguard Worker       }
1698*e5436536SAndroid Build Coastguard Worker       if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1699*e5436536SAndroid Build Coastguard Worker       self->userParams.dmxProfile = (DMX_PROFILE_TYPE)value;
1700*e5436536SAndroid Build Coastguard Worker       break;
1701*e5436536SAndroid Build Coastguard Worker 
1702*e5436536SAndroid Build Coastguard Worker     case DMX_BS_DATA_EXPIRY_FRAME:
1703*e5436536SAndroid Build Coastguard Worker       if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1704*e5436536SAndroid Build Coastguard Worker       self->userParams.expiryFrame = (value > 0) ? (UINT)value : 0;
1705*e5436536SAndroid Build Coastguard Worker       break;
1706*e5436536SAndroid Build Coastguard Worker 
1707*e5436536SAndroid Build Coastguard Worker     case DMX_BS_DATA_DELAY:
1708*e5436536SAndroid Build Coastguard Worker       if ((value > (1)) || (value < 0)) {
1709*e5436536SAndroid Build Coastguard Worker         return (PCMDMX_UNABLE_TO_SET_PARAM);
1710*e5436536SAndroid Build Coastguard Worker       }
1711*e5436536SAndroid Build Coastguard Worker       if (self == NULL) {
1712*e5436536SAndroid Build Coastguard Worker         return (PCMDMX_INVALID_HANDLE);
1713*e5436536SAndroid Build Coastguard Worker       }
1714*e5436536SAndroid Build Coastguard Worker       self->userParams.frameDelay = (UCHAR)value;
1715*e5436536SAndroid Build Coastguard Worker       break;
1716*e5436536SAndroid Build Coastguard Worker 
1717*e5436536SAndroid Build Coastguard Worker     case MIN_NUMBER_OF_OUTPUT_CHANNELS:
1718*e5436536SAndroid Build Coastguard Worker       switch (value) { /* supported output channels */
1719*e5436536SAndroid Build Coastguard Worker         case -1:
1720*e5436536SAndroid Build Coastguard Worker         case 0:
1721*e5436536SAndroid Build Coastguard Worker         case ONE_CHANNEL:
1722*e5436536SAndroid Build Coastguard Worker         case TWO_CHANNEL:
1723*e5436536SAndroid Build Coastguard Worker         case SIX_CHANNEL:
1724*e5436536SAndroid Build Coastguard Worker         case EIGHT_CHANNEL:
1725*e5436536SAndroid Build Coastguard Worker           break;
1726*e5436536SAndroid Build Coastguard Worker         default:
1727*e5436536SAndroid Build Coastguard Worker           return (PCMDMX_UNABLE_TO_SET_PARAM);
1728*e5436536SAndroid Build Coastguard Worker       }
1729*e5436536SAndroid Build Coastguard Worker       if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1730*e5436536SAndroid Build Coastguard Worker       /* Store the new value */
1731*e5436536SAndroid Build Coastguard Worker       self->userParams.numOutChannelsMin = (value > 0) ? (SHORT)value : -1;
1732*e5436536SAndroid Build Coastguard Worker       if ((value > 0) && (self->userParams.numOutChannelsMax > 0) &&
1733*e5436536SAndroid Build Coastguard Worker           (value > self->userParams
1734*e5436536SAndroid Build Coastguard Worker                        .numOutChannelsMax)) { /* MIN > MAX would be an invalid
1735*e5436536SAndroid Build Coastguard Worker                                                  state. Thus set MAX = MIN in
1736*e5436536SAndroid Build Coastguard Worker                                                  this case. */
1737*e5436536SAndroid Build Coastguard Worker         self->userParams.numOutChannelsMax = self->userParams.numOutChannelsMin;
1738*e5436536SAndroid Build Coastguard Worker       }
1739*e5436536SAndroid Build Coastguard Worker       break;
1740*e5436536SAndroid Build Coastguard Worker 
1741*e5436536SAndroid Build Coastguard Worker     case MAX_NUMBER_OF_OUTPUT_CHANNELS:
1742*e5436536SAndroid Build Coastguard Worker       switch (value) { /* supported output channels */
1743*e5436536SAndroid Build Coastguard Worker         case -1:
1744*e5436536SAndroid Build Coastguard Worker         case 0:
1745*e5436536SAndroid Build Coastguard Worker         case ONE_CHANNEL:
1746*e5436536SAndroid Build Coastguard Worker         case TWO_CHANNEL:
1747*e5436536SAndroid Build Coastguard Worker         case SIX_CHANNEL:
1748*e5436536SAndroid Build Coastguard Worker         case EIGHT_CHANNEL:
1749*e5436536SAndroid Build Coastguard Worker           break;
1750*e5436536SAndroid Build Coastguard Worker         default:
1751*e5436536SAndroid Build Coastguard Worker           return (PCMDMX_UNABLE_TO_SET_PARAM);
1752*e5436536SAndroid Build Coastguard Worker       }
1753*e5436536SAndroid Build Coastguard Worker       if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1754*e5436536SAndroid Build Coastguard Worker       /* Store the new value */
1755*e5436536SAndroid Build Coastguard Worker       self->userParams.numOutChannelsMax = (value > 0) ? (SHORT)value : -1;
1756*e5436536SAndroid Build Coastguard Worker       if ((value > 0) &&
1757*e5436536SAndroid Build Coastguard Worker           (value < self->userParams
1758*e5436536SAndroid Build Coastguard Worker                        .numOutChannelsMin)) { /* MAX < MIN would be an invalid
1759*e5436536SAndroid Build Coastguard Worker                                                  state. Thus set MIN = MAX in
1760*e5436536SAndroid Build Coastguard Worker                                                  this case. */
1761*e5436536SAndroid Build Coastguard Worker         self->userParams.numOutChannelsMin = self->userParams.numOutChannelsMax;
1762*e5436536SAndroid Build Coastguard Worker       }
1763*e5436536SAndroid Build Coastguard Worker       break;
1764*e5436536SAndroid Build Coastguard Worker 
1765*e5436536SAndroid Build Coastguard Worker     case DMX_DUAL_CHANNEL_MODE:
1766*e5436536SAndroid Build Coastguard Worker       switch ((DUAL_CHANNEL_MODE)value) {
1767*e5436536SAndroid Build Coastguard Worker         case STEREO_MODE:
1768*e5436536SAndroid Build Coastguard Worker         case CH1_MODE:
1769*e5436536SAndroid Build Coastguard Worker         case CH2_MODE:
1770*e5436536SAndroid Build Coastguard Worker         case MIXED_MODE:
1771*e5436536SAndroid Build Coastguard Worker           break;
1772*e5436536SAndroid Build Coastguard Worker         default:
1773*e5436536SAndroid Build Coastguard Worker           return (PCMDMX_UNABLE_TO_SET_PARAM);
1774*e5436536SAndroid Build Coastguard Worker       }
1775*e5436536SAndroid Build Coastguard Worker       if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1776*e5436536SAndroid Build Coastguard Worker       self->userParams.dualChannelMode = (DUAL_CHANNEL_MODE)value;
1777*e5436536SAndroid Build Coastguard Worker       self->applyProcessing = ((DUAL_CHANNEL_MODE)value != STEREO_MODE)
1778*e5436536SAndroid Build Coastguard Worker                                   ? 1
1779*e5436536SAndroid Build Coastguard Worker                                   : 0; /* Force processing if necessary. */
1780*e5436536SAndroid Build Coastguard Worker       break;
1781*e5436536SAndroid Build Coastguard Worker 
1782*e5436536SAndroid Build Coastguard Worker     case DMX_PSEUDO_SURROUND_MODE:
1783*e5436536SAndroid Build Coastguard Worker       switch ((PSEUDO_SURROUND_MODE)value) {
1784*e5436536SAndroid Build Coastguard Worker         case NEVER_DO_PS_DMX:
1785*e5436536SAndroid Build Coastguard Worker         case AUTO_PS_DMX:
1786*e5436536SAndroid Build Coastguard Worker         case FORCE_PS_DMX:
1787*e5436536SAndroid Build Coastguard Worker           break;
1788*e5436536SAndroid Build Coastguard Worker         default:
1789*e5436536SAndroid Build Coastguard Worker           return (PCMDMX_UNABLE_TO_SET_PARAM);
1790*e5436536SAndroid Build Coastguard Worker       }
1791*e5436536SAndroid Build Coastguard Worker       if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1792*e5436536SAndroid Build Coastguard Worker       self->userParams.pseudoSurrMode = (PSEUDO_SURROUND_MODE)value;
1793*e5436536SAndroid Build Coastguard Worker       break;
1794*e5436536SAndroid Build Coastguard Worker 
1795*e5436536SAndroid Build Coastguard Worker     default:
1796*e5436536SAndroid Build Coastguard Worker       return (PCMDMX_UNKNOWN_PARAM);
1797*e5436536SAndroid Build Coastguard Worker   }
1798*e5436536SAndroid Build Coastguard Worker 
1799*e5436536SAndroid Build Coastguard Worker   return (PCMDMX_OK);
1800*e5436536SAndroid Build Coastguard Worker }
1801*e5436536SAndroid Build Coastguard Worker 
1802*e5436536SAndroid Build Coastguard Worker /** Get one parameter value of one PCM downmix module instance.
1803*e5436536SAndroid Build Coastguard Worker  * @param [in] Handle of PCM downmix module instance.
1804*e5436536SAndroid Build Coastguard Worker  * @param [in] Parameter to be set.
1805*e5436536SAndroid Build Coastguard Worker  * @param [out] Pointer to buffer receiving the parameter value.
1806*e5436536SAndroid Build Coastguard Worker  * @returns Returns an error code.
1807*e5436536SAndroid Build Coastguard Worker  **/
pcmDmx_GetParam(HANDLE_PCM_DOWNMIX self,const PCMDMX_PARAM param,INT * const pValue)1808*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_GetParam(HANDLE_PCM_DOWNMIX self, const PCMDMX_PARAM param,
1809*e5436536SAndroid Build Coastguard Worker                              INT *const pValue) {
1810*e5436536SAndroid Build Coastguard Worker   PCM_DMX_USER_PARAMS *pUsrParams;
1811*e5436536SAndroid Build Coastguard Worker 
1812*e5436536SAndroid Build Coastguard Worker   if ((self == NULL) || (pValue == NULL)) {
1813*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_HANDLE);
1814*e5436536SAndroid Build Coastguard Worker   }
1815*e5436536SAndroid Build Coastguard Worker   pUsrParams = &self->userParams;
1816*e5436536SAndroid Build Coastguard Worker 
1817*e5436536SAndroid Build Coastguard Worker   switch (param) {
1818*e5436536SAndroid Build Coastguard Worker     case DMX_PROFILE_SETTING:
1819*e5436536SAndroid Build Coastguard Worker       *pValue = (INT)pUsrParams->dmxProfile;
1820*e5436536SAndroid Build Coastguard Worker       break;
1821*e5436536SAndroid Build Coastguard Worker     case DMX_BS_DATA_EXPIRY_FRAME:
1822*e5436536SAndroid Build Coastguard Worker       *pValue = (INT)pUsrParams->expiryFrame;
1823*e5436536SAndroid Build Coastguard Worker       break;
1824*e5436536SAndroid Build Coastguard Worker     case DMX_BS_DATA_DELAY:
1825*e5436536SAndroid Build Coastguard Worker       *pValue = (INT)pUsrParams->frameDelay;
1826*e5436536SAndroid Build Coastguard Worker       break;
1827*e5436536SAndroid Build Coastguard Worker     case MIN_NUMBER_OF_OUTPUT_CHANNELS:
1828*e5436536SAndroid Build Coastguard Worker       *pValue = (INT)pUsrParams->numOutChannelsMin;
1829*e5436536SAndroid Build Coastguard Worker       break;
1830*e5436536SAndroid Build Coastguard Worker     case MAX_NUMBER_OF_OUTPUT_CHANNELS:
1831*e5436536SAndroid Build Coastguard Worker       *pValue = (INT)pUsrParams->numOutChannelsMax;
1832*e5436536SAndroid Build Coastguard Worker       break;
1833*e5436536SAndroid Build Coastguard Worker     case DMX_DUAL_CHANNEL_MODE:
1834*e5436536SAndroid Build Coastguard Worker       *pValue = (INT)pUsrParams->dualChannelMode;
1835*e5436536SAndroid Build Coastguard Worker       break;
1836*e5436536SAndroid Build Coastguard Worker     case DMX_PSEUDO_SURROUND_MODE:
1837*e5436536SAndroid Build Coastguard Worker       *pValue = (INT)pUsrParams->pseudoSurrMode;
1838*e5436536SAndroid Build Coastguard Worker       break;
1839*e5436536SAndroid Build Coastguard Worker     default:
1840*e5436536SAndroid Build Coastguard Worker       return (PCMDMX_UNKNOWN_PARAM);
1841*e5436536SAndroid Build Coastguard Worker   }
1842*e5436536SAndroid Build Coastguard Worker 
1843*e5436536SAndroid Build Coastguard Worker   return (PCMDMX_OK);
1844*e5436536SAndroid Build Coastguard Worker }
1845*e5436536SAndroid Build Coastguard Worker 
1846*e5436536SAndroid Build Coastguard Worker /*
1847*e5436536SAndroid Build Coastguard Worker  * Read DMX meta-data from a data stream element.
1848*e5436536SAndroid Build Coastguard Worker  */
pcmDmx_Parse(HANDLE_PCM_DOWNMIX self,HANDLE_FDK_BITSTREAM hBs,UINT ancDataBits,int isMpeg2)1849*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_Parse(HANDLE_PCM_DOWNMIX self, HANDLE_FDK_BITSTREAM hBs,
1850*e5436536SAndroid Build Coastguard Worker                           UINT ancDataBits, int isMpeg2) {
1851*e5436536SAndroid Build Coastguard Worker   PCMDMX_ERROR errorStatus = PCMDMX_OK;
1852*e5436536SAndroid Build Coastguard Worker 
1853*e5436536SAndroid Build Coastguard Worker #define MAX_DSE_ANC_BYTES (16)    /* 15 bytes */
1854*e5436536SAndroid Build Coastguard Worker #define ANC_DATA_SYNC_BYTE (0xBC) /* ancillary data sync byte. */
1855*e5436536SAndroid Build Coastguard Worker 
1856*e5436536SAndroid Build Coastguard Worker   DMX_BS_META_DATA *pBsMetaData;
1857*e5436536SAndroid Build Coastguard Worker 
1858*e5436536SAndroid Build Coastguard Worker   int skip4Dmx = 0, skip4Ext = 0;
1859*e5436536SAndroid Build Coastguard Worker   int dmxLvlAvail = 0, extDataAvail = 0;
1860*e5436536SAndroid Build Coastguard Worker   UINT foundNewData = 0;
1861*e5436536SAndroid Build Coastguard Worker   UINT minAncBits = ((isMpeg2) ? 5 : 3) * 8;
1862*e5436536SAndroid Build Coastguard Worker 
1863*e5436536SAndroid Build Coastguard Worker   if ((self == NULL) || (hBs == NULL)) {
1864*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_HANDLE);
1865*e5436536SAndroid Build Coastguard Worker   }
1866*e5436536SAndroid Build Coastguard Worker 
1867*e5436536SAndroid Build Coastguard Worker   /* sanity checks */
1868*e5436536SAndroid Build Coastguard Worker   if ((ancDataBits < minAncBits) || (ancDataBits > FDKgetValidBits(hBs))) {
1869*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_CORRUPT_ANC_DATA);
1870*e5436536SAndroid Build Coastguard Worker   }
1871*e5436536SAndroid Build Coastguard Worker 
1872*e5436536SAndroid Build Coastguard Worker   pBsMetaData = &self->bsMetaData[0];
1873*e5436536SAndroid Build Coastguard Worker 
1874*e5436536SAndroid Build Coastguard Worker   if (isMpeg2) {
1875*e5436536SAndroid Build Coastguard Worker     /* skip DVD ancillary data */
1876*e5436536SAndroid Build Coastguard Worker     FDKpushFor(hBs, 16);
1877*e5436536SAndroid Build Coastguard Worker   }
1878*e5436536SAndroid Build Coastguard Worker 
1879*e5436536SAndroid Build Coastguard Worker   /* check sync word */
1880*e5436536SAndroid Build Coastguard Worker   if (FDKreadBits(hBs, 8) != ANC_DATA_SYNC_BYTE) {
1881*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_CORRUPT_ANC_DATA);
1882*e5436536SAndroid Build Coastguard Worker   }
1883*e5436536SAndroid Build Coastguard Worker 
1884*e5436536SAndroid Build Coastguard Worker   /* skip MPEG audio type and Dolby surround mode */
1885*e5436536SAndroid Build Coastguard Worker   FDKpushFor(hBs, 4);
1886*e5436536SAndroid Build Coastguard Worker 
1887*e5436536SAndroid Build Coastguard Worker   if (isMpeg2) {
1888*e5436536SAndroid Build Coastguard Worker     /* int numAncBytes = */ FDKreadBits(hBs, 4);
1889*e5436536SAndroid Build Coastguard Worker     /* advanced dynamic range control */
1890*e5436536SAndroid Build Coastguard Worker     if (FDKreadBit(hBs)) skip4Dmx += 24;
1891*e5436536SAndroid Build Coastguard Worker     /* dialog normalization */
1892*e5436536SAndroid Build Coastguard Worker     if (FDKreadBit(hBs)) skip4Dmx += 8;
1893*e5436536SAndroid Build Coastguard Worker     /* reproduction_level */
1894*e5436536SAndroid Build Coastguard Worker     if (FDKreadBit(hBs)) skip4Dmx += 8;
1895*e5436536SAndroid Build Coastguard Worker   } else {
1896*e5436536SAndroid Build Coastguard Worker     FDKpushFor(hBs, 2); /* drc presentation mode */
1897*e5436536SAndroid Build Coastguard Worker     pBsMetaData->pseudoSurround = (SCHAR)FDKreadBit(hBs);
1898*e5436536SAndroid Build Coastguard Worker     FDKpushFor(hBs, 4); /* reserved bits */
1899*e5436536SAndroid Build Coastguard Worker   }
1900*e5436536SAndroid Build Coastguard Worker 
1901*e5436536SAndroid Build Coastguard Worker   /* downmixing levels MPEGx status */
1902*e5436536SAndroid Build Coastguard Worker   dmxLvlAvail = FDKreadBit(hBs);
1903*e5436536SAndroid Build Coastguard Worker 
1904*e5436536SAndroid Build Coastguard Worker   if (isMpeg2) {
1905*e5436536SAndroid Build Coastguard Worker     /* scale factor CRC status */
1906*e5436536SAndroid Build Coastguard Worker     if (FDKreadBit(hBs)) skip4Ext += 16;
1907*e5436536SAndroid Build Coastguard Worker   } else {
1908*e5436536SAndroid Build Coastguard Worker     /* ancillary data extension status */
1909*e5436536SAndroid Build Coastguard Worker     extDataAvail = FDKreadBit(hBs);
1910*e5436536SAndroid Build Coastguard Worker   }
1911*e5436536SAndroid Build Coastguard Worker 
1912*e5436536SAndroid Build Coastguard Worker   /* audio coding and compression status */
1913*e5436536SAndroid Build Coastguard Worker   if (FDKreadBit(hBs)) skip4Ext += 16;
1914*e5436536SAndroid Build Coastguard Worker   /* coarse grain timecode status */
1915*e5436536SAndroid Build Coastguard Worker   if (FDKreadBit(hBs)) skip4Ext += 16;
1916*e5436536SAndroid Build Coastguard Worker   /* fine grain timecode status */
1917*e5436536SAndroid Build Coastguard Worker   if (FDKreadBit(hBs)) skip4Ext += 16;
1918*e5436536SAndroid Build Coastguard Worker 
1919*e5436536SAndroid Build Coastguard Worker   /* skip the useless data to get to the DMX levels */
1920*e5436536SAndroid Build Coastguard Worker   FDKpushFor(hBs, skip4Dmx);
1921*e5436536SAndroid Build Coastguard Worker 
1922*e5436536SAndroid Build Coastguard Worker   /* downmix_levels_MPEGX */
1923*e5436536SAndroid Build Coastguard Worker   if (dmxLvlAvail) {
1924*e5436536SAndroid Build Coastguard Worker     if (FDKreadBit(hBs)) { /* center_mix_level_on */
1925*e5436536SAndroid Build Coastguard Worker       pBsMetaData->cLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1926*e5436536SAndroid Build Coastguard Worker       foundNewData |= TYPE_DSE_CLEV_DATA;
1927*e5436536SAndroid Build Coastguard Worker     } else {
1928*e5436536SAndroid Build Coastguard Worker       FDKreadBits(hBs, 3);
1929*e5436536SAndroid Build Coastguard Worker     }
1930*e5436536SAndroid Build Coastguard Worker     if (FDKreadBit(hBs)) { /* surround_mix_level_on */
1931*e5436536SAndroid Build Coastguard Worker       pBsMetaData->sLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1932*e5436536SAndroid Build Coastguard Worker       foundNewData |= TYPE_DSE_SLEV_DATA;
1933*e5436536SAndroid Build Coastguard Worker     } else {
1934*e5436536SAndroid Build Coastguard Worker       FDKreadBits(hBs, 3);
1935*e5436536SAndroid Build Coastguard Worker     }
1936*e5436536SAndroid Build Coastguard Worker   }
1937*e5436536SAndroid Build Coastguard Worker 
1938*e5436536SAndroid Build Coastguard Worker   /* skip the useless data to get to the ancillary data extension */
1939*e5436536SAndroid Build Coastguard Worker   FDKpushFor(hBs, skip4Ext);
1940*e5436536SAndroid Build Coastguard Worker 
1941*e5436536SAndroid Build Coastguard Worker   /* anc data extension (MPEG-4 only) */
1942*e5436536SAndroid Build Coastguard Worker   if (extDataAvail) {
1943*e5436536SAndroid Build Coastguard Worker     int extDmxLvlSt, extDmxGainSt, extDmxLfeSt;
1944*e5436536SAndroid Build Coastguard Worker 
1945*e5436536SAndroid Build Coastguard Worker     FDKreadBit(hBs); /* reserved bit */
1946*e5436536SAndroid Build Coastguard Worker     extDmxLvlSt = FDKreadBit(hBs);
1947*e5436536SAndroid Build Coastguard Worker     extDmxGainSt = FDKreadBit(hBs);
1948*e5436536SAndroid Build Coastguard Worker     extDmxLfeSt = FDKreadBit(hBs);
1949*e5436536SAndroid Build Coastguard Worker     FDKreadBits(hBs, 4); /* reserved bits */
1950*e5436536SAndroid Build Coastguard Worker 
1951*e5436536SAndroid Build Coastguard Worker     if (extDmxLvlSt) {
1952*e5436536SAndroid Build Coastguard Worker       pBsMetaData->dmixIdxA = (UCHAR)FDKreadBits(hBs, 3);
1953*e5436536SAndroid Build Coastguard Worker       pBsMetaData->dmixIdxB = (UCHAR)FDKreadBits(hBs, 3);
1954*e5436536SAndroid Build Coastguard Worker       FDKreadBits(hBs, 2); /* reserved bits */
1955*e5436536SAndroid Build Coastguard Worker       foundNewData |= TYPE_DSE_DMIX_AB_DATA;
1956*e5436536SAndroid Build Coastguard Worker     }
1957*e5436536SAndroid Build Coastguard Worker     if (extDmxGainSt) {
1958*e5436536SAndroid Build Coastguard Worker       pBsMetaData->dmxGainIdx5 = (UCHAR)FDKreadBits(hBs, 7);
1959*e5436536SAndroid Build Coastguard Worker       FDKreadBit(hBs); /* reserved bit */
1960*e5436536SAndroid Build Coastguard Worker       pBsMetaData->dmxGainIdx2 = (UCHAR)FDKreadBits(hBs, 7);
1961*e5436536SAndroid Build Coastguard Worker       FDKreadBit(hBs); /* reserved bit */
1962*e5436536SAndroid Build Coastguard Worker       foundNewData |= TYPE_DSE_DMX_GAIN_DATA;
1963*e5436536SAndroid Build Coastguard Worker     }
1964*e5436536SAndroid Build Coastguard Worker     if (extDmxLfeSt) {
1965*e5436536SAndroid Build Coastguard Worker       pBsMetaData->dmixIdxLfe = (UCHAR)FDKreadBits(hBs, 4);
1966*e5436536SAndroid Build Coastguard Worker       FDKreadBits(hBs, 4); /* reserved bits */
1967*e5436536SAndroid Build Coastguard Worker       foundNewData |= TYPE_DSE_DMIX_LFE_DATA;
1968*e5436536SAndroid Build Coastguard Worker     }
1969*e5436536SAndroid Build Coastguard Worker   }
1970*e5436536SAndroid Build Coastguard Worker 
1971*e5436536SAndroid Build Coastguard Worker   /* final sanity check on the amount of read data */
1972*e5436536SAndroid Build Coastguard Worker   if ((INT)FDKgetValidBits(hBs) < 0) {
1973*e5436536SAndroid Build Coastguard Worker     errorStatus = PCMDMX_CORRUPT_ANC_DATA;
1974*e5436536SAndroid Build Coastguard Worker   }
1975*e5436536SAndroid Build Coastguard Worker 
1976*e5436536SAndroid Build Coastguard Worker   if ((errorStatus == PCMDMX_OK) && (foundNewData != 0)) {
1977*e5436536SAndroid Build Coastguard Worker     /* announce new data */
1978*e5436536SAndroid Build Coastguard Worker     pBsMetaData->typeFlags |= foundNewData;
1979*e5436536SAndroid Build Coastguard Worker     /* reset expiry counter */
1980*e5436536SAndroid Build Coastguard Worker     pBsMetaData->expiryCount = 0;
1981*e5436536SAndroid Build Coastguard Worker   }
1982*e5436536SAndroid Build Coastguard Worker 
1983*e5436536SAndroid Build Coastguard Worker   return (errorStatus);
1984*e5436536SAndroid Build Coastguard Worker }
1985*e5436536SAndroid Build Coastguard Worker 
1986*e5436536SAndroid Build Coastguard Worker /*
1987*e5436536SAndroid Build Coastguard Worker  * Read DMX meta-data from a data stream element.
1988*e5436536SAndroid Build Coastguard Worker  */
pcmDmx_ReadDvbAncData(HANDLE_PCM_DOWNMIX self,UCHAR * pAncDataBuf,UINT ancDataBytes,int isMpeg2)1989*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_ReadDvbAncData(HANDLE_PCM_DOWNMIX self, UCHAR *pAncDataBuf,
1990*e5436536SAndroid Build Coastguard Worker                                    UINT ancDataBytes, int isMpeg2) {
1991*e5436536SAndroid Build Coastguard Worker   PCMDMX_ERROR errorStatus = PCMDMX_OK;
1992*e5436536SAndroid Build Coastguard Worker   FDK_BITSTREAM bs;
1993*e5436536SAndroid Build Coastguard Worker   HANDLE_FDK_BITSTREAM hBs = &bs;
1994*e5436536SAndroid Build Coastguard Worker 
1995*e5436536SAndroid Build Coastguard Worker   if (self == NULL) {
1996*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_HANDLE);
1997*e5436536SAndroid Build Coastguard Worker   }
1998*e5436536SAndroid Build Coastguard Worker 
1999*e5436536SAndroid Build Coastguard Worker   /* sanity checks */
2000*e5436536SAndroid Build Coastguard Worker   if ((pAncDataBuf == NULL) || (ancDataBytes == 0)) {
2001*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_CORRUPT_ANC_DATA);
2002*e5436536SAndroid Build Coastguard Worker   }
2003*e5436536SAndroid Build Coastguard Worker 
2004*e5436536SAndroid Build Coastguard Worker   FDKinitBitStream(hBs, pAncDataBuf, MAX_DSE_ANC_BYTES, ancDataBytes * 8,
2005*e5436536SAndroid Build Coastguard Worker                    BS_READER);
2006*e5436536SAndroid Build Coastguard Worker 
2007*e5436536SAndroid Build Coastguard Worker   errorStatus = pcmDmx_Parse(self, hBs, ancDataBytes * 8, isMpeg2);
2008*e5436536SAndroid Build Coastguard Worker 
2009*e5436536SAndroid Build Coastguard Worker   return (errorStatus);
2010*e5436536SAndroid Build Coastguard Worker }
2011*e5436536SAndroid Build Coastguard Worker 
2012*e5436536SAndroid Build Coastguard Worker /** Set the matrix mixdown information extracted from the PCE of an AAC
2013*e5436536SAndroid Build Coastguard Worker  *bitstream. Note: Call only if matrix_mixdown_idx_present is true.
2014*e5436536SAndroid Build Coastguard Worker  * @param [in] Handle of PCM downmix module instance.
2015*e5436536SAndroid Build Coastguard Worker  * @param [in] The 2 bit matrix mixdown index extracted from PCE.
2016*e5436536SAndroid Build Coastguard Worker  * @param [in] The pseudo surround enable flag extracted from PCE.
2017*e5436536SAndroid Build Coastguard Worker  * @returns Returns an error code.
2018*e5436536SAndroid Build Coastguard Worker  **/
pcmDmx_SetMatrixMixdownFromPce(HANDLE_PCM_DOWNMIX self,int matrixMixdownPresent,int matrixMixdownIdx,int pseudoSurroundEnable)2019*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce(HANDLE_PCM_DOWNMIX self,
2020*e5436536SAndroid Build Coastguard Worker                                             int matrixMixdownPresent,
2021*e5436536SAndroid Build Coastguard Worker                                             int matrixMixdownIdx,
2022*e5436536SAndroid Build Coastguard Worker                                             int pseudoSurroundEnable) {
2023*e5436536SAndroid Build Coastguard Worker   if (self == NULL) {
2024*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_HANDLE);
2025*e5436536SAndroid Build Coastguard Worker   }
2026*e5436536SAndroid Build Coastguard Worker 
2027*e5436536SAndroid Build Coastguard Worker   {
2028*e5436536SAndroid Build Coastguard Worker     DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
2029*e5436536SAndroid Build Coastguard Worker 
2030*e5436536SAndroid Build Coastguard Worker     if (matrixMixdownPresent) {
2031*e5436536SAndroid Build Coastguard Worker       pBsMetaData->pseudoSurround = (pseudoSurroundEnable) ? 1 : 0;
2032*e5436536SAndroid Build Coastguard Worker       pBsMetaData->matrixMixdownIdx = matrixMixdownIdx & 0x03;
2033*e5436536SAndroid Build Coastguard Worker       pBsMetaData->typeFlags |= TYPE_PCE_DATA;
2034*e5436536SAndroid Build Coastguard Worker       /* Reset expiry counter */
2035*e5436536SAndroid Build Coastguard Worker       pBsMetaData->expiryCount = 0;
2036*e5436536SAndroid Build Coastguard Worker     }
2037*e5436536SAndroid Build Coastguard Worker   }
2038*e5436536SAndroid Build Coastguard Worker 
2039*e5436536SAndroid Build Coastguard Worker   return (PCMDMX_OK);
2040*e5436536SAndroid Build Coastguard Worker }
2041*e5436536SAndroid Build Coastguard Worker 
2042*e5436536SAndroid Build Coastguard Worker /** Apply down or up mixing.
2043*e5436536SAndroid Build Coastguard Worker  * @param [in]    Handle of PCM downmix module instance.
2044*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to buffer that hold the time domain signal.
2045*e5436536SAndroid Build Coastguard Worker  * @param [in]    Pointer where the amount of output samples is returned into.
2046*e5436536SAndroid Build Coastguard Worker  * @param [in]    Size of pPcmBuf.
2047*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer where the amount of output channels is returned into.
2048*e5436536SAndroid Build Coastguard Worker  * @param [in]    Input and output samples are processed interleaved.
2049*e5436536SAndroid Build Coastguard Worker  * @param [inout] Array where the corresponding channel type for each output
2050*e5436536SAndroid Build Coastguard Worker  *audio channel is stored into.
2051*e5436536SAndroid Build Coastguard Worker  * @param [inout] Array where the corresponding channel type index for each
2052*e5436536SAndroid Build Coastguard Worker  *output audio channel is stored into.
2053*e5436536SAndroid Build Coastguard Worker  * @param [in]    Array containing the out channel mapping to be used (From MPEG
2054*e5436536SAndroid Build Coastguard Worker  *PCE ordering to whatever is required).
2055*e5436536SAndroid Build Coastguard Worker  * @param [out]   Pointer on a field receiving the scale factor that has to be
2056*e5436536SAndroid Build Coastguard Worker  *applied on all samples afterwards. If the handed pointer is NULL scaling is
2057*e5436536SAndroid Build Coastguard Worker  *done internally.
2058*e5436536SAndroid Build Coastguard Worker  * @returns Returns an error code.
2059*e5436536SAndroid Build Coastguard Worker  **/
pcmDmx_ApplyFrame(HANDLE_PCM_DOWNMIX self,DMX_PCM * pPcmBuf,const int pcmBufSize,UINT frameSize,INT * nChannels,INT fInterleaved,AUDIO_CHANNEL_TYPE channelType[],UCHAR channelIndices[],const FDK_channelMapDescr * const mapDescr,INT * pDmxOutScale)2060*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_ApplyFrame(HANDLE_PCM_DOWNMIX self, DMX_PCM *pPcmBuf,
2061*e5436536SAndroid Build Coastguard Worker                                const int pcmBufSize, UINT frameSize,
2062*e5436536SAndroid Build Coastguard Worker                                INT *nChannels, INT fInterleaved,
2063*e5436536SAndroid Build Coastguard Worker                                AUDIO_CHANNEL_TYPE channelType[],
2064*e5436536SAndroid Build Coastguard Worker                                UCHAR channelIndices[],
2065*e5436536SAndroid Build Coastguard Worker                                const FDK_channelMapDescr *const mapDescr,
2066*e5436536SAndroid Build Coastguard Worker                                INT *pDmxOutScale) {
2067*e5436536SAndroid Build Coastguard Worker   PCM_DMX_USER_PARAMS *pParam = NULL;
2068*e5436536SAndroid Build Coastguard Worker   PCMDMX_ERROR errorStatus = PCMDMX_OK;
2069*e5436536SAndroid Build Coastguard Worker   DUAL_CHANNEL_MODE dualChannelMode;
2070*e5436536SAndroid Build Coastguard Worker   PCM_DMX_CHANNEL_MODE inChMode;
2071*e5436536SAndroid Build Coastguard Worker   PCM_DMX_CHANNEL_MODE outChMode;
2072*e5436536SAndroid Build Coastguard Worker   INT devNull; /* Just a dummy to avoid a lot of branches in the code */
2073*e5436536SAndroid Build Coastguard Worker   int numOutChannels, numInChannels;
2074*e5436536SAndroid Build Coastguard Worker   int inStride, outStride, offset;
2075*e5436536SAndroid Build Coastguard Worker   int dmxMaxScale, dmxScale;
2076*e5436536SAndroid Build Coastguard Worker   int slot;
2077*e5436536SAndroid Build Coastguard Worker   UCHAR inOffsetTable[(8)];
2078*e5436536SAndroid Build Coastguard Worker 
2079*e5436536SAndroid Build Coastguard Worker   DMX_BS_META_DATA bsMetaData;
2080*e5436536SAndroid Build Coastguard Worker 
2081*e5436536SAndroid Build Coastguard Worker   if ((self == NULL) || (nChannels == NULL) || (channelType == NULL) ||
2082*e5436536SAndroid Build Coastguard Worker       (channelIndices == NULL) || (!FDK_chMapDescr_isValid(mapDescr))) {
2083*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_HANDLE);
2084*e5436536SAndroid Build Coastguard Worker   }
2085*e5436536SAndroid Build Coastguard Worker 
2086*e5436536SAndroid Build Coastguard Worker   /* Init the output scaling */
2087*e5436536SAndroid Build Coastguard Worker   dmxScale = 0;
2088*e5436536SAndroid Build Coastguard Worker   if (pDmxOutScale != NULL) {
2089*e5436536SAndroid Build Coastguard Worker     /* Avoid final scaling internally and hand it to the outside world. */
2090*e5436536SAndroid Build Coastguard Worker     *pDmxOutScale = 0;
2091*e5436536SAndroid Build Coastguard Worker     dmxMaxScale = (3);
2092*e5436536SAndroid Build Coastguard Worker   } else {
2093*e5436536SAndroid Build Coastguard Worker     /* Apply the scaling internally. */
2094*e5436536SAndroid Build Coastguard Worker     pDmxOutScale = &devNull; /* redirect to temporal stack memory */
2095*e5436536SAndroid Build Coastguard Worker     dmxMaxScale = 0;
2096*e5436536SAndroid Build Coastguard Worker   }
2097*e5436536SAndroid Build Coastguard Worker 
2098*e5436536SAndroid Build Coastguard Worker   pParam = &self->userParams;
2099*e5436536SAndroid Build Coastguard Worker   numInChannels = *nChannels;
2100*e5436536SAndroid Build Coastguard Worker 
2101*e5436536SAndroid Build Coastguard Worker   /* Perform some input sanity checks */
2102*e5436536SAndroid Build Coastguard Worker   if (pPcmBuf == NULL) {
2103*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_ARGUMENT);
2104*e5436536SAndroid Build Coastguard Worker   }
2105*e5436536SAndroid Build Coastguard Worker   if (frameSize == 0) {
2106*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_ARGUMENT);
2107*e5436536SAndroid Build Coastguard Worker   }
2108*e5436536SAndroid Build Coastguard Worker   if (numInChannels == 0) {
2109*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_ARGUMENT);
2110*e5436536SAndroid Build Coastguard Worker   }
2111*e5436536SAndroid Build Coastguard Worker   if (numInChannels > (8)) {
2112*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_CH_CONFIG);
2113*e5436536SAndroid Build Coastguard Worker   }
2114*e5436536SAndroid Build Coastguard Worker 
2115*e5436536SAndroid Build Coastguard Worker   /* Check on misconfiguration */
2116*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT((pParam->numOutChannelsMax <= 0) ||
2117*e5436536SAndroid Build Coastguard Worker              (pParam->numOutChannelsMax >= pParam->numOutChannelsMin));
2118*e5436536SAndroid Build Coastguard Worker 
2119*e5436536SAndroid Build Coastguard Worker   /* Determine if the module has to do processing */
2120*e5436536SAndroid Build Coastguard Worker   if ((self->applyProcessing == 0) &&
2121*e5436536SAndroid Build Coastguard Worker       ((pParam->numOutChannelsMax <= 0) ||
2122*e5436536SAndroid Build Coastguard Worker        (pParam->numOutChannelsMax >= numInChannels)) &&
2123*e5436536SAndroid Build Coastguard Worker       (pParam->numOutChannelsMin <= numInChannels)) {
2124*e5436536SAndroid Build Coastguard Worker     /* Nothing to do */
2125*e5436536SAndroid Build Coastguard Worker     return (errorStatus);
2126*e5436536SAndroid Build Coastguard Worker   }
2127*e5436536SAndroid Build Coastguard Worker 
2128*e5436536SAndroid Build Coastguard Worker   /* Determine the number of output channels */
2129*e5436536SAndroid Build Coastguard Worker   if ((pParam->numOutChannelsMax > 0) &&
2130*e5436536SAndroid Build Coastguard Worker       (numInChannels > pParam->numOutChannelsMax)) {
2131*e5436536SAndroid Build Coastguard Worker     numOutChannels = pParam->numOutChannelsMax;
2132*e5436536SAndroid Build Coastguard Worker   } else if (numInChannels < pParam->numOutChannelsMin) {
2133*e5436536SAndroid Build Coastguard Worker     numOutChannels = pParam->numOutChannelsMin;
2134*e5436536SAndroid Build Coastguard Worker   } else {
2135*e5436536SAndroid Build Coastguard Worker     numOutChannels = numInChannels;
2136*e5436536SAndroid Build Coastguard Worker   }
2137*e5436536SAndroid Build Coastguard Worker 
2138*e5436536SAndroid Build Coastguard Worker   /* Check I/O buffer size */
2139*e5436536SAndroid Build Coastguard Worker   if ((UINT)pcmBufSize < (UINT)numOutChannels * frameSize) {
2140*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_OUTPUT_BUFFER_TOO_SMALL);
2141*e5436536SAndroid Build Coastguard Worker   }
2142*e5436536SAndroid Build Coastguard Worker 
2143*e5436536SAndroid Build Coastguard Worker   dualChannelMode = pParam->dualChannelMode;
2144*e5436536SAndroid Build Coastguard Worker 
2145*e5436536SAndroid Build Coastguard Worker   /* Analyse input channel configuration and get channel offset
2146*e5436536SAndroid Build Coastguard Worker    * table that can be accessed with the fixed channel labels. */
2147*e5436536SAndroid Build Coastguard Worker   errorStatus = getChannelMode(numInChannels, channelType, channelIndices,
2148*e5436536SAndroid Build Coastguard Worker                                inOffsetTable, &inChMode);
2149*e5436536SAndroid Build Coastguard Worker   if (PCMDMX_IS_FATAL_ERROR(errorStatus) || (inChMode == CH_MODE_UNDEFINED)) {
2150*e5436536SAndroid Build Coastguard Worker     /* We don't need to restore because the channel
2151*e5436536SAndroid Build Coastguard Worker        configuration has not been changed. Just exit. */
2152*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_CH_CONFIG);
2153*e5436536SAndroid Build Coastguard Worker   }
2154*e5436536SAndroid Build Coastguard Worker 
2155*e5436536SAndroid Build Coastguard Worker   /* Set input stride and offset */
2156*e5436536SAndroid Build Coastguard Worker   if (fInterleaved) {
2157*e5436536SAndroid Build Coastguard Worker     inStride = numInChannels;
2158*e5436536SAndroid Build Coastguard Worker     offset = 1; /* Channel specific offset factor */
2159*e5436536SAndroid Build Coastguard Worker   } else {
2160*e5436536SAndroid Build Coastguard Worker     inStride = 1;
2161*e5436536SAndroid Build Coastguard Worker     offset = frameSize; /* Channel specific offset factor */
2162*e5436536SAndroid Build Coastguard Worker   }
2163*e5436536SAndroid Build Coastguard Worker 
2164*e5436536SAndroid Build Coastguard Worker   /* Reset downmix meta data if necessary */
2165*e5436536SAndroid Build Coastguard Worker   if ((pParam->expiryFrame > 0) &&
2166*e5436536SAndroid Build Coastguard Worker       (++self->bsMetaData[0].expiryCount >
2167*e5436536SAndroid Build Coastguard Worker        pParam
2168*e5436536SAndroid Build Coastguard Worker            ->expiryFrame)) { /* The metadata read from bitstream is too old. */
2169*e5436536SAndroid Build Coastguard Worker #ifdef FDK_ASSERT_ENABLE
2170*e5436536SAndroid Build Coastguard Worker     PCMDMX_ERROR err = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
2171*e5436536SAndroid Build Coastguard Worker     FDK_ASSERT(err == PCMDMX_OK);
2172*e5436536SAndroid Build Coastguard Worker #else
2173*e5436536SAndroid Build Coastguard Worker     pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
2174*e5436536SAndroid Build Coastguard Worker #endif
2175*e5436536SAndroid Build Coastguard Worker   }
2176*e5436536SAndroid Build Coastguard Worker   FDKmemcpy(&bsMetaData, &self->bsMetaData[pParam->frameDelay],
2177*e5436536SAndroid Build Coastguard Worker             sizeof(DMX_BS_META_DATA));
2178*e5436536SAndroid Build Coastguard Worker   /* Maintain delay line */
2179*e5436536SAndroid Build Coastguard Worker   for (slot = pParam->frameDelay; slot > 0; slot -= 1) {
2180*e5436536SAndroid Build Coastguard Worker     FDKmemcpy(&self->bsMetaData[slot], &self->bsMetaData[slot - 1],
2181*e5436536SAndroid Build Coastguard Worker               sizeof(DMX_BS_META_DATA));
2182*e5436536SAndroid Build Coastguard Worker   }
2183*e5436536SAndroid Build Coastguard Worker 
2184*e5436536SAndroid Build Coastguard Worker   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2185*e5436536SAndroid Build Coastguard Worker    * - - - - - - - - - - - - - - - - - - */
2186*e5436536SAndroid Build Coastguard Worker   if (numInChannels > numOutChannels) { /* Apply downmix */
2187*e5436536SAndroid Build Coastguard Worker     DMX_PCM *pInPcm[(8)] = {NULL};
2188*e5436536SAndroid Build Coastguard Worker     DMX_PCM *pOutPcm[(8)] = {NULL};
2189*e5436536SAndroid Build Coastguard Worker     FIXP_DMX mixFactors[(8)][(8)];
2190*e5436536SAndroid Build Coastguard Worker     UCHAR outOffsetTable[(8)];
2191*e5436536SAndroid Build Coastguard Worker     UINT sample;
2192*e5436536SAndroid Build Coastguard Worker     int chCfg = 0;
2193*e5436536SAndroid Build Coastguard Worker     int bypScale = 0;
2194*e5436536SAndroid Build Coastguard Worker 
2195*e5436536SAndroid Build Coastguard Worker     if (numInChannels > SIX_CHANNEL) {
2196*e5436536SAndroid Build Coastguard Worker       AUDIO_CHANNEL_TYPE multiPurposeChType[2];
2197*e5436536SAndroid Build Coastguard Worker 
2198*e5436536SAndroid Build Coastguard Worker       /* Get the type of the multipurpose channels */
2199*e5436536SAndroid Build Coastguard Worker       multiPurposeChType[0] =
2200*e5436536SAndroid Build Coastguard Worker           channelType[inOffsetTable[LEFT_MULTIPRPS_CHANNEL]];
2201*e5436536SAndroid Build Coastguard Worker       multiPurposeChType[1] =
2202*e5436536SAndroid Build Coastguard Worker           channelType[inOffsetTable[RIGHT_MULTIPRPS_CHANNEL]];
2203*e5436536SAndroid Build Coastguard Worker 
2204*e5436536SAndroid Build Coastguard Worker       /* Check if the input configuration is one defined in the standard. */
2205*e5436536SAndroid Build Coastguard Worker       switch (inChMode) {
2206*e5436536SAndroid Build Coastguard Worker         case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
2207*e5436536SAndroid Build Coastguard Worker           /* Further analyse the input config to distinguish the two
2208*e5436536SAndroid Build Coastguard Worker            * CH_MODE_5_0_2_1 configs. */
2209*e5436536SAndroid Build Coastguard Worker           if ((multiPurposeChType[0] == ACT_FRONT_TOP) &&
2210*e5436536SAndroid Build Coastguard Worker               (multiPurposeChType[1] == ACT_FRONT_TOP)) {
2211*e5436536SAndroid Build Coastguard Worker             chCfg = 14;
2212*e5436536SAndroid Build Coastguard Worker           } else {
2213*e5436536SAndroid Build Coastguard Worker             chCfg = 7;
2214*e5436536SAndroid Build Coastguard Worker           }
2215*e5436536SAndroid Build Coastguard Worker           break;
2216*e5436536SAndroid Build Coastguard Worker         case CH_MODE_3_0_3_1: /* chCfg 11 */
2217*e5436536SAndroid Build Coastguard Worker           chCfg = 11;
2218*e5436536SAndroid Build Coastguard Worker           break;
2219*e5436536SAndroid Build Coastguard Worker         case CH_MODE_3_0_4_1: /* chCfg 12 */
2220*e5436536SAndroid Build Coastguard Worker           chCfg = 12;
2221*e5436536SAndroid Build Coastguard Worker           break;
2222*e5436536SAndroid Build Coastguard Worker         default:
2223*e5436536SAndroid Build Coastguard Worker           chCfg = 0; /* Not a known config */
2224*e5436536SAndroid Build Coastguard Worker           break;
2225*e5436536SAndroid Build Coastguard Worker       }
2226*e5436536SAndroid Build Coastguard Worker     }
2227*e5436536SAndroid Build Coastguard Worker 
2228*e5436536SAndroid Build Coastguard Worker     /* Set this stages output stride and channel mode: */
2229*e5436536SAndroid Build Coastguard Worker     outStride = (fInterleaved) ? numOutChannels : 1;
2230*e5436536SAndroid Build Coastguard Worker     outChMode = outChModeTable[numOutChannels];
2231*e5436536SAndroid Build Coastguard Worker     FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
2232*e5436536SAndroid Build Coastguard Worker 
2233*e5436536SAndroid Build Coastguard Worker     /* Get channel description and channel mapping for the desired output
2234*e5436536SAndroid Build Coastguard Worker      * configuration. */
2235*e5436536SAndroid Build Coastguard Worker     getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2236*e5436536SAndroid Build Coastguard Worker                           outOffsetTable);
2237*e5436536SAndroid Build Coastguard Worker     /* Now there is no way back because we modified the channel configuration!
2238*e5436536SAndroid Build Coastguard Worker      */
2239*e5436536SAndroid Build Coastguard Worker 
2240*e5436536SAndroid Build Coastguard Worker     /* Create the DMX matrix */
2241*e5436536SAndroid Build Coastguard Worker     errorStatus =
2242*e5436536SAndroid Build Coastguard Worker         getMixFactors((chCfg > 0) ? 1 : 0,
2243*e5436536SAndroid Build Coastguard Worker                       (chCfg > 0) ? (PCM_DMX_CHANNEL_MODE)chCfg : inChMode,
2244*e5436536SAndroid Build Coastguard Worker                       outChMode, pParam, &bsMetaData, mixFactors, &dmxScale);
2245*e5436536SAndroid Build Coastguard Worker     /* No fatal errors can occur here. The function is designed to always return
2246*e5436536SAndroid Build Coastguard Worker        a valid matrix. The error code is used to signal configurations and
2247*e5436536SAndroid Build Coastguard Worker        matrices that are not conform to any standard. */
2248*e5436536SAndroid Build Coastguard Worker 
2249*e5436536SAndroid Build Coastguard Worker     /* Determine the final scaling */
2250*e5436536SAndroid Build Coastguard Worker     bypScale = fMin(dmxMaxScale, dmxScale);
2251*e5436536SAndroid Build Coastguard Worker     *pDmxOutScale += bypScale;
2252*e5436536SAndroid Build Coastguard Worker     dmxScale -= bypScale;
2253*e5436536SAndroid Build Coastguard Worker 
2254*e5436536SAndroid Build Coastguard Worker     { /* Set channel pointer for input. Remove empty cols. */
2255*e5436536SAndroid Build Coastguard Worker       int inCh, outCh, map[(8)];
2256*e5436536SAndroid Build Coastguard Worker       int ch = 0;
2257*e5436536SAndroid Build Coastguard Worker       for (inCh = 0; inCh < (8); inCh += 1) {
2258*e5436536SAndroid Build Coastguard Worker         if (inOffsetTable[inCh] < (UCHAR)numInChannels) {
2259*e5436536SAndroid Build Coastguard Worker           pInPcm[ch] = &pPcmBuf[inOffsetTable[inCh] * offset];
2260*e5436536SAndroid Build Coastguard Worker           map[ch++] = inCh;
2261*e5436536SAndroid Build Coastguard Worker         }
2262*e5436536SAndroid Build Coastguard Worker       }
2263*e5436536SAndroid Build Coastguard Worker       for (; ch < (8); ch += 1) {
2264*e5436536SAndroid Build Coastguard Worker         map[ch] = ch;
2265*e5436536SAndroid Build Coastguard Worker       }
2266*e5436536SAndroid Build Coastguard Worker 
2267*e5436536SAndroid Build Coastguard Worker       /* Remove unused cols from factor matrix */
2268*e5436536SAndroid Build Coastguard Worker       for (inCh = 0; inCh < numInChannels; inCh += 1) {
2269*e5436536SAndroid Build Coastguard Worker         if (inCh != map[inCh]) {
2270*e5436536SAndroid Build Coastguard Worker           for (outCh = 0; outCh < (8); outCh += 1) {
2271*e5436536SAndroid Build Coastguard Worker             mixFactors[outCh][inCh] = mixFactors[outCh][map[inCh]];
2272*e5436536SAndroid Build Coastguard Worker           }
2273*e5436536SAndroid Build Coastguard Worker         }
2274*e5436536SAndroid Build Coastguard Worker       }
2275*e5436536SAndroid Build Coastguard Worker 
2276*e5436536SAndroid Build Coastguard Worker       /* Set channel pointer for output. Remove empty cols. */
2277*e5436536SAndroid Build Coastguard Worker       ch = 0;
2278*e5436536SAndroid Build Coastguard Worker       for (outCh = 0; outCh < (8); outCh += 1) {
2279*e5436536SAndroid Build Coastguard Worker         if (outOffsetTable[outCh] < (UCHAR)numOutChannels) {
2280*e5436536SAndroid Build Coastguard Worker           pOutPcm[ch] = &pPcmBuf[outOffsetTable[outCh] * offset];
2281*e5436536SAndroid Build Coastguard Worker           map[ch++] = outCh;
2282*e5436536SAndroid Build Coastguard Worker         }
2283*e5436536SAndroid Build Coastguard Worker       }
2284*e5436536SAndroid Build Coastguard Worker       for (; ch < (8); ch += 1) {
2285*e5436536SAndroid Build Coastguard Worker         map[ch] = ch;
2286*e5436536SAndroid Build Coastguard Worker       }
2287*e5436536SAndroid Build Coastguard Worker 
2288*e5436536SAndroid Build Coastguard Worker       /* Remove unused rows from factor matrix */
2289*e5436536SAndroid Build Coastguard Worker       for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2290*e5436536SAndroid Build Coastguard Worker         if (outCh != map[outCh]) {
2291*e5436536SAndroid Build Coastguard Worker           FDKmemcpy(&mixFactors[outCh], &mixFactors[map[outCh]],
2292*e5436536SAndroid Build Coastguard Worker                     (8) * sizeof(FIXP_DMX));
2293*e5436536SAndroid Build Coastguard Worker         }
2294*e5436536SAndroid Build Coastguard Worker       }
2295*e5436536SAndroid Build Coastguard Worker     }
2296*e5436536SAndroid Build Coastguard Worker 
2297*e5436536SAndroid Build Coastguard Worker     /* Sample processing loop */
2298*e5436536SAndroid Build Coastguard Worker     for (sample = 0; sample < frameSize; sample++) {
2299*e5436536SAndroid Build Coastguard Worker       DMX_PCM tIn[(8)] = {0};
2300*e5436536SAndroid Build Coastguard Worker       FIXP_DBL tOut[(8)] = {(FIXP_DBL)0};
2301*e5436536SAndroid Build Coastguard Worker       int inCh, outCh;
2302*e5436536SAndroid Build Coastguard Worker 
2303*e5436536SAndroid Build Coastguard Worker       /* Preload all input samples */
2304*e5436536SAndroid Build Coastguard Worker       for (inCh = 0; inCh < numInChannels; inCh += 1) {
2305*e5436536SAndroid Build Coastguard Worker         if (pInPcm[inCh] != NULL) {
2306*e5436536SAndroid Build Coastguard Worker           tIn[inCh] = *pInPcm[inCh];
2307*e5436536SAndroid Build Coastguard Worker           pInPcm[inCh] += inStride;
2308*e5436536SAndroid Build Coastguard Worker         } else {
2309*e5436536SAndroid Build Coastguard Worker           tIn[inCh] = (DMX_PCM)0;
2310*e5436536SAndroid Build Coastguard Worker         }
2311*e5436536SAndroid Build Coastguard Worker       }
2312*e5436536SAndroid Build Coastguard Worker       /* Apply downmix coefficients to input samples and accumulate for output
2313*e5436536SAndroid Build Coastguard Worker        */
2314*e5436536SAndroid Build Coastguard Worker       for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2315*e5436536SAndroid Build Coastguard Worker         for (inCh = 0; inCh < numInChannels; inCh += 1) {
2316*e5436536SAndroid Build Coastguard Worker           tOut[outCh] += fMult((DMX_PCMF)tIn[inCh], mixFactors[outCh][inCh]);
2317*e5436536SAndroid Build Coastguard Worker         }
2318*e5436536SAndroid Build Coastguard Worker         FDK_ASSERT(pOutPcm[outCh] >= pPcmBuf);
2319*e5436536SAndroid Build Coastguard Worker         FDK_ASSERT(pOutPcm[outCh] < &pPcmBuf[pcmBufSize]);
2320*e5436536SAndroid Build Coastguard Worker         /* Write sample */
2321*e5436536SAndroid Build Coastguard Worker         *pOutPcm[outCh] = (DMX_PCM)SATURATE_SHIFT(
2322*e5436536SAndroid Build Coastguard Worker             tOut[outCh], DFRACT_BITS - DMX_PCM_BITS - dmxScale, DMX_PCM_BITS);
2323*e5436536SAndroid Build Coastguard Worker         pOutPcm[outCh] += outStride;
2324*e5436536SAndroid Build Coastguard Worker       }
2325*e5436536SAndroid Build Coastguard Worker     }
2326*e5436536SAndroid Build Coastguard Worker 
2327*e5436536SAndroid Build Coastguard Worker     /* Update the number of output channels */
2328*e5436536SAndroid Build Coastguard Worker     *nChannels = numOutChannels;
2329*e5436536SAndroid Build Coastguard Worker 
2330*e5436536SAndroid Build Coastguard Worker   } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2331*e5436536SAndroid Build Coastguard Worker        - - - - - - - - - - - - - - - - - - */
2332*e5436536SAndroid Build Coastguard Worker   else if (numInChannels < numOutChannels) { /* Apply rudimentary upmix */
2333*e5436536SAndroid Build Coastguard Worker     /* Set up channel pointer */
2334*e5436536SAndroid Build Coastguard Worker     UCHAR outOffsetTable[(8)];
2335*e5436536SAndroid Build Coastguard Worker 
2336*e5436536SAndroid Build Coastguard Worker     /* FIRST STAGE
2337*e5436536SAndroid Build Coastguard Worker          Create a stereo/dual channel signal */
2338*e5436536SAndroid Build Coastguard Worker     if (numInChannels == ONE_CHANNEL) {
2339*e5436536SAndroid Build Coastguard Worker       DMX_PCM *pInPcm[(8)];
2340*e5436536SAndroid Build Coastguard Worker       DMX_PCM *pOutLF, *pOutRF;
2341*e5436536SAndroid Build Coastguard Worker       UINT sample;
2342*e5436536SAndroid Build Coastguard Worker 
2343*e5436536SAndroid Build Coastguard Worker       /* Set this stages output stride and channel mode: */
2344*e5436536SAndroid Build Coastguard Worker       outStride = (fInterleaved) ? TWO_CHANNEL : 1;
2345*e5436536SAndroid Build Coastguard Worker       outChMode = outChModeTable[TWO_CHANNEL];
2346*e5436536SAndroid Build Coastguard Worker 
2347*e5436536SAndroid Build Coastguard Worker       /* Get channel description and channel mapping for this
2348*e5436536SAndroid Build Coastguard Worker        * stages number of output channels (always STEREO). */
2349*e5436536SAndroid Build Coastguard Worker       getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2350*e5436536SAndroid Build Coastguard Worker                             outOffsetTable);
2351*e5436536SAndroid Build Coastguard Worker       /* Now there is no way back because we modified the channel configuration!
2352*e5436536SAndroid Build Coastguard Worker        */
2353*e5436536SAndroid Build Coastguard Worker 
2354*e5436536SAndroid Build Coastguard Worker       /* Set input channel pointer. The first channel is always at index 0. */
2355*e5436536SAndroid Build Coastguard Worker       pInPcm[CENTER_FRONT_CHANNEL] =
2356*e5436536SAndroid Build Coastguard Worker           &pPcmBuf[(frameSize - 1) *
2357*e5436536SAndroid Build Coastguard Worker                    inStride]; /* Considering input mapping could lead to a
2358*e5436536SAndroid Build Coastguard Worker                                  invalid pointer here if the channel is not
2359*e5436536SAndroid Build Coastguard Worker                                  declared to be a front channel. */
2360*e5436536SAndroid Build Coastguard Worker 
2361*e5436536SAndroid Build Coastguard Worker       /* Set output channel pointer (for this stage). */
2362*e5436536SAndroid Build Coastguard Worker       pOutLF = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL] * offset +
2363*e5436536SAndroid Build Coastguard Worker                         (frameSize - 1) * outStride];
2364*e5436536SAndroid Build Coastguard Worker       pOutRF = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL] * offset +
2365*e5436536SAndroid Build Coastguard Worker                         (frameSize - 1) * outStride];
2366*e5436536SAndroid Build Coastguard Worker 
2367*e5436536SAndroid Build Coastguard Worker       /* 1/0 input: */
2368*e5436536SAndroid Build Coastguard Worker       for (sample = 0; sample < frameSize; sample++) {
2369*e5436536SAndroid Build Coastguard Worker         /* L' = C;  R' = C; */
2370*e5436536SAndroid Build Coastguard Worker         *pOutLF = *pOutRF = *pInPcm[CENTER_FRONT_CHANNEL];
2371*e5436536SAndroid Build Coastguard Worker 
2372*e5436536SAndroid Build Coastguard Worker         pInPcm[CENTER_FRONT_CHANNEL] -= inStride;
2373*e5436536SAndroid Build Coastguard Worker         pOutLF -= outStride;
2374*e5436536SAndroid Build Coastguard Worker         pOutRF -= outStride;
2375*e5436536SAndroid Build Coastguard Worker       }
2376*e5436536SAndroid Build Coastguard Worker 
2377*e5436536SAndroid Build Coastguard Worker       /* Prepare for next stage: */
2378*e5436536SAndroid Build Coastguard Worker       inStride = outStride;
2379*e5436536SAndroid Build Coastguard Worker       inChMode = outChMode;
2380*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(inOffsetTable, outOffsetTable, (8) * sizeof(UCHAR));
2381*e5436536SAndroid Build Coastguard Worker     }
2382*e5436536SAndroid Build Coastguard Worker 
2383*e5436536SAndroid Build Coastguard Worker     /* SECOND STAGE
2384*e5436536SAndroid Build Coastguard Worker          Extend with zero channels to achieved the desired number of output
2385*e5436536SAndroid Build Coastguard Worker        channels. */
2386*e5436536SAndroid Build Coastguard Worker     if (numOutChannels > TWO_CHANNEL) {
2387*e5436536SAndroid Build Coastguard Worker       DMX_PCM *pIn[(8)] = {NULL};
2388*e5436536SAndroid Build Coastguard Worker       DMX_PCM *pOut[(8)] = {NULL};
2389*e5436536SAndroid Build Coastguard Worker       UINT sample;
2390*e5436536SAndroid Build Coastguard Worker       AUDIO_CHANNEL_TYPE inChTypes[(8)];
2391*e5436536SAndroid Build Coastguard Worker       UCHAR inChIndices[(8)];
2392*e5436536SAndroid Build Coastguard Worker       UCHAR numChPerGrp[2][(4)];
2393*e5436536SAndroid Build Coastguard Worker       int nContentCh = 0; /* Number of channels with content */
2394*e5436536SAndroid Build Coastguard Worker       int nEmptyCh = 0;   /* Number of channels with content */
2395*e5436536SAndroid Build Coastguard Worker       int ch, chGrp, isCompatible = 1;
2396*e5436536SAndroid Build Coastguard Worker 
2397*e5436536SAndroid Build Coastguard Worker       /* Do not change the signalling which is the channel types and indices.
2398*e5436536SAndroid Build Coastguard Worker          Just reorder and add channels. So first save the input signalling. */
2399*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(inChTypes, channelType,
2400*e5436536SAndroid Build Coastguard Worker                 numInChannels * sizeof(AUDIO_CHANNEL_TYPE));
2401*e5436536SAndroid Build Coastguard Worker       FDKmemclear(inChTypes + numInChannels,
2402*e5436536SAndroid Build Coastguard Worker                   ((8) - numInChannels) * sizeof(AUDIO_CHANNEL_TYPE));
2403*e5436536SAndroid Build Coastguard Worker       FDKmemcpy(inChIndices, channelIndices, numInChannels * sizeof(UCHAR));
2404*e5436536SAndroid Build Coastguard Worker       FDKmemclear(inChIndices + numInChannels,
2405*e5436536SAndroid Build Coastguard Worker                   ((8) - numInChannels) * sizeof(UCHAR));
2406*e5436536SAndroid Build Coastguard Worker 
2407*e5436536SAndroid Build Coastguard Worker       /* Set this stages output stride and channel mode: */
2408*e5436536SAndroid Build Coastguard Worker       outStride = (fInterleaved) ? numOutChannels : 1;
2409*e5436536SAndroid Build Coastguard Worker       outChMode = outChModeTable[numOutChannels];
2410*e5436536SAndroid Build Coastguard Worker       FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
2411*e5436536SAndroid Build Coastguard Worker 
2412*e5436536SAndroid Build Coastguard Worker       /* Check if input channel config can be easily mapped to the desired
2413*e5436536SAndroid Build Coastguard Worker        * output config. */
2414*e5436536SAndroid Build Coastguard Worker       for (chGrp = 0; chGrp < (4); chGrp += 1) {
2415*e5436536SAndroid Build Coastguard Worker         numChPerGrp[IN][chGrp] = (inChMode >> (chGrp * 4)) & 0xF;
2416*e5436536SAndroid Build Coastguard Worker         numChPerGrp[OUT][chGrp] = (outChMode >> (chGrp * 4)) & 0xF;
2417*e5436536SAndroid Build Coastguard Worker 
2418*e5436536SAndroid Build Coastguard Worker         if (numChPerGrp[IN][chGrp] > numChPerGrp[OUT][chGrp]) {
2419*e5436536SAndroid Build Coastguard Worker           isCompatible = 0;
2420*e5436536SAndroid Build Coastguard Worker           break;
2421*e5436536SAndroid Build Coastguard Worker         }
2422*e5436536SAndroid Build Coastguard Worker       }
2423*e5436536SAndroid Build Coastguard Worker 
2424*e5436536SAndroid Build Coastguard Worker       if (isCompatible) {
2425*e5436536SAndroid Build Coastguard Worker         /* Get new channel description and channel
2426*e5436536SAndroid Build Coastguard Worker          * mapping for the desired output channel mode. */
2427*e5436536SAndroid Build Coastguard Worker         getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2428*e5436536SAndroid Build Coastguard Worker                               outOffsetTable);
2429*e5436536SAndroid Build Coastguard Worker         /* If the input config has a back center channel but the output
2430*e5436536SAndroid Build Coastguard Worker            config has not, copy it to left and right (if available). */
2431*e5436536SAndroid Build Coastguard Worker         if ((numChPerGrp[IN][CH_GROUP_REAR] % 2) &&
2432*e5436536SAndroid Build Coastguard Worker             !(numChPerGrp[OUT][CH_GROUP_REAR] % 2)) {
2433*e5436536SAndroid Build Coastguard Worker           if (numChPerGrp[IN][CH_GROUP_REAR] == 1) {
2434*e5436536SAndroid Build Coastguard Worker             inOffsetTable[RIGHT_REAR_CHANNEL] =
2435*e5436536SAndroid Build Coastguard Worker                 inOffsetTable[LEFT_REAR_CHANNEL];
2436*e5436536SAndroid Build Coastguard Worker           } else if (numChPerGrp[IN][CH_GROUP_REAR] == 3) {
2437*e5436536SAndroid Build Coastguard Worker             inOffsetTable[RIGHT_MULTIPRPS_CHANNEL] =
2438*e5436536SAndroid Build Coastguard Worker                 inOffsetTable[LEFT_MULTIPRPS_CHANNEL];
2439*e5436536SAndroid Build Coastguard Worker           }
2440*e5436536SAndroid Build Coastguard Worker         }
2441*e5436536SAndroid Build Coastguard Worker       } else {
2442*e5436536SAndroid Build Coastguard Worker         /* Just copy and extend the original config */
2443*e5436536SAndroid Build Coastguard Worker         FDKmemcpy(outOffsetTable, inOffsetTable, (8) * sizeof(UCHAR));
2444*e5436536SAndroid Build Coastguard Worker       }
2445*e5436536SAndroid Build Coastguard Worker 
2446*e5436536SAndroid Build Coastguard Worker       /* Set I/O channel pointer.
2447*e5436536SAndroid Build Coastguard Worker          Note: The following assignment algorithm clears the channel offset
2448*e5436536SAndroid Build Coastguard Worker          tables. Thus they can not be used afterwards. */
2449*e5436536SAndroid Build Coastguard Worker       for (ch = 0; ch < (8); ch += 1) {
2450*e5436536SAndroid Build Coastguard Worker         if ((outOffsetTable[ch] < 255) &&
2451*e5436536SAndroid Build Coastguard Worker             (inOffsetTable[ch] < 255)) { /* Set I/O pointer: */
2452*e5436536SAndroid Build Coastguard Worker           pIn[nContentCh] =
2453*e5436536SAndroid Build Coastguard Worker               &pPcmBuf[inOffsetTable[ch] * offset + (frameSize - 1) * inStride];
2454*e5436536SAndroid Build Coastguard Worker           pOut[nContentCh] = &pPcmBuf[outOffsetTable[ch] * offset +
2455*e5436536SAndroid Build Coastguard Worker                                       (frameSize - 1) * outStride];
2456*e5436536SAndroid Build Coastguard Worker           /* Update signalling */
2457*e5436536SAndroid Build Coastguard Worker           channelType[outOffsetTable[ch]] = inChTypes[inOffsetTable[ch]];
2458*e5436536SAndroid Build Coastguard Worker           channelIndices[outOffsetTable[ch]] = inChIndices[inOffsetTable[ch]];
2459*e5436536SAndroid Build Coastguard Worker           inOffsetTable[ch] = 255;
2460*e5436536SAndroid Build Coastguard Worker           outOffsetTable[ch] = 255;
2461*e5436536SAndroid Build Coastguard Worker           nContentCh += 1;
2462*e5436536SAndroid Build Coastguard Worker         }
2463*e5436536SAndroid Build Coastguard Worker       }
2464*e5436536SAndroid Build Coastguard Worker       if (isCompatible) {
2465*e5436536SAndroid Build Coastguard Worker         /* Assign the remaining input channels.
2466*e5436536SAndroid Build Coastguard Worker            This is just a safety appliance. We should never need it. */
2467*e5436536SAndroid Build Coastguard Worker         for (ch = 0; ch < (8); ch += 1) {
2468*e5436536SAndroid Build Coastguard Worker           if (inOffsetTable[ch] < 255) {
2469*e5436536SAndroid Build Coastguard Worker             int outCh;
2470*e5436536SAndroid Build Coastguard Worker             for (outCh = 0; outCh < (8); outCh += 1) {
2471*e5436536SAndroid Build Coastguard Worker               if (outOffsetTable[outCh] < 255) {
2472*e5436536SAndroid Build Coastguard Worker                 break;
2473*e5436536SAndroid Build Coastguard Worker               }
2474*e5436536SAndroid Build Coastguard Worker             }
2475*e5436536SAndroid Build Coastguard Worker             if (outCh >= (8)) {
2476*e5436536SAndroid Build Coastguard Worker               FDK_ASSERT(0);
2477*e5436536SAndroid Build Coastguard Worker               break;
2478*e5436536SAndroid Build Coastguard Worker             }
2479*e5436536SAndroid Build Coastguard Worker             /* Set I/O pointer: */
2480*e5436536SAndroid Build Coastguard Worker             pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch] * offset +
2481*e5436536SAndroid Build Coastguard Worker                                        (frameSize - 1) * inStride];
2482*e5436536SAndroid Build Coastguard Worker             pOut[nContentCh] = &pPcmBuf[outOffsetTable[outCh] * offset +
2483*e5436536SAndroid Build Coastguard Worker                                         (frameSize - 1) * outStride];
2484*e5436536SAndroid Build Coastguard Worker             /* Update signalling */
2485*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(inOffsetTable[outCh] < numInChannels);
2486*e5436536SAndroid Build Coastguard Worker             FDK_ASSERT(outOffsetTable[outCh] < numOutChannels);
2487*e5436536SAndroid Build Coastguard Worker             channelType[outOffsetTable[outCh]] = inChTypes[inOffsetTable[ch]];
2488*e5436536SAndroid Build Coastguard Worker             channelIndices[outOffsetTable[outCh]] =
2489*e5436536SAndroid Build Coastguard Worker                 inChIndices[inOffsetTable[ch]];
2490*e5436536SAndroid Build Coastguard Worker             inOffsetTable[ch] = 255;
2491*e5436536SAndroid Build Coastguard Worker             outOffsetTable[outCh] = 255;
2492*e5436536SAndroid Build Coastguard Worker             nContentCh += 1;
2493*e5436536SAndroid Build Coastguard Worker           }
2494*e5436536SAndroid Build Coastguard Worker         }
2495*e5436536SAndroid Build Coastguard Worker         /* Set the remaining output channel pointer */
2496*e5436536SAndroid Build Coastguard Worker         for (ch = 0; ch < (8); ch += 1) {
2497*e5436536SAndroid Build Coastguard Worker           if (outOffsetTable[ch] < 255) {
2498*e5436536SAndroid Build Coastguard Worker             pOut[nContentCh + nEmptyCh] = &pPcmBuf[outOffsetTable[ch] * offset +
2499*e5436536SAndroid Build Coastguard Worker                                                    (frameSize - 1) * outStride];
2500*e5436536SAndroid Build Coastguard Worker             /* Expand output signalling */
2501*e5436536SAndroid Build Coastguard Worker             channelType[outOffsetTable[ch]] = ACT_NONE;
2502*e5436536SAndroid Build Coastguard Worker             channelIndices[outOffsetTable[ch]] = (UCHAR)nEmptyCh;
2503*e5436536SAndroid Build Coastguard Worker             outOffsetTable[ch] = 255;
2504*e5436536SAndroid Build Coastguard Worker             nEmptyCh += 1;
2505*e5436536SAndroid Build Coastguard Worker           }
2506*e5436536SAndroid Build Coastguard Worker         }
2507*e5436536SAndroid Build Coastguard Worker       } else {
2508*e5436536SAndroid Build Coastguard Worker         /* Set the remaining output channel pointer */
2509*e5436536SAndroid Build Coastguard Worker         for (ch = nContentCh; ch < numOutChannels; ch += 1) {
2510*e5436536SAndroid Build Coastguard Worker           pOut[ch] = &pPcmBuf[ch * offset + (frameSize - 1) * outStride];
2511*e5436536SAndroid Build Coastguard Worker           /* Expand output signalling */
2512*e5436536SAndroid Build Coastguard Worker           channelType[ch] = ACT_NONE;
2513*e5436536SAndroid Build Coastguard Worker           channelIndices[ch] = (UCHAR)nEmptyCh;
2514*e5436536SAndroid Build Coastguard Worker           nEmptyCh += 1;
2515*e5436536SAndroid Build Coastguard Worker         }
2516*e5436536SAndroid Build Coastguard Worker       }
2517*e5436536SAndroid Build Coastguard Worker 
2518*e5436536SAndroid Build Coastguard Worker       /* First copy the channels that have signal */
2519*e5436536SAndroid Build Coastguard Worker       for (sample = 0; sample < frameSize; sample += 1) {
2520*e5436536SAndroid Build Coastguard Worker         DMX_PCM tIn[(8)];
2521*e5436536SAndroid Build Coastguard Worker         /* Read all channel samples */
2522*e5436536SAndroid Build Coastguard Worker         for (ch = 0; ch < nContentCh; ch += 1) {
2523*e5436536SAndroid Build Coastguard Worker           tIn[ch] = *pIn[ch];
2524*e5436536SAndroid Build Coastguard Worker           pIn[ch] -= inStride;
2525*e5436536SAndroid Build Coastguard Worker         }
2526*e5436536SAndroid Build Coastguard Worker         /* Write all channel samples */
2527*e5436536SAndroid Build Coastguard Worker         for (ch = 0; ch < nContentCh; ch += 1) {
2528*e5436536SAndroid Build Coastguard Worker           *pOut[ch] = tIn[ch];
2529*e5436536SAndroid Build Coastguard Worker           pOut[ch] -= outStride;
2530*e5436536SAndroid Build Coastguard Worker         }
2531*e5436536SAndroid Build Coastguard Worker       }
2532*e5436536SAndroid Build Coastguard Worker 
2533*e5436536SAndroid Build Coastguard Worker       /* Clear all the other channels */
2534*e5436536SAndroid Build Coastguard Worker       for (sample = 0; sample < frameSize; sample++) {
2535*e5436536SAndroid Build Coastguard Worker         for (ch = nContentCh; ch < numOutChannels; ch += 1) {
2536*e5436536SAndroid Build Coastguard Worker           *pOut[ch] = (DMX_PCM)0;
2537*e5436536SAndroid Build Coastguard Worker           pOut[ch] -= outStride;
2538*e5436536SAndroid Build Coastguard Worker         }
2539*e5436536SAndroid Build Coastguard Worker       }
2540*e5436536SAndroid Build Coastguard Worker     }
2541*e5436536SAndroid Build Coastguard Worker 
2542*e5436536SAndroid Build Coastguard Worker     /* update the number of output channels */
2543*e5436536SAndroid Build Coastguard Worker     *nChannels = numOutChannels;
2544*e5436536SAndroid Build Coastguard Worker   } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2545*e5436536SAndroid Build Coastguard Worker        - - - - - - - - - - - - - - - - - - */
2546*e5436536SAndroid Build Coastguard Worker   else if (numInChannels == numOutChannels) {
2547*e5436536SAndroid Build Coastguard Worker     /* Don't need to change the channel description here */
2548*e5436536SAndroid Build Coastguard Worker 
2549*e5436536SAndroid Build Coastguard Worker     switch (numInChannels) {
2550*e5436536SAndroid Build Coastguard Worker       case 2: { /* Set up channel pointer */
2551*e5436536SAndroid Build Coastguard Worker         DMX_PCM *pInPcm[(8)];
2552*e5436536SAndroid Build Coastguard Worker         DMX_PCM *pOutL, *pOutR;
2553*e5436536SAndroid Build Coastguard Worker         FIXP_DMX flev;
2554*e5436536SAndroid Build Coastguard Worker 
2555*e5436536SAndroid Build Coastguard Worker         UINT sample;
2556*e5436536SAndroid Build Coastguard Worker 
2557*e5436536SAndroid Build Coastguard Worker         if (fInterleaved) {
2558*e5436536SAndroid Build Coastguard Worker           inStride = numInChannels;
2559*e5436536SAndroid Build Coastguard Worker           outStride =
2560*e5436536SAndroid Build Coastguard Worker               2; /* fixed !!! (below stereo is donwmixed to mono if required */
2561*e5436536SAndroid Build Coastguard Worker           offset = 1; /* Channel specific offset factor */
2562*e5436536SAndroid Build Coastguard Worker         } else {
2563*e5436536SAndroid Build Coastguard Worker           inStride = 1;
2564*e5436536SAndroid Build Coastguard Worker           outStride = 1;
2565*e5436536SAndroid Build Coastguard Worker           offset = frameSize; /* Channel specific offset factor */
2566*e5436536SAndroid Build Coastguard Worker         }
2567*e5436536SAndroid Build Coastguard Worker 
2568*e5436536SAndroid Build Coastguard Worker         /* Set input channel pointer */
2569*e5436536SAndroid Build Coastguard Worker         pInPcm[LEFT_FRONT_CHANNEL] =
2570*e5436536SAndroid Build Coastguard Worker             &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL] * offset];
2571*e5436536SAndroid Build Coastguard Worker         pInPcm[RIGHT_FRONT_CHANNEL] =
2572*e5436536SAndroid Build Coastguard Worker             &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL] * offset];
2573*e5436536SAndroid Build Coastguard Worker 
2574*e5436536SAndroid Build Coastguard Worker         /* Set output channel pointer (same as input) */
2575*e5436536SAndroid Build Coastguard Worker         pOutL = pInPcm[LEFT_FRONT_CHANNEL];
2576*e5436536SAndroid Build Coastguard Worker         pOutR = pInPcm[RIGHT_FRONT_CHANNEL];
2577*e5436536SAndroid Build Coastguard Worker 
2578*e5436536SAndroid Build Coastguard Worker         /* Set downmix levels: */
2579*e5436536SAndroid Build Coastguard Worker         flev = FL2FXCONST_DMX(0.70710678f);
2580*e5436536SAndroid Build Coastguard Worker         /* 2/0 input: */
2581*e5436536SAndroid Build Coastguard Worker         switch (dualChannelMode) {
2582*e5436536SAndroid Build Coastguard Worker           case CH1_MODE: /* L' = 0.707 * Ch1;  R' = 0.707 * Ch1 */
2583*e5436536SAndroid Build Coastguard Worker             for (sample = 0; sample < frameSize; sample++) {
2584*e5436536SAndroid Build Coastguard Worker               *pOutL = *pOutR = (DMX_PCM)SATURATE_RIGHT_SHIFT(
2585*e5436536SAndroid Build Coastguard Worker                   fMult((DMX_PCMF)*pInPcm[LEFT_FRONT_CHANNEL], flev),
2586*e5436536SAndroid Build Coastguard Worker                   DFRACT_BITS - DMX_PCM_BITS, DMX_PCM_BITS);
2587*e5436536SAndroid Build Coastguard Worker 
2588*e5436536SAndroid Build Coastguard Worker               pInPcm[LEFT_FRONT_CHANNEL] += inStride;
2589*e5436536SAndroid Build Coastguard Worker               pOutL += outStride;
2590*e5436536SAndroid Build Coastguard Worker               pOutR += outStride;
2591*e5436536SAndroid Build Coastguard Worker             }
2592*e5436536SAndroid Build Coastguard Worker             break;
2593*e5436536SAndroid Build Coastguard Worker           case CH2_MODE: /* L' = 0.707 * Ch2;  R' = 0.707 * Ch2 */
2594*e5436536SAndroid Build Coastguard Worker             for (sample = 0; sample < frameSize; sample++) {
2595*e5436536SAndroid Build Coastguard Worker               *pOutL = *pOutR = (DMX_PCM)SATURATE_RIGHT_SHIFT(
2596*e5436536SAndroid Build Coastguard Worker                   fMult((DMX_PCMF)*pInPcm[RIGHT_FRONT_CHANNEL], flev),
2597*e5436536SAndroid Build Coastguard Worker                   DFRACT_BITS - DMX_PCM_BITS, DMX_PCM_BITS);
2598*e5436536SAndroid Build Coastguard Worker 
2599*e5436536SAndroid Build Coastguard Worker               pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
2600*e5436536SAndroid Build Coastguard Worker               pOutL += outStride;
2601*e5436536SAndroid Build Coastguard Worker               pOutR += outStride;
2602*e5436536SAndroid Build Coastguard Worker             }
2603*e5436536SAndroid Build Coastguard Worker             break;
2604*e5436536SAndroid Build Coastguard Worker           case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2;  R' = 0.5*Ch1 + 0.5*Ch2 */
2605*e5436536SAndroid Build Coastguard Worker             for (sample = 0; sample < frameSize; sample++) {
2606*e5436536SAndroid Build Coastguard Worker               *pOutL = *pOutR = (*pInPcm[LEFT_FRONT_CHANNEL] >> 1) +
2607*e5436536SAndroid Build Coastguard Worker                                 (*pInPcm[RIGHT_FRONT_CHANNEL] >> 1);
2608*e5436536SAndroid Build Coastguard Worker 
2609*e5436536SAndroid Build Coastguard Worker               pInPcm[LEFT_FRONT_CHANNEL] += inStride;
2610*e5436536SAndroid Build Coastguard Worker               pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
2611*e5436536SAndroid Build Coastguard Worker               pOutL += outStride;
2612*e5436536SAndroid Build Coastguard Worker               pOutR += outStride;
2613*e5436536SAndroid Build Coastguard Worker             }
2614*e5436536SAndroid Build Coastguard Worker             break;
2615*e5436536SAndroid Build Coastguard Worker           default:
2616*e5436536SAndroid Build Coastguard Worker           case STEREO_MODE:
2617*e5436536SAndroid Build Coastguard Worker             /* nothing to do */
2618*e5436536SAndroid Build Coastguard Worker             break;
2619*e5436536SAndroid Build Coastguard Worker         }
2620*e5436536SAndroid Build Coastguard Worker       } break;
2621*e5436536SAndroid Build Coastguard Worker 
2622*e5436536SAndroid Build Coastguard Worker       default:
2623*e5436536SAndroid Build Coastguard Worker         /* nothing to do */
2624*e5436536SAndroid Build Coastguard Worker         break;
2625*e5436536SAndroid Build Coastguard Worker     }
2626*e5436536SAndroid Build Coastguard Worker   }
2627*e5436536SAndroid Build Coastguard Worker 
2628*e5436536SAndroid Build Coastguard Worker   return (errorStatus);
2629*e5436536SAndroid Build Coastguard Worker }
2630*e5436536SAndroid Build Coastguard Worker 
2631*e5436536SAndroid Build Coastguard Worker /** Close an instance of the PCM downmix module.
2632*e5436536SAndroid Build Coastguard Worker  * @param [inout] Pointer to a buffer containing the handle of the instance.
2633*e5436536SAndroid Build Coastguard Worker  * @returns Returns an error code.
2634*e5436536SAndroid Build Coastguard Worker  **/
pcmDmx_Close(HANDLE_PCM_DOWNMIX * pSelf)2635*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_Close(HANDLE_PCM_DOWNMIX *pSelf) {
2636*e5436536SAndroid Build Coastguard Worker   if (pSelf == NULL) {
2637*e5436536SAndroid Build Coastguard Worker     return (PCMDMX_INVALID_HANDLE);
2638*e5436536SAndroid Build Coastguard Worker   }
2639*e5436536SAndroid Build Coastguard Worker 
2640*e5436536SAndroid Build Coastguard Worker   FreePcmDmxInstance(pSelf);
2641*e5436536SAndroid Build Coastguard Worker   *pSelf = NULL;
2642*e5436536SAndroid Build Coastguard Worker 
2643*e5436536SAndroid Build Coastguard Worker   return (PCMDMX_OK);
2644*e5436536SAndroid Build Coastguard Worker }
2645*e5436536SAndroid Build Coastguard Worker 
2646*e5436536SAndroid Build Coastguard Worker /** Get library info for this module.
2647*e5436536SAndroid Build Coastguard Worker  * @param [out] Pointer to an allocated LIB_INFO structure.
2648*e5436536SAndroid Build Coastguard Worker  * @returns Returns an error code.
2649*e5436536SAndroid Build Coastguard Worker  */
pcmDmx_GetLibInfo(LIB_INFO * info)2650*e5436536SAndroid Build Coastguard Worker PCMDMX_ERROR pcmDmx_GetLibInfo(LIB_INFO *info) {
2651*e5436536SAndroid Build Coastguard Worker   int i;
2652*e5436536SAndroid Build Coastguard Worker 
2653*e5436536SAndroid Build Coastguard Worker   if (info == NULL) {
2654*e5436536SAndroid Build Coastguard Worker     return PCMDMX_INVALID_ARGUMENT;
2655*e5436536SAndroid Build Coastguard Worker   }
2656*e5436536SAndroid Build Coastguard Worker 
2657*e5436536SAndroid Build Coastguard Worker   /* Search for next free tab */
2658*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < FDK_MODULE_LAST; i++) {
2659*e5436536SAndroid Build Coastguard Worker     if (info[i].module_id == FDK_NONE) break;
2660*e5436536SAndroid Build Coastguard Worker   }
2661*e5436536SAndroid Build Coastguard Worker   if (i == FDK_MODULE_LAST) {
2662*e5436536SAndroid Build Coastguard Worker     return PCMDMX_INVALID_ARGUMENT;
2663*e5436536SAndroid Build Coastguard Worker   }
2664*e5436536SAndroid Build Coastguard Worker 
2665*e5436536SAndroid Build Coastguard Worker   /* Add the library info */
2666*e5436536SAndroid Build Coastguard Worker   info[i].module_id = FDK_PCMDMX;
2667*e5436536SAndroid Build Coastguard Worker   info[i].version =
2668*e5436536SAndroid Build Coastguard Worker       LIB_VERSION(PCMUTIL_LIB_VL0, PCMUTIL_LIB_VL1, PCMUTIL_LIB_VL2);
2669*e5436536SAndroid Build Coastguard Worker   LIB_VERSION_STRING(info + i);
2670*e5436536SAndroid Build Coastguard Worker   info[i].build_date = PCMUTIL_LIB_BUILD_DATE;
2671*e5436536SAndroid Build Coastguard Worker   info[i].build_time = PCMUTIL_LIB_BUILD_TIME;
2672*e5436536SAndroid Build Coastguard Worker   info[i].title = PCMDMX_LIB_TITLE;
2673*e5436536SAndroid Build Coastguard Worker 
2674*e5436536SAndroid Build Coastguard Worker   /* Set flags */
2675*e5436536SAndroid Build Coastguard Worker   info[i].flags = 0 | CAPF_DMX_BLIND /* At least blind downmixing is possible */
2676*e5436536SAndroid Build Coastguard Worker                   | CAPF_DMX_PCE     /* Guided downmix with data from MPEG-2/4
2677*e5436536SAndroid Build Coastguard Worker                                         Program Config Elements (PCE). */
2678*e5436536SAndroid Build Coastguard Worker                   | CAPF_DMX_ARIB /* PCE guided downmix with slightly different
2679*e5436536SAndroid Build Coastguard Worker                                      equations and levels. */
2680*e5436536SAndroid Build Coastguard Worker                   | CAPF_DMX_DVB  /* Guided downmix with data from DVB ancillary
2681*e5436536SAndroid Build Coastguard Worker                                      data fields. */
2682*e5436536SAndroid Build Coastguard Worker                   | CAPF_DMX_CH_EXP /* Simple upmixing by dublicating channels
2683*e5436536SAndroid Build Coastguard Worker                                        or adding zero channels. */
2684*e5436536SAndroid Build Coastguard Worker                   | CAPF_DMX_6_CH | CAPF_DMX_8_CH;
2685*e5436536SAndroid Build Coastguard Worker 
2686*e5436536SAndroid Build Coastguard Worker   /* Add lib info for FDK tools (if not yet done). */
2687*e5436536SAndroid Build Coastguard Worker   FDK_toolsGetLibInfo(info);
2688*e5436536SAndroid Build Coastguard Worker 
2689*e5436536SAndroid Build Coastguard Worker   return PCMDMX_OK;
2690*e5436536SAndroid Build Coastguard Worker }
2691