/src/aac/libAACenc/src/block_switch.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 - 2018 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 | | /**************************** AAC encoder library ****************************** |
96 | | |
97 | | Author(s): M. Werner, Tobias Chalupka |
98 | | |
99 | | Description: Block switching |
100 | | |
101 | | *******************************************************************************/ |
102 | | |
103 | | /****************** Includes *****************************/ |
104 | | |
105 | | #include "block_switch.h" |
106 | | #include "genericStds.h" |
107 | | |
108 | | #define LOWOV_WINDOW _LOWOV_WINDOW |
109 | | |
110 | | /**************** internal function prototypes ***********/ |
111 | | |
112 | | static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], |
113 | | const INT blSwWndIdx); |
114 | | |
115 | | static void FDKaacEnc_CalcWindowEnergy( |
116 | | BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen, |
117 | | const INT_PCM *pTimeSignal); |
118 | | |
119 | | /****************** Constants *****************************/ |
120 | | /* LONG START |
121 | | * SHORT STOP LOWOV */ |
122 | | static const INT blockType2windowShape[2][5] = { |
123 | | {SINE_WINDOW, KBD_WINDOW, WRONG_WINDOW, SINE_WINDOW, KBD_WINDOW}, /* LD */ |
124 | | {KBD_WINDOW, SINE_WINDOW, SINE_WINDOW, KBD_WINDOW, WRONG_WINDOW}}; /* LC */ |
125 | | |
126 | | /* IIR high pass coeffs */ |
127 | | |
128 | | #ifndef SINETABLE_16BIT |
129 | | |
130 | | static const FIXP_DBL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN] = { |
131 | | FL2FXCONST_DBL(-0.5095), FL2FXCONST_DBL(0.7548)}; |
132 | | |
133 | | static const FIXP_DBL accWindowNrgFac = |
134 | | FL2FXCONST_DBL(0.3f); /* factor for accumulating filtered window energies */ |
135 | | static const FIXP_DBL oneMinusAccWindowNrgFac = FL2FXCONST_DBL(0.7f); |
136 | | /* static const float attackRatio = 10.0; */ /* lower ratio limit for attacks */ |
137 | | static const FIXP_DBL invAttackRatio = |
138 | | FL2FXCONST_DBL(0.1f); /* inverted lower ratio limit for attacks */ |
139 | | |
140 | | /* The next constants are scaled, because they are used for comparison with |
141 | | * scaled values*/ |
142 | | /* minimum energy for attacks */ |
143 | | static const FIXP_DBL minAttackNrg = |
144 | | (FL2FXCONST_DBL(1e+6f * NORM_PCM_ENERGY) >> |
145 | | BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */ |
146 | | |
147 | | #else |
148 | | |
149 | | static const FIXP_SGL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN] = { |
150 | | FL2FXCONST_SGL(-0.5095), FL2FXCONST_SGL(0.7548)}; |
151 | | |
152 | | static const FIXP_DBL accWindowNrgFac = |
153 | | FL2FXCONST_DBL(0.3f); /* factor for accumulating filtered window energies */ |
154 | | static const FIXP_SGL oneMinusAccWindowNrgFac = FL2FXCONST_SGL(0.7f); |
155 | | /* static const float attackRatio = 10.0; */ /* lower ratio limit for attacks */ |
156 | | static const FIXP_SGL invAttackRatio = |
157 | | FL2FXCONST_SGL(0.1f); /* inverted lower ratio limit for attacks */ |
158 | | /* minimum energy for attacks */ |
159 | | static const FIXP_DBL minAttackNrg = |
160 | | (FL2FXCONST_DBL(1e+6f * NORM_PCM_ENERGY) >> |
161 | | BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */ |
162 | | |
163 | | #endif |
164 | | |
165 | | /**************** internal function prototypes ***********/ |
166 | | |
167 | | /****************** Routines ****************************/ |
168 | | void FDKaacEnc_InitBlockSwitching( |
169 | 0 | BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay) { |
170 | 0 | FDKmemclear(blockSwitchingControl, sizeof(BLOCK_SWITCHING_CONTROL)); |
171 | |
|
172 | 0 | if (isLowDelay) { |
173 | 0 | blockSwitchingControl->nBlockSwitchWindows = 4; |
174 | 0 | blockSwitchingControl->allowShortFrames = 0; |
175 | 0 | blockSwitchingControl->allowLookAhead = 0; |
176 | 0 | } else { |
177 | 0 | blockSwitchingControl->nBlockSwitchWindows = 8; |
178 | 0 | blockSwitchingControl->allowShortFrames = 1; |
179 | 0 | blockSwitchingControl->allowLookAhead = 1; |
180 | 0 | } |
181 | |
|
182 | 0 | blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS; |
183 | | |
184 | | /* Initialize startvalue for blocktype */ |
185 | 0 | blockSwitchingControl->lastWindowSequence = LONG_WINDOW; |
186 | 0 | blockSwitchingControl->windowShape = |
187 | 0 | blockType2windowShape[blockSwitchingControl->allowShortFrames] |
188 | 0 | [blockSwitchingControl->lastWindowSequence]; |
189 | 0 | } |
190 | | |
191 | | static const INT suggestedGroupingTable[TRANS_FAC][MAX_NO_OF_GROUPS] = { |
192 | | /* Attack in Window 0 */ {1, 3, 3, 1}, |
193 | | /* Attack in Window 1 */ {1, 1, 3, 3}, |
194 | | /* Attack in Window 2 */ {2, 1, 3, 2}, |
195 | | /* Attack in Window 3 */ {3, 1, 3, 1}, |
196 | | /* Attack in Window 4 */ {3, 1, 1, 3}, |
197 | | /* Attack in Window 5 */ {3, 2, 1, 2}, |
198 | | /* Attack in Window 6 */ {3, 3, 1, 1}, |
199 | | /* Attack in Window 7 */ {3, 3, 1, 1}}; |
200 | | |
201 | | /* change block type depending on current blocktype and whether there's an |
202 | | * attack */ |
203 | | /* assume no look-ahead */ |
204 | | static const INT chgWndSq[2][N_BLOCKTYPES] = { |
205 | | /* LONG WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW, |
206 | | LOWOV_WINDOW, WRONG_WINDOW */ |
207 | | /*no attack*/ {LONG_WINDOW, STOP_WINDOW, WRONG_WINDOW, LONG_WINDOW, |
208 | | STOP_WINDOW, WRONG_WINDOW}, |
209 | | /*attack */ {START_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, START_WINDOW, |
210 | | LOWOV_WINDOW, WRONG_WINDOW}}; |
211 | | |
212 | | /* change block type depending on current blocktype and whether there's an |
213 | | * attack */ |
214 | | /* assume look-ahead */ |
215 | | static const INT chgWndSqLkAhd[2][2][N_BLOCKTYPES] = { |
216 | | /*attack LONG WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW LOWOV_WINDOW, WRONG_WINDOW */ /* last attack */ |
217 | | /*no attack*/ { |
218 | | {LONG_WINDOW, SHORT_WINDOW, STOP_WINDOW, LONG_WINDOW, WRONG_WINDOW, |
219 | | WRONG_WINDOW}, /* no attack */ |
220 | | /*attack */ {START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, START_WINDOW, |
221 | | WRONG_WINDOW, WRONG_WINDOW}}, /* no attack */ |
222 | | /*no attack*/ {{LONG_WINDOW, SHORT_WINDOW, SHORT_WINDOW, LONG_WINDOW, |
223 | | WRONG_WINDOW, WRONG_WINDOW}, /* attack */ |
224 | | /*attack */ {START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, |
225 | | START_WINDOW, WRONG_WINDOW, |
226 | | WRONG_WINDOW}} /* attack */ |
227 | | }; |
228 | | |
229 | | int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, |
230 | | const INT granuleLength, const int isLFE, |
231 | 0 | const INT_PCM *pTimeSignal) { |
232 | 0 | UINT i; |
233 | 0 | FIXP_DBL enM1, enMax; |
234 | |
|
235 | 0 | UINT nBlockSwitchWindows = blockSwitchingControl->nBlockSwitchWindows; |
236 | | |
237 | | /* for LFE : only LONG window allowed */ |
238 | 0 | if (isLFE) { |
239 | | /* case LFE: */ |
240 | | /* only long blocks, always use sine windows (MPEG2 AAC, MPEG4 AAC) */ |
241 | 0 | blockSwitchingControl->lastWindowSequence = LONG_WINDOW; |
242 | 0 | blockSwitchingControl->windowShape = SINE_WINDOW; |
243 | 0 | blockSwitchingControl->noOfGroups = 1; |
244 | 0 | blockSwitchingControl->groupLen[0] = 1; |
245 | |
|
246 | 0 | return (0); |
247 | 0 | }; |
248 | | |
249 | | /* Save current attack index as last attack index */ |
250 | 0 | blockSwitchingControl->lastattack = blockSwitchingControl->attack; |
251 | 0 | blockSwitchingControl->lastAttackIndex = blockSwitchingControl->attackIndex; |
252 | | |
253 | | /* Save current window energy as last window energy */ |
254 | 0 | FDKmemcpy(blockSwitchingControl->windowNrg[0], |
255 | 0 | blockSwitchingControl->windowNrg[1], |
256 | 0 | sizeof(blockSwitchingControl->windowNrg[0])); |
257 | 0 | FDKmemcpy(blockSwitchingControl->windowNrgF[0], |
258 | 0 | blockSwitchingControl->windowNrgF[1], |
259 | 0 | sizeof(blockSwitchingControl->windowNrgF[0])); |
260 | |
|
261 | 0 | if (blockSwitchingControl->allowShortFrames) { |
262 | | /* Calculate suggested grouping info for the last frame */ |
263 | | |
264 | | /* Reset grouping info */ |
265 | 0 | FDKmemclear(blockSwitchingControl->groupLen, |
266 | 0 | sizeof(blockSwitchingControl->groupLen)); |
267 | | |
268 | | /* Set grouping info */ |
269 | 0 | blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS; |
270 | |
|
271 | 0 | FDKmemcpy(blockSwitchingControl->groupLen, |
272 | 0 | suggestedGroupingTable[blockSwitchingControl->lastAttackIndex], |
273 | 0 | sizeof(blockSwitchingControl->groupLen)); |
274 | |
|
275 | 0 | if (blockSwitchingControl->attack == TRUE) |
276 | 0 | blockSwitchingControl->maxWindowNrg = |
277 | 0 | FDKaacEnc_GetWindowEnergy(blockSwitchingControl->windowNrg[0], |
278 | 0 | blockSwitchingControl->lastAttackIndex); |
279 | 0 | else |
280 | 0 | blockSwitchingControl->maxWindowNrg = FL2FXCONST_DBL(0.0); |
281 | 0 | } |
282 | | |
283 | | /* Calculate unfiltered and filtered energies in subwindows and combine to |
284 | | * segments */ |
285 | 0 | FDKaacEnc_CalcWindowEnergy( |
286 | 0 | blockSwitchingControl, |
287 | 0 | granuleLength >> (nBlockSwitchWindows == 4 ? 2 : 3), pTimeSignal); |
288 | | |
289 | | /* now calculate if there is an attack */ |
290 | | |
291 | | /* reset attack */ |
292 | 0 | blockSwitchingControl->attack = FALSE; |
293 | | |
294 | | /* look for attack */ |
295 | 0 | enMax = FL2FXCONST_DBL(0.0f); |
296 | 0 | enM1 = blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows - 1]; |
297 | |
|
298 | 0 | for (i = 0; i < nBlockSwitchWindows; i++) { |
299 | 0 | FIXP_DBL tmp = |
300 | 0 | fMultDiv2(oneMinusAccWindowNrgFac, blockSwitchingControl->accWindowNrg); |
301 | 0 | blockSwitchingControl->accWindowNrg = fMultAdd(tmp, accWindowNrgFac, enM1); |
302 | |
|
303 | 0 | if (fMult(blockSwitchingControl->windowNrgF[1][i], invAttackRatio) > |
304 | 0 | blockSwitchingControl->accWindowNrg) { |
305 | 0 | blockSwitchingControl->attack = TRUE; |
306 | 0 | blockSwitchingControl->attackIndex = i; |
307 | 0 | } |
308 | 0 | enM1 = blockSwitchingControl->windowNrgF[1][i]; |
309 | 0 | enMax = fixMax(enMax, enM1); |
310 | 0 | } |
311 | |
|
312 | 0 | if (enMax < minAttackNrg) blockSwitchingControl->attack = FALSE; |
313 | | |
314 | | /* Check if attack spreads over frame border */ |
315 | 0 | if ((blockSwitchingControl->attack == FALSE) && |
316 | 0 | (blockSwitchingControl->lastattack == TRUE)) { |
317 | | /* if attack is in last window repeat SHORT_WINDOW */ |
318 | 0 | if (((blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows - 1] >> 4) > |
319 | 0 | fMult((FIXP_DBL)(10 << (DFRACT_BITS - 1 - 4)), |
320 | 0 | blockSwitchingControl->windowNrgF[1][1])) && |
321 | 0 | (blockSwitchingControl->lastAttackIndex == |
322 | 0 | (INT)nBlockSwitchWindows - 1)) { |
323 | 0 | blockSwitchingControl->attack = TRUE; |
324 | 0 | blockSwitchingControl->attackIndex = 0; |
325 | 0 | } |
326 | 0 | } |
327 | |
|
328 | 0 | if (blockSwitchingControl->allowLookAhead) { |
329 | 0 | blockSwitchingControl->lastWindowSequence = |
330 | 0 | chgWndSqLkAhd[blockSwitchingControl->lastattack] |
331 | 0 | [blockSwitchingControl->attack] |
332 | 0 | [blockSwitchingControl->lastWindowSequence]; |
333 | 0 | } else { |
334 | | /* Low Delay */ |
335 | 0 | blockSwitchingControl->lastWindowSequence = |
336 | 0 | chgWndSq[blockSwitchingControl->attack] |
337 | 0 | [blockSwitchingControl->lastWindowSequence]; |
338 | 0 | } |
339 | | |
340 | | /* update window shape */ |
341 | 0 | blockSwitchingControl->windowShape = |
342 | 0 | blockType2windowShape[blockSwitchingControl->allowShortFrames] |
343 | 0 | [blockSwitchingControl->lastWindowSequence]; |
344 | |
|
345 | 0 | return (0); |
346 | 0 | } |
347 | | |
348 | | static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], |
349 | 0 | const INT blSwWndIdx) { |
350 | | /* For coherency, change FDKaacEnc_GetWindowEnergy() to calcluate the energy |
351 | | for a block switching analysis windows, not for a short block. The same is |
352 | | done FDKaacEnc_CalcWindowEnergy(). The result of |
353 | | FDKaacEnc_GetWindowEnergy() is used for a comparision of the max energy of |
354 | | left/right channel. */ |
355 | |
|
356 | 0 | return in[blSwWndIdx]; |
357 | 0 | } |
358 | | |
359 | | static void FDKaacEnc_CalcWindowEnergy( |
360 | | BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen, |
361 | 0 | const INT_PCM *pTimeSignal) { |
362 | 0 | INT i; |
363 | 0 | UINT w; |
364 | |
|
365 | | #ifndef SINETABLE_16BIT |
366 | | const FIXP_DBL hiPassCoeff0 = hiPassCoeff[0]; |
367 | | const FIXP_DBL hiPassCoeff1 = hiPassCoeff[1]; |
368 | | #else |
369 | 0 | const FIXP_SGL hiPassCoeff0 = hiPassCoeff[0]; |
370 | 0 | const FIXP_SGL hiPassCoeff1 = hiPassCoeff[1]; |
371 | 0 | #endif |
372 | |
|
373 | 0 | FIXP_DBL temp_iirState0 = blockSwitchingControl->iirStates[0]; |
374 | 0 | FIXP_DBL temp_iirState1 = blockSwitchingControl->iirStates[1]; |
375 | | |
376 | | /* sum up scalarproduct of timesignal as windowed Energies */ |
377 | 0 | for (w = 0; w < blockSwitchingControl->nBlockSwitchWindows; w++) { |
378 | 0 | ULONG temp_windowNrg = 0x0; |
379 | 0 | ULONG temp_windowNrgF = 0x0; |
380 | | |
381 | | /* windowNrg = sum(timesample^2) */ |
382 | 0 | for (i = 0; i < windowLen; i++) { |
383 | 0 | FIXP_DBL tempUnfiltered, t1, t2; |
384 | | /* tempUnfiltered is scaled with 1 to prevent overflows during calculation |
385 | | * of tempFiltred */ |
386 | | #if SAMPLE_BITS == DFRACT_BITS |
387 | | tempUnfiltered = (FIXP_DBL)*pTimeSignal++ >> 1; |
388 | | #else |
389 | 0 | tempUnfiltered = (FIXP_DBL)*pTimeSignal++ |
390 | 0 | << (DFRACT_BITS - SAMPLE_BITS - 1); |
391 | 0 | #endif |
392 | 0 | t1 = fMultDiv2(hiPassCoeff1, tempUnfiltered - temp_iirState0); |
393 | 0 | t2 = fMultDiv2(hiPassCoeff0, temp_iirState1); |
394 | 0 | temp_iirState0 = tempUnfiltered; |
395 | 0 | temp_iirState1 = (t1 - t2) << 1; |
396 | |
|
397 | 0 | temp_windowNrg += (LONG)fPow2Div2(temp_iirState0) >> |
398 | 0 | (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2); |
399 | 0 | temp_windowNrgF += (LONG)fPow2Div2(temp_iirState1) >> |
400 | 0 | (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2); |
401 | 0 | } |
402 | 0 | blockSwitchingControl->windowNrg[1][w] = |
403 | 0 | (LONG)fMin(temp_windowNrg, (UINT)MAXVAL_DBL); |
404 | 0 | blockSwitchingControl->windowNrgF[1][w] = |
405 | 0 | (LONG)fMin(temp_windowNrgF, (UINT)MAXVAL_DBL); |
406 | 0 | } |
407 | 0 | blockSwitchingControl->iirStates[0] = temp_iirState0; |
408 | 0 | blockSwitchingControl->iirStates[1] = temp_iirState1; |
409 | 0 | } |
410 | | |
411 | | static const UCHAR synchronizedBlockTypeTable[5][5] = { |
412 | | /* LONG_WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW |
413 | | LOWOV_WINDOW*/ |
414 | | /* LONG_WINDOW */ {LONG_WINDOW, START_WINDOW, SHORT_WINDOW, STOP_WINDOW, |
415 | | LOWOV_WINDOW}, |
416 | | /* START_WINDOW */ |
417 | | {START_WINDOW, START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, LOWOV_WINDOW}, |
418 | | /* SHORT_WINDOW */ |
419 | | {SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, WRONG_WINDOW}, |
420 | | /* STOP_WINDOW */ |
421 | | {STOP_WINDOW, SHORT_WINDOW, SHORT_WINDOW, STOP_WINDOW, LOWOV_WINDOW}, |
422 | | /* LOWOV_WINDOW */ |
423 | | {LOWOV_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, LOWOV_WINDOW, LOWOV_WINDOW}, |
424 | | }; |
425 | | |
426 | | int FDKaacEnc_SyncBlockSwitching( |
427 | | BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft, |
428 | | BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight, const INT nChannels, |
429 | 0 | const INT commonWindow) { |
430 | 0 | UCHAR patchType = LONG_WINDOW; |
431 | |
|
432 | 0 | if (nChannels == 2 && commonWindow == TRUE) { |
433 | | /* could be better with a channel loop (need a handle to psy_data) */ |
434 | | /* get suggested Block Types and synchronize */ |
435 | 0 | patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlLeft |
436 | 0 | ->lastWindowSequence]; |
437 | 0 | patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlRight |
438 | 0 | ->lastWindowSequence]; |
439 | | |
440 | | /* sanity check (no change from low overlap window to short winow and vice |
441 | | * versa) */ |
442 | 0 | if (patchType == WRONG_WINDOW) return -1; /* mixed up AAC-LC and AAC-LD */ |
443 | | |
444 | | /* Set synchronized Blocktype */ |
445 | 0 | blockSwitchingControlLeft->lastWindowSequence = patchType; |
446 | 0 | blockSwitchingControlRight->lastWindowSequence = patchType; |
447 | | |
448 | | /* update window shape */ |
449 | 0 | blockSwitchingControlLeft->windowShape = |
450 | 0 | blockType2windowShape[blockSwitchingControlLeft->allowShortFrames] |
451 | 0 | [blockSwitchingControlLeft->lastWindowSequence]; |
452 | 0 | blockSwitchingControlRight->windowShape = |
453 | 0 | blockType2windowShape[blockSwitchingControlLeft->allowShortFrames] |
454 | 0 | [blockSwitchingControlRight->lastWindowSequence]; |
455 | 0 | } |
456 | | |
457 | 0 | if (blockSwitchingControlLeft->allowShortFrames) { |
458 | 0 | int i; |
459 | |
|
460 | 0 | if (nChannels == 2) { |
461 | 0 | if (commonWindow == TRUE) { |
462 | | /* Synchronize grouping info */ |
463 | 0 | int windowSequenceLeftOld = |
464 | 0 | blockSwitchingControlLeft->lastWindowSequence; |
465 | 0 | int windowSequenceRightOld = |
466 | 0 | blockSwitchingControlRight->lastWindowSequence; |
467 | | |
468 | | /* Long Blocks */ |
469 | 0 | if (patchType != SHORT_WINDOW) { |
470 | | /* Set grouping info */ |
471 | 0 | blockSwitchingControlLeft->noOfGroups = 1; |
472 | 0 | blockSwitchingControlRight->noOfGroups = 1; |
473 | 0 | blockSwitchingControlLeft->groupLen[0] = 1; |
474 | 0 | blockSwitchingControlRight->groupLen[0] = 1; |
475 | |
|
476 | 0 | for (i = 1; i < MAX_NO_OF_GROUPS; i++) { |
477 | 0 | blockSwitchingControlLeft->groupLen[i] = 0; |
478 | 0 | blockSwitchingControlRight->groupLen[i] = 0; |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | | /* Short Blocks */ |
483 | 0 | else { |
484 | | /* in case all two channels were detected as short-blocks before |
485 | | * syncing, use the grouping of channel with higher maxWindowNrg */ |
486 | 0 | if ((windowSequenceLeftOld == SHORT_WINDOW) && |
487 | 0 | (windowSequenceRightOld == SHORT_WINDOW)) { |
488 | 0 | if (blockSwitchingControlLeft->maxWindowNrg > |
489 | 0 | blockSwitchingControlRight->maxWindowNrg) { |
490 | | /* Left Channel wins */ |
491 | 0 | blockSwitchingControlRight->noOfGroups = |
492 | 0 | blockSwitchingControlLeft->noOfGroups; |
493 | 0 | for (i = 0; i < MAX_NO_OF_GROUPS; i++) { |
494 | 0 | blockSwitchingControlRight->groupLen[i] = |
495 | 0 | blockSwitchingControlLeft->groupLen[i]; |
496 | 0 | } |
497 | 0 | } else { |
498 | | /* Right Channel wins */ |
499 | 0 | blockSwitchingControlLeft->noOfGroups = |
500 | 0 | blockSwitchingControlRight->noOfGroups; |
501 | 0 | for (i = 0; i < MAX_NO_OF_GROUPS; i++) { |
502 | 0 | blockSwitchingControlLeft->groupLen[i] = |
503 | 0 | blockSwitchingControlRight->groupLen[i]; |
504 | 0 | } |
505 | 0 | } |
506 | 0 | } else if ((windowSequenceLeftOld == SHORT_WINDOW) && |
507 | 0 | (windowSequenceRightOld != SHORT_WINDOW)) { |
508 | | /* else use grouping of short-block channel */ |
509 | 0 | blockSwitchingControlRight->noOfGroups = |
510 | 0 | blockSwitchingControlLeft->noOfGroups; |
511 | 0 | for (i = 0; i < MAX_NO_OF_GROUPS; i++) { |
512 | 0 | blockSwitchingControlRight->groupLen[i] = |
513 | 0 | blockSwitchingControlLeft->groupLen[i]; |
514 | 0 | } |
515 | 0 | } else if ((windowSequenceRightOld == SHORT_WINDOW) && |
516 | 0 | (windowSequenceLeftOld != SHORT_WINDOW)) { |
517 | 0 | blockSwitchingControlLeft->noOfGroups = |
518 | 0 | blockSwitchingControlRight->noOfGroups; |
519 | 0 | for (i = 0; i < MAX_NO_OF_GROUPS; i++) { |
520 | 0 | blockSwitchingControlLeft->groupLen[i] = |
521 | 0 | blockSwitchingControlRight->groupLen[i]; |
522 | 0 | } |
523 | 0 | } else { |
524 | | /* syncing a start and stop window ... */ |
525 | 0 | blockSwitchingControlLeft->noOfGroups = |
526 | 0 | blockSwitchingControlRight->noOfGroups = 2; |
527 | 0 | blockSwitchingControlLeft->groupLen[0] = |
528 | 0 | blockSwitchingControlRight->groupLen[0] = 4; |
529 | 0 | blockSwitchingControlLeft->groupLen[1] = |
530 | 0 | blockSwitchingControlRight->groupLen[1] = 4; |
531 | 0 | } |
532 | 0 | } /* Short Blocks */ |
533 | 0 | } else { |
534 | | /* stereo, no common window */ |
535 | 0 | if (blockSwitchingControlLeft->lastWindowSequence != SHORT_WINDOW) { |
536 | 0 | blockSwitchingControlLeft->noOfGroups = 1; |
537 | 0 | blockSwitchingControlLeft->groupLen[0] = 1; |
538 | 0 | for (i = 1; i < MAX_NO_OF_GROUPS; i++) { |
539 | 0 | blockSwitchingControlLeft->groupLen[i] = 0; |
540 | 0 | } |
541 | 0 | } |
542 | 0 | if (blockSwitchingControlRight->lastWindowSequence != SHORT_WINDOW) { |
543 | 0 | blockSwitchingControlRight->noOfGroups = 1; |
544 | 0 | blockSwitchingControlRight->groupLen[0] = 1; |
545 | 0 | for (i = 1; i < MAX_NO_OF_GROUPS; i++) { |
546 | 0 | blockSwitchingControlRight->groupLen[i] = 0; |
547 | 0 | } |
548 | 0 | } |
549 | 0 | } /* common window */ |
550 | 0 | } else { |
551 | | /* Mono */ |
552 | 0 | if (blockSwitchingControlLeft->lastWindowSequence != SHORT_WINDOW) { |
553 | 0 | blockSwitchingControlLeft->noOfGroups = 1; |
554 | 0 | blockSwitchingControlLeft->groupLen[0] = 1; |
555 | |
|
556 | 0 | for (i = 1; i < MAX_NO_OF_GROUPS; i++) { |
557 | 0 | blockSwitchingControlLeft->groupLen[i] = 0; |
558 | 0 | } |
559 | 0 | } |
560 | 0 | } |
561 | 0 | } /* allowShortFrames */ |
562 | | |
563 | | /* Translate LOWOV_WINDOW block type to a meaningful window shape. */ |
564 | 0 | if (!blockSwitchingControlLeft->allowShortFrames) { |
565 | 0 | if (blockSwitchingControlLeft->lastWindowSequence != LONG_WINDOW && |
566 | 0 | blockSwitchingControlLeft->lastWindowSequence != STOP_WINDOW) { |
567 | 0 | blockSwitchingControlLeft->lastWindowSequence = LONG_WINDOW; |
568 | 0 | blockSwitchingControlLeft->windowShape = LOL_WINDOW; |
569 | 0 | } |
570 | 0 | } |
571 | 0 | if (nChannels == 2) { |
572 | 0 | if (!blockSwitchingControlRight->allowShortFrames) { |
573 | 0 | if (blockSwitchingControlRight->lastWindowSequence != LONG_WINDOW && |
574 | 0 | blockSwitchingControlRight->lastWindowSequence != STOP_WINDOW) { |
575 | 0 | blockSwitchingControlRight->lastWindowSequence = LONG_WINDOW; |
576 | 0 | blockSwitchingControlRight->windowShape = LOL_WINDOW; |
577 | 0 | } |
578 | 0 | } |
579 | 0 | } |
580 | |
|
581 | 0 | return 0; |
582 | 0 | } |