1
2/* -----------------------------------------------------------------------------------------------------------
3Software License for The Fraunhofer FDK AAC Codec Library for Android
4
5� Copyright  1995 - 2013 Fraunhofer-Gesellschaft zur F�rderung der angewandten Forschung e.V.
6  All rights reserved.
7
8 1.    INTRODUCTION
9The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16of the MPEG specifications.
17
18Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20individually for the purpose of encoding or decoding bit streams in products that are compliant with
21the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23software may already be covered under those patent licenses when it is used for those licensed purposes only.
24
25Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27applications information and documentation.
28
292.    COPYRIGHT LICENSE
30
31Redistribution and use in source and binary forms, with or without modification, are permitted without
32payment of copyright license fees provided that you satisfy the following conditions:
33
34You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35your modifications thereto in source code form.
36
37You must retain the complete text of this software license in the documentation and/or other materials
38provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40modifications thereto to recipients of copies in binary form.
41
42The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43prior written permission.
44
45You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46software or your modifications thereto.
47
48Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49and the date of any change. For modified versions of the FDK AAC Codec, the term
50"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
51"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
52
533.    NO PATENT LICENSE
54
55NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57respect to this software.
58
59You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60by appropriate patent licenses.
61
624.    DISCLAIMER
63
64This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
65"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
66of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69or business interruption, however caused and on any theory of liability, whether in contract, strict
70liability, or tort (including negligence), arising in any way out of the use of this software, even if
71advised of the possibility of such damage.
72
735.    CONTACT INFORMATION
74
75Fraunhofer Institute for Integrated Circuits IIS
76Attention: Audio and Multimedia Departments - FDK AAC LL
77Am Wolfsmantel 33
7891058 Erlangen, Germany
79
80www.iis.fraunhofer.de/amm
81amm-info@iis.fraunhofer.de
82----------------------------------------------------------------------------------------------------------- */
83
84/*****************************  MPEG-4 AAC Encoder  **************************
85
86   Author(s):   M. Werner, Tobias Chalupka
87   Description: Block switching
88
89******************************************************************************/
90
91/****************** Includes *****************************/
92
93#include "block_switch.h"
94#include "genericStds.h"
95
96
97#define LOWOV_WINDOW _LOWOV_WINDOW
98
99/**************** internal function prototypes ***********/
100
101static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx);
102
103static void FDKaacEnc_CalcWindowEnergy(
104        BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl,
105        INT                      windowLen,
106        const INT_PCM           *pTimeSignal
107        );
108
109/****************** Constants *****************************/
110/*                                                LONG         START        SHORT         STOP         LOWOV                  */
111static const INT blockType2windowShape[2][5] = { {SINE_WINDOW, KBD_WINDOW,  WRONG_WINDOW, SINE_WINDOW, KBD_WINDOW},     /* LD */
112                                                 {KBD_WINDOW,  SINE_WINDOW, SINE_WINDOW,  KBD_WINDOW,  WRONG_WINDOW} }; /* LC */
113
114/* IIR high pass coeffs */
115
116#ifndef SINETABLE_16BIT
117
118static const FIXP_DBL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN]=
119{
120  FL2FXCONST_DBL(-0.5095),FL2FXCONST_DBL(0.7548)
121};
122
123static const FIXP_DBL accWindowNrgFac = FL2FXCONST_DBL(0.3f);                   /* factor for accumulating filtered window energies */
124static const FIXP_DBL oneMinusAccWindowNrgFac = FL2FXCONST_DBL(0.7f);
125/* static const float attackRatio = 10.0; */                                    /* lower ratio limit for attacks */
126static const FIXP_DBL invAttackRatio = FL2FXCONST_DBL(0.1f);                    /* inverted lower ratio limit for attacks */
127
128/* The next constants are scaled, because they are used for comparison with scaled values*/
129/* minimum energy for attacks */
130static const FIXP_DBL minAttackNrg = (FL2FXCONST_DBL(1e+6f*NORM_PCM_ENERGY)>>BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */
131
132#else
133
134static const FIXP_SGL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN]=
135{
136  FL2FXCONST_SGL(-0.5095),FL2FXCONST_SGL(0.7548)
137};
138
139static const FIXP_DBL accWindowNrgFac = FL2FXCONST_DBL(0.3f);                   /* factor for accumulating filtered window energies */
140static const FIXP_SGL oneMinusAccWindowNrgFac = FL2FXCONST_SGL(0.7f);
141/* static const float attackRatio = 10.0; */                                    /* lower ratio limit for attacks */
142static const FIXP_SGL invAttackRatio = FL2FXCONST_SGL(0.1f);                    /* inverted lower ratio limit for attacks */
143/* minimum energy for attacks */
144static const FIXP_DBL minAttackNrg = (FL2FXCONST_DBL(1e+6f*NORM_PCM_ENERGY)>>BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */
145
146#endif
147
148/**************** internal function prototypes ***********/
149
150/****************** Routines ****************************/
151void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay)
152{
153  FDKmemclear (blockSwitchingControl, sizeof(BLOCK_SWITCHING_CONTROL));
154
155  if (isLowDelay)
156  {
157    blockSwitchingControl->nBlockSwitchWindows = 4;
158    blockSwitchingControl->allowShortFrames    = 0;
159    blockSwitchingControl->allowLookAhead      = 0;
160  }
161  else
162  {
163    blockSwitchingControl->nBlockSwitchWindows = 8;
164    blockSwitchingControl->allowShortFrames    = 1;
165    blockSwitchingControl->allowLookAhead      = 1;
166  }
167
168  blockSwitchingControl->noOfGroups            = MAX_NO_OF_GROUPS;
169
170  /* Initialize startvalue for blocktype */
171  blockSwitchingControl->lastWindowSequence    = LONG_WINDOW;
172  blockSwitchingControl->windowShape           = blockType2windowShape[blockSwitchingControl->allowShortFrames][blockSwitchingControl->lastWindowSequence];
173
174}
175
176static const INT suggestedGroupingTable[TRANS_FAC][MAX_NO_OF_GROUPS] =
177{
178    /* Attack in Window 0 */ {1,  3,  3,  1},
179    /* Attack in Window 1 */ {1,  1,  3,  3},
180    /* Attack in Window 2 */ {2,  1,  3,  2},
181    /* Attack in Window 3 */ {3,  1,  3,  1},
182    /* Attack in Window 4 */ {3,  1,  1,  3},
183    /* Attack in Window 5 */ {3,  2,  1,  2},
184    /* Attack in Window 6 */ {3,  3,  1,  1},
185    /* Attack in Window 7 */ {3,  3,  1,  1}
186};
187
188/* change block type depending on current blocktype and whether there's an attack */
189/* assume no look-ahead */
190static const INT chgWndSq[2][N_BLOCKTYPES] =
191{
192  /*             LONG WINDOW   START_WINDOW  SHORT_WINDOW  STOP_WINDOW,  LOWOV_WINDOW, WRONG_WINDOW */
193  /*no attack*/ {LONG_WINDOW,  STOP_WINDOW,  WRONG_WINDOW, LONG_WINDOW,  STOP_WINDOW , WRONG_WINDOW },
194  /*attack   */ {START_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, START_WINDOW, LOWOV_WINDOW, WRONG_WINDOW }
195};
196
197/* change block type depending on current blocktype and whether there's an attack */
198/* assume look-ahead */
199static const INT chgWndSqLkAhd[2][2][N_BLOCKTYPES] =
200{
201  /*attack         LONG WINDOW    START_WINDOW   SHORT_WINDOW   STOP_WINDOW   LOWOV_WINDOW, WRONG_WINDOW */  /* last attack */
202  /*no attack*/ { {LONG_WINDOW,   SHORT_WINDOW,  STOP_WINDOW,   LONG_WINDOW,  WRONG_WINDOW, WRONG_WINDOW},   /* no attack   */
203  /*attack   */   {START_WINDOW,  SHORT_WINDOW,  SHORT_WINDOW,  START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} }, /* no attack   */
204  /*no attack*/ { {LONG_WINDOW,   SHORT_WINDOW,  SHORT_WINDOW,  LONG_WINDOW,  WRONG_WINDOW, WRONG_WINDOW},   /* attack      */
205  /*attack   */   {START_WINDOW,  SHORT_WINDOW,  SHORT_WINDOW,  START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} }  /* attack      */
206};
207
208int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE, const INT_PCM *pTimeSignal)
209{
210    UINT i;
211    FIXP_DBL enM1, enMax;
212
213    UINT nBlockSwitchWindows = blockSwitchingControl->nBlockSwitchWindows;
214
215    /* for LFE : only LONG window allowed */
216    if (isLFE) {
217
218      /* case LFE: */
219      /* only long blocks, always use sine windows (MPEG2 AAC, MPEG4 AAC) */
220      blockSwitchingControl->lastWindowSequence = LONG_WINDOW;
221      blockSwitchingControl->windowShape    = SINE_WINDOW;
222      blockSwitchingControl->noOfGroups     = 1;
223      blockSwitchingControl->groupLen[0]    = 1;
224
225      return(0);
226    };
227
228    /* Save current attack index as last attack index */
229    blockSwitchingControl->lastattack = blockSwitchingControl->attack;
230    blockSwitchingControl->lastAttackIndex = blockSwitchingControl->attackIndex;
231
232    /* Save current window energy as last window energy */
233    FDKmemcpy(blockSwitchingControl->windowNrg[0], blockSwitchingControl->windowNrg[1], sizeof(blockSwitchingControl->windowNrg[0]));
234    FDKmemcpy(blockSwitchingControl->windowNrgF[0], blockSwitchingControl->windowNrgF[1], sizeof(blockSwitchingControl->windowNrgF[0]));
235
236    if (blockSwitchingControl->allowShortFrames)
237    {
238      /* Calculate suggested grouping info for the last frame */
239
240      /* Reset grouping info */
241      FDKmemclear (blockSwitchingControl->groupLen, sizeof(blockSwitchingControl->groupLen));
242
243      /* Set grouping info */
244      blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS;
245
246      FDKmemcpy(blockSwitchingControl->groupLen, suggestedGroupingTable[blockSwitchingControl->lastAttackIndex], sizeof(blockSwitchingControl->groupLen));
247
248      if (blockSwitchingControl->attack == TRUE)
249          blockSwitchingControl->maxWindowNrg = FDKaacEnc_GetWindowEnergy(blockSwitchingControl->windowNrg[0], blockSwitchingControl->lastAttackIndex);
250      else
251          blockSwitchingControl->maxWindowNrg = FL2FXCONST_DBL(0.0);
252
253    }
254
255
256    /* Calculate unfiltered and filtered energies in subwindows and combine to segments */
257    FDKaacEnc_CalcWindowEnergy(blockSwitchingControl, granuleLength>>(nBlockSwitchWindows==4? 2:3 ), pTimeSignal);
258
259    /* now calculate if there is an attack */
260
261    /* reset attack */
262    blockSwitchingControl->attack = FALSE;
263
264    /* look for attack */
265    enMax = FL2FXCONST_DBL(0.0f);
266    enM1 = blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows-1];
267
268    for (i=0; i<nBlockSwitchWindows; i++) {
269        FIXP_DBL tmp = fMultDiv2(oneMinusAccWindowNrgFac, blockSwitchingControl->accWindowNrg);
270        blockSwitchingControl->accWindowNrg = fMultAdd(tmp, accWindowNrgFac, enM1) ;
271
272        if (fMult(blockSwitchingControl->windowNrgF[1][i],invAttackRatio) > blockSwitchingControl->accWindowNrg ) {
273            blockSwitchingControl->attack = TRUE;
274            blockSwitchingControl->attackIndex = i;
275        }
276        enM1 = blockSwitchingControl->windowNrgF[1][i];
277        enMax = fixMax(enMax, enM1);
278    }
279
280
281    if (enMax < minAttackNrg) blockSwitchingControl->attack = FALSE;
282
283    /* Check if attack spreads over frame border */
284    if((blockSwitchingControl->attack == FALSE) && (blockSwitchingControl->lastattack == TRUE)) {
285        /* if attack is in last window repeat SHORT_WINDOW */
286        if ( ((blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows-1]>>4) > fMult((FIXP_DBL)(10<<(DFRACT_BITS-1-4)), blockSwitchingControl->windowNrgF[1][1]))
287           && (blockSwitchingControl->lastAttackIndex == (INT)nBlockSwitchWindows-1)
288        )
289        {
290            blockSwitchingControl->attack = TRUE;
291            blockSwitchingControl->attackIndex = 0;
292        }
293    }
294
295
296    if(blockSwitchingControl->allowLookAhead)
297    {
298
299
300      blockSwitchingControl->lastWindowSequence =
301        chgWndSqLkAhd[blockSwitchingControl->lastattack][blockSwitchingControl->attack][blockSwitchingControl->lastWindowSequence];
302    }
303    else
304    {
305      /* Low Delay */
306      blockSwitchingControl->lastWindowSequence =
307        chgWndSq[blockSwitchingControl->attack][blockSwitchingControl->lastWindowSequence];
308    }
309
310
311    /* update window shape */
312    blockSwitchingControl->windowShape = blockType2windowShape[blockSwitchingControl->allowShortFrames][blockSwitchingControl->lastWindowSequence];
313
314    return(0);
315}
316
317
318
319static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx)
320{
321/* For coherency, change FDKaacEnc_GetWindowEnergy() to calcluate the energy for a block switching analysis windows,
322   not for a short block. The same is done FDKaacEnc_CalcWindowEnergy(). The result of FDKaacEnc_GetWindowEnergy()
323   is used for a comparision of the max energy of left/right channel. */
324
325  return in[blSwWndIdx];
326
327}
328
329static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen, const INT_PCM *pTimeSignal)
330{
331    INT  i;
332    UINT w;
333
334    FIXP_SGL hiPassCoeff0 = hiPassCoeff[0];
335    FIXP_SGL hiPassCoeff1 = hiPassCoeff[1];
336
337    /* sum up scalarproduct of timesignal as windowed Energies */
338    for (w=0; w < blockSwitchingControl->nBlockSwitchWindows; w++) {
339
340        FIXP_DBL temp_windowNrg  = FL2FXCONST_DBL(0.0f);
341        FIXP_DBL temp_windowNrgF = FL2FXCONST_DBL(0.0f);
342        FIXP_DBL temp_iirState0  = blockSwitchingControl->iirStates[0];
343        FIXP_DBL temp_iirState1  = blockSwitchingControl->iirStates[1];
344
345        /* windowNrg = sum(timesample^2) */
346        for(i=0;i<windowLen;i++)
347        {
348
349            FIXP_DBL tempUnfiltered, tempFiltred, t1, t2;
350            /* tempUnfiltered is scaled with 1 to prevent overflows during calculation of tempFiltred */
351#if SAMPLE_BITS == DFRACT_BITS
352            tempUnfiltered = (FIXP_DBL) *pTimeSignal++ >> 1;
353#else
354            tempUnfiltered = (FIXP_DBL) *pTimeSignal++ << (DFRACT_BITS-SAMPLE_BITS-1);
355#endif
356            t1 = fMultDiv2(hiPassCoeff1, tempUnfiltered-temp_iirState0);
357            t2 = fMultDiv2(hiPassCoeff0, temp_iirState1);
358            tempFiltred = (t1 - t2) << 1;
359
360            temp_iirState0 = tempUnfiltered;
361            temp_iirState1 = tempFiltred;
362
363            /* subtract 2 from overallscaling (BLOCK_SWITCH_ENERGY_SHIFT)
364             * because tempUnfiltered was already scaled with 1 (is 2 after squaring)
365             * subtract 1 from overallscaling (BLOCK_SWITCH_ENERGY_SHIFT)
366             * because of fMultDiv2 is doing a scaling by one */
367            temp_windowNrg += fPow2Div2(tempUnfiltered) >> (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2);
368            temp_windowNrgF += fPow2Div2(tempFiltred) >> (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2);
369        }
370        blockSwitchingControl->windowNrg[1][w]  = temp_windowNrg;
371        blockSwitchingControl->windowNrgF[1][w] = temp_windowNrgF;
372        blockSwitchingControl->iirStates[0]     = temp_iirState0;
373        blockSwitchingControl->iirStates[1]     = temp_iirState1;
374    }
375}
376
377
378static const UCHAR synchronizedBlockTypeTable[5][5] =
379{
380  /*                  LONG_WINDOW   START_WINDOW  SHORT_WINDOW  STOP_WINDOW   LOWOV_WINDOW*/
381  /* LONG_WINDOW  */ {LONG_WINDOW,  START_WINDOW, SHORT_WINDOW, STOP_WINDOW,  LOWOV_WINDOW},
382  /* START_WINDOW */ {START_WINDOW, START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, LOWOV_WINDOW},
383  /* SHORT_WINDOW */ {SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, WRONG_WINDOW},
384  /* STOP_WINDOW  */ {STOP_WINDOW,  SHORT_WINDOW, SHORT_WINDOW, STOP_WINDOW,  LOWOV_WINDOW},
385  /* LOWOV_WINDOW */ {LOWOV_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, LOWOV_WINDOW, LOWOV_WINDOW},
386};
387
388int FDKaacEnc_SyncBlockSwitching (
389      BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft,
390      BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight,
391      const INT nChannels,
392      const INT commonWindow )
393{
394  UCHAR patchType = LONG_WINDOW;
395
396  if( nChannels == 2 && commonWindow == TRUE)
397  {
398    /* could be better with a channel loop (need a handle to psy_data) */
399    /* get suggested Block Types and synchronize */
400    patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlLeft->lastWindowSequence];
401    patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlRight->lastWindowSequence];
402
403    /* sanity check (no change from low overlap window to short winow and vice versa) */
404    if (patchType == WRONG_WINDOW)
405      return -1; /* mixed up AAC-LC and AAC-LD */
406
407    /* Set synchronized Blocktype */
408    blockSwitchingControlLeft->lastWindowSequence  = patchType;
409    blockSwitchingControlRight->lastWindowSequence = patchType;
410
411    /* update window shape */
412    blockSwitchingControlLeft->windowShape  = blockType2windowShape[blockSwitchingControlLeft->allowShortFrames][blockSwitchingControlLeft->lastWindowSequence];
413    blockSwitchingControlRight->windowShape = blockType2windowShape[blockSwitchingControlLeft->allowShortFrames][blockSwitchingControlRight->lastWindowSequence];
414  }
415
416  if (blockSwitchingControlLeft->allowShortFrames)
417  {
418    int i;
419
420    if( nChannels == 2 )
421    {
422      if (commonWindow == TRUE)
423      {
424        /* Synchronize grouping info */
425        int windowSequenceLeftOld  = blockSwitchingControlLeft->lastWindowSequence;
426        int windowSequenceRightOld = blockSwitchingControlRight->lastWindowSequence;
427
428        /* Long Blocks */
429        if(patchType != SHORT_WINDOW) {
430          /* Set grouping info */
431          blockSwitchingControlLeft->noOfGroups   = 1;
432          blockSwitchingControlRight->noOfGroups  = 1;
433          blockSwitchingControlLeft->groupLen[0]  = 1;
434          blockSwitchingControlRight->groupLen[0] = 1;
435
436          for (i = 1; i < MAX_NO_OF_GROUPS; i++)
437          {
438            blockSwitchingControlLeft->groupLen[i]  = 0;
439            blockSwitchingControlRight->groupLen[i] = 0;
440          }
441        }
442
443        /* Short Blocks */
444        else {
445          /* in case all two channels were detected as short-blocks before syncing, use the grouping of channel with higher maxWindowNrg */
446          if( (windowSequenceLeftOld  == SHORT_WINDOW) &&
447	            (windowSequenceRightOld == SHORT_WINDOW) )
448          {
449            if(blockSwitchingControlLeft->maxWindowNrg > blockSwitchingControlRight->maxWindowNrg) {
450	            /* Left Channel wins */
451	            blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups;
452	            for (i = 0; i < MAX_NO_OF_GROUPS; i++){
453	              blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i];
454	            }
455            }
456            else {
457	            /* Right Channel wins */
458	            blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups;
459	            for (i = 0; i < MAX_NO_OF_GROUPS; i++){
460	              blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i];
461	            }
462            }
463          }
464          else if ( (windowSequenceLeftOld  == SHORT_WINDOW) &&
465                    (windowSequenceRightOld != SHORT_WINDOW) )
466          {
467            /* else use grouping of short-block channel */
468            blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups;
469            for (i = 0; i < MAX_NO_OF_GROUPS; i++){
470              blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i];
471            }
472          }
473          else if ( (windowSequenceRightOld == SHORT_WINDOW) &&
474		                (windowSequenceLeftOld  != SHORT_WINDOW) )
475          {
476            blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups;
477            for (i = 0; i < MAX_NO_OF_GROUPS; i++){
478              blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i];
479            }
480          } else {
481            /* syncing a start and stop window ... */
482            blockSwitchingControlLeft->noOfGroups  = blockSwitchingControlRight->noOfGroups  = 2;
483            blockSwitchingControlLeft->groupLen[0] = blockSwitchingControlRight->groupLen[0] = 4;
484            blockSwitchingControlLeft->groupLen[1] = blockSwitchingControlRight->groupLen[1] = 4;
485          }
486        } /* Short Blocks */
487      }
488      else {
489        /* stereo, no common window */
490        if (blockSwitchingControlLeft->lastWindowSequence!=SHORT_WINDOW){
491          blockSwitchingControlLeft->noOfGroups  = 1;
492          blockSwitchingControlLeft->groupLen[0] = 1;
493          for (i = 1; i < MAX_NO_OF_GROUPS; i++)
494          {
495            blockSwitchingControlLeft->groupLen[i] = 0;
496          }
497        }
498        if (blockSwitchingControlRight->lastWindowSequence!=SHORT_WINDOW){
499          blockSwitchingControlRight->noOfGroups  = 1;
500          blockSwitchingControlRight->groupLen[0] = 1;
501          for (i = 1; i < MAX_NO_OF_GROUPS; i++)
502          {
503            blockSwitchingControlRight->groupLen[i] = 0;
504          }
505        }
506      } /* common window */
507    } else {
508      /* Mono */
509      if (blockSwitchingControlLeft->lastWindowSequence!=SHORT_WINDOW){
510        blockSwitchingControlLeft->noOfGroups  = 1;
511        blockSwitchingControlLeft->groupLen[0] = 1;
512
513        for (i = 1; i < MAX_NO_OF_GROUPS; i++)
514        {
515          blockSwitchingControlLeft->groupLen[i] = 0;
516        }
517      }
518    }
519  } /* allowShortFrames */
520
521
522  /* Translate LOWOV_WINDOW block type to a meaningful window shape. */
523  if ( ! blockSwitchingControlLeft->allowShortFrames ) {
524    if ( blockSwitchingControlLeft->lastWindowSequence != LONG_WINDOW
525      && blockSwitchingControlLeft->lastWindowSequence != STOP_WINDOW )
526    {
527      blockSwitchingControlLeft->lastWindowSequence = LONG_WINDOW;
528      blockSwitchingControlLeft->windowShape = LOL_WINDOW;
529    }
530  }
531  if (nChannels == 2) {
532    if ( ! blockSwitchingControlRight->allowShortFrames ) {
533      if ( blockSwitchingControlRight->lastWindowSequence != LONG_WINDOW
534        && blockSwitchingControlRight->lastWindowSequence != STOP_WINDOW )
535      {
536        blockSwitchingControlRight->lastWindowSequence = LONG_WINDOW;
537        blockSwitchingControlRight->windowShape = LOL_WINDOW;
538      }
539    }
540  }
541
542  return 0;
543}
544
545
546