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