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