| |
| /* ----------------------------------------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. |
| All rights reserved. |
| |
| 1. INTRODUCTION |
| The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements |
| the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. |
| This FDK AAC Codec software is intended to be used on a wide variety of Android devices. |
| |
| AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual |
| audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by |
| independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part |
| of the MPEG specifications. |
| |
| Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) |
| may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners |
| individually for the purpose of encoding or decoding bit streams in products that are compliant with |
| the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license |
| these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec |
| software may already be covered under those patent licenses when it is used for those licensed purposes only. |
| |
| Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, |
| are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional |
| applications information and documentation. |
| |
| 2. COPYRIGHT LICENSE |
| |
| Redistribution and use in source and binary forms, with or without modification, are permitted without |
| payment of copyright license fees provided that you satisfy the following conditions: |
| |
| You must retain the complete text of this software license in redistributions of the FDK AAC Codec or |
| your modifications thereto in source code form. |
| |
| You must retain the complete text of this software license in the documentation and/or other materials |
| provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. |
| You must make available free of charge copies of the complete source code of the FDK AAC Codec and your |
| modifications thereto to recipients of copies in binary form. |
| |
| The name of Fraunhofer may not be used to endorse or promote products derived from this library without |
| prior written permission. |
| |
| You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec |
| software or your modifications thereto. |
| |
| Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software |
| and the date of any change. For modified versions of the FDK AAC Codec, the term |
| "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term |
| "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." |
| |
| 3. NO PATENT LICENSE |
| |
| NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, |
| ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with |
| respect to this software. |
| |
| You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized |
| by appropriate patent licenses. |
| |
| 4. DISCLAIMER |
| |
| This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors |
| "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties |
| of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages, |
| including but not limited to procurement of substitute goods or services; loss of use, data, or profits, |
| or business interruption, however caused and on any theory of liability, whether in contract, strict |
| liability, or tort (including negligence), arising in any way out of the use of this software, even if |
| advised of the possibility of such damage. |
| |
| 5. CONTACT INFORMATION |
| |
| Fraunhofer Institute for Integrated Circuits IIS |
| Attention: Audio and Multimedia Departments - FDK AAC LL |
| Am Wolfsmantel 33 |
| 91058 Erlangen, Germany |
| |
| www.iis.fraunhofer.de/amm |
| amm-info@iis.fraunhofer.de |
| ----------------------------------------------------------------------------------------------------------- */ |
| |
| /***************************** MPEG-4 AAC Encoder ************************** |
| |
| Author(s): M. Werner |
| Description: Block switching |
| |
| ******************************************************************************/ |
| |
| /****************** Includes *****************************/ |
| |
| #include "block_switch.h" |
| #include "genericStds.h" |
| |
| |
| #define LOWOV_WINDOW _LOWOV_WINDOW |
| |
| /**************** internal function prototypes ***********/ |
| |
| static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx); |
| |
| static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, |
| INT windowLen); |
| |
| |
| /****************** Constants *****************************/ |
| /* LONG START SHORT STOP LOWOV */ |
| static const INT blockType2windowShape[2][5] = { {SINE_WINDOW, KBD_WINDOW, WRONG_WINDOW, SINE_WINDOW, KBD_WINDOW}, /* LD */ |
| {KBD_WINDOW, SINE_WINDOW, SINE_WINDOW, KBD_WINDOW, WRONG_WINDOW} }; /* LC */ |
| |
| /* IIR high pass coeffs */ |
| |
| #ifndef SINETABLE_16BIT |
| |
| static const FIXP_DBL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN]= |
| { |
| FL2FXCONST_DBL(-0.5095),FL2FXCONST_DBL(0.7548) |
| }; |
| |
| static const FIXP_DBL accWindowNrgFac = FL2FXCONST_DBL(0.3f); /* factor for accumulating filtered window energies */ |
| static const FIXP_DBL oneMinusAccWindowNrgFac = FL2FXCONST_DBL(0.7f); |
| /* static const float attackRatio = 10.0; */ /* lower ratio limit for attacks */ |
| static const FIXP_DBL invAttackRatio = FL2FXCONST_DBL(0.1f); /* inverted lower ratio limit for attacks */ |
| |
| /* The next constants are scaled, because they are used for comparison with scaled values*/ |
| /* minimum energy for attacks */ |
| static const FIXP_DBL minAttackNrg = (FL2FXCONST_DBL(1e+6f*NORM_PCM_ENERGY)>>BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */ |
| |
| #else |
| |
| static const FIXP_SGL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN]= |
| { |
| FL2FXCONST_SGL(-0.5095),FL2FXCONST_SGL(0.7548) |
| }; |
| |
| static const FIXP_DBL accWindowNrgFac = FL2FXCONST_DBL(0.3f); /* factor for accumulating filtered window energies */ |
| static const FIXP_SGL oneMinusAccWindowNrgFac = FL2FXCONST_SGL(0.7f); |
| /* static const float attackRatio = 10.0; */ /* lower ratio limit for attacks */ |
| static const FIXP_SGL invAttackRatio = FL2FXCONST_SGL(0.1f); /* inverted lower ratio limit for attacks */ |
| /* minimum energy for attacks */ |
| static const FIXP_DBL minAttackNrg = (FL2FXCONST_DBL(1e+6f*NORM_PCM_ENERGY)>>BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */ |
| |
| #endif |
| |
| /**************** internal function prototypes ***********/ |
| |
| static INT FDKaacEnc_GetWindowIndex(INT blockSwWindowIndex); |
| |
| static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT shortWndIdx); |
| |
| static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, |
| INT windowLen); |
| |
| |
| |
| /****************** Routines ****************************/ |
| void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay) |
| { |
| /* note: the pointer to timeSignal can be zeroed here, because it is initialized for every call |
| to FDKaacEnc_BlockSwitching anew */ |
| FDKmemclear (blockSwitchingControl, sizeof(BLOCK_SWITCHING_CONTROL)); |
| |
| if (isLowDelay) |
| { |
| blockSwitchingControl->nBlockSwitchWindows = 4; |
| blockSwitchingControl->allowShortFrames = 0; |
| blockSwitchingControl->allowLookAhead = 0; |
| } |
| else |
| { |
| blockSwitchingControl->nBlockSwitchWindows = 8; |
| blockSwitchingControl->allowShortFrames = 1; |
| blockSwitchingControl->allowLookAhead = 1; |
| } |
| |
| blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS; |
| |
| /* Initialize startvalue for blocktype */ |
| blockSwitchingControl->lastWindowSequence = LONG_WINDOW; |
| blockSwitchingControl->windowShape = blockType2windowShape[blockSwitchingControl->allowShortFrames][blockSwitchingControl->lastWindowSequence]; |
| |
| } |
| |
| static const INT suggestedGroupingTable[TRANS_FAC][MAX_NO_OF_GROUPS] = |
| { |
| /* Attack in Window 0 */ {1, 3, 3, 1}, |
| /* Attack in Window 1 */ {1, 1, 3, 3}, |
| /* Attack in Window 2 */ {2, 1, 3, 2}, |
| /* Attack in Window 3 */ {3, 1, 3, 1}, |
| /* Attack in Window 4 */ {3, 1, 1, 3}, |
| /* Attack in Window 5 */ {3, 2, 1, 2}, |
| /* Attack in Window 6 */ {3, 3, 1, 1}, |
| /* Attack in Window 7 */ {3, 3, 1, 1} |
| }; |
| |
| /* change block type depending on current blocktype and whether there's an attack */ |
| /* assume no look-ahead */ |
| static const INT chgWndSq[2][N_BLOCKTYPES] = |
| { |
| /* LONG WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW, LOWOV_WINDOW, WRONG_WINDOW */ |
| /*no attack*/ {LONG_WINDOW, STOP_WINDOW, WRONG_WINDOW, LONG_WINDOW, STOP_WINDOW , WRONG_WINDOW }, |
| /*attack */ {START_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, START_WINDOW, LOWOV_WINDOW, WRONG_WINDOW } |
| }; |
| |
| /* change block type depending on current blocktype and whether there's an attack */ |
| /* assume look-ahead */ |
| static const INT chgWndSqLkAhd[2][2][N_BLOCKTYPES] = |
| { |
| /*attack LONG WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW LOWOV_WINDOW, WRONG_WINDOW */ /* last attack */ |
| /*no attack*/ { {LONG_WINDOW, SHORT_WINDOW, STOP_WINDOW, LONG_WINDOW, WRONG_WINDOW, WRONG_WINDOW}, /* no attack */ |
| /*attack */ {START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} }, /* no attack */ |
| /*no attack*/ { {LONG_WINDOW, SHORT_WINDOW, SHORT_WINDOW, LONG_WINDOW, WRONG_WINDOW, WRONG_WINDOW}, /* attack */ |
| /*attack */ {START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} } /* attack */ |
| }; |
| |
| int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE) |
| { |
| UINT i; |
| FIXP_DBL enM1, enMax; |
| |
| UINT nBlockSwitchWindows = blockSwitchingControl->nBlockSwitchWindows; |
| |
| /* for LFE : only LONG window allowed */ |
| if (isLFE) { |
| |
| /* case LFE: */ |
| /* only long blocks, always use sine windows (MPEG2 AAC, MPEG4 AAC) */ |
| blockSwitchingControl->lastWindowSequence = LONG_WINDOW; |
| blockSwitchingControl->windowShape = SINE_WINDOW; |
| blockSwitchingControl->noOfGroups = 1; |
| blockSwitchingControl->groupLen[0] = 1; |
| |
| return(0); |
| }; |
| |
| /* Save current attack index as last attack index */ |
| blockSwitchingControl->lastattack = blockSwitchingControl->attack; |
| blockSwitchingControl->lastAttackIndex = blockSwitchingControl->attackIndex; |
| |
| /* Save current window energy as last window energy */ |
| FDKmemcpy(blockSwitchingControl->windowNrg[0], blockSwitchingControl->windowNrg[1], sizeof(blockSwitchingControl->windowNrg[0])); |
| FDKmemcpy(blockSwitchingControl->windowNrgF[0], blockSwitchingControl->windowNrgF[1], sizeof(blockSwitchingControl->windowNrgF[0])); |
| |
| if (blockSwitchingControl->allowShortFrames) |
| { |
| /* Calculate suggested grouping info for the last frame */ |
| |
| /* Reset grouping info */ |
| FDKmemclear (blockSwitchingControl->groupLen, sizeof(blockSwitchingControl->groupLen)); |
| |
| /* Set grouping info */ |
| blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS; |
| |
| FDKmemcpy(blockSwitchingControl->groupLen, suggestedGroupingTable[blockSwitchingControl->lastAttackIndex], sizeof(blockSwitchingControl->groupLen)); |
| |
| if (blockSwitchingControl->attack == TRUE) |
| blockSwitchingControl->maxWindowNrg = FDKaacEnc_GetWindowEnergy(blockSwitchingControl->windowNrg[0], blockSwitchingControl->lastAttackIndex); |
| else |
| blockSwitchingControl->maxWindowNrg = FL2FXCONST_DBL(0.0); |
| |
| } |
| |
| |
| /* Calculate unfiltered and filtered energies in subwindows and combine to segments */ |
| FDKaacEnc_CalcWindowEnergy(blockSwitchingControl, granuleLength>>(nBlockSwitchWindows==4? 2:3 )); |
| |
| /* now calculate if there is an attack */ |
| |
| /* reset attack */ |
| blockSwitchingControl->attack = FALSE; |
| |
| /* look for attack */ |
| enMax = FL2FXCONST_DBL(0.0f); |
| enM1 = blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows-1]; |
| |
| for (i=0; i<nBlockSwitchWindows; i++) { |
| FIXP_DBL tmp = fMultDiv2(oneMinusAccWindowNrgFac, blockSwitchingControl->accWindowNrg); |
| blockSwitchingControl->accWindowNrg = fMultAdd(tmp, accWindowNrgFac, enM1) ; |
| |
| if (fMult(blockSwitchingControl->windowNrgF[1][i],invAttackRatio) > blockSwitchingControl->accWindowNrg ) { |
| blockSwitchingControl->attack = TRUE; |
| blockSwitchingControl->attackIndex = i; |
| } |
| enM1 = blockSwitchingControl->windowNrgF[1][i]; |
| enMax = fixMax(enMax, enM1); |
| } |
| |
| |
| if (enMax < minAttackNrg) blockSwitchingControl->attack = FALSE; |
| |
| /* Check if attack spreads over frame border */ |
| if((blockSwitchingControl->attack == FALSE) && (blockSwitchingControl->lastattack == TRUE)) { |
| /* if attack is in last window repeat SHORT_WINDOW */ |
| if ( ((blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows-1]>>4) > fMult((FIXP_DBL)(10<<(DFRACT_BITS-1-4)), blockSwitchingControl->windowNrgF[1][1])) |
| && (blockSwitchingControl->lastAttackIndex == (INT)nBlockSwitchWindows-1) |
| ) |
| { |
| blockSwitchingControl->attack = TRUE; |
| blockSwitchingControl->attackIndex = 0; |
| } |
| } |
| |
| |
| if(blockSwitchingControl->allowLookAhead) |
| { |
| |
| |
| blockSwitchingControl->lastWindowSequence = |
| chgWndSqLkAhd[blockSwitchingControl->lastattack][blockSwitchingControl->attack][blockSwitchingControl->lastWindowSequence]; |
| } |
| else |
| { |
| /* Low Delay */ |
| blockSwitchingControl->lastWindowSequence = |
| chgWndSq[blockSwitchingControl->attack][blockSwitchingControl->lastWindowSequence]; |
| } |
| |
| |
| /* update window shape */ |
| blockSwitchingControl->windowShape = blockType2windowShape[blockSwitchingControl->allowShortFrames][blockSwitchingControl->lastWindowSequence]; |
| |
| return(0); |
| } |
| |
| |
| |
| static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx) |
| { |
| /* For coherency, change FDKaacEnc_GetWindowEnergy() to calcluate the energy for a block switching analysis windows, |
| not for a short block. The same is done FDKaacEnc_CalcWindowEnergy(). The result of FDKaacEnc_GetWindowEnergy() |
| is used for a comparision of the max energy of left/right channel. */ |
| |
| return in[blSwWndIdx]; |
| |
| } |
| |
| |
| static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen) |
| { |
| INT i; |
| UINT w; |
| |
| FIXP_SGL hiPassCoeff0 = hiPassCoeff[0]; |
| FIXP_SGL hiPassCoeff1 = hiPassCoeff[1]; |
| |
| INT_PCM *timeSignal = blockSwitchingControl->timeSignal; |
| |
| /* sum up scalarproduct of timesignal as windowed Energies */ |
| for (w=0; w < blockSwitchingControl->nBlockSwitchWindows; w++) { |
| |
| FIXP_DBL temp_windowNrg = FL2FXCONST_DBL(0.0f); |
| FIXP_DBL temp_windowNrgF = FL2FXCONST_DBL(0.0f); |
| FIXP_DBL temp_iirState0 = blockSwitchingControl->iirStates[0]; |
| FIXP_DBL temp_iirState1 = blockSwitchingControl->iirStates[1]; |
| |
| /* windowNrg = sum(timesample^2) */ |
| for(i=0;i<windowLen;i++) |
| { |
| |
| FIXP_DBL tempUnfiltered, tempFiltred, t1, t2; |
| /* tempUnfiltered is scaled with 1 to prevent overflows during calculation of tempFiltred */ |
| #if SAMPLE_BITS == DFRACT_BITS |
| tempUnfiltered = (FIXP_DBL) *timeSignal++ >> 1; |
| #else |
| tempUnfiltered = (FIXP_DBL) *timeSignal++ << (DFRACT_BITS-SAMPLE_BITS-1); |
| #endif |
| t1 = fMultDiv2(hiPassCoeff1, tempUnfiltered-temp_iirState0); |
| t2 = fMultDiv2(hiPassCoeff0, temp_iirState1); |
| tempFiltred = (t1 - t2) << 1; |
| |
| temp_iirState0 = tempUnfiltered; |
| temp_iirState1 = tempFiltred; |
| |
| /* subtract 2 from overallscaling (BLOCK_SWITCH_ENERGY_SHIFT) |
| * because tempUnfiltered was already scaled with 1 (is 2 after squaring) |
| * subtract 1 from overallscaling (BLOCK_SWITCH_ENERGY_SHIFT) |
| * because of fMultDiv2 is doing a scaling by one */ |
| temp_windowNrg += fPow2Div2(tempUnfiltered) >> (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2); |
| temp_windowNrgF += fPow2Div2(tempFiltred) >> (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2); |
| } |
| blockSwitchingControl->windowNrg[1][w] = temp_windowNrg; |
| blockSwitchingControl->windowNrgF[1][w] = temp_windowNrgF; |
| blockSwitchingControl->iirStates[0] = temp_iirState0; |
| blockSwitchingControl->iirStates[1] = temp_iirState1; |
| } |
| } |
| |
| |
| static const UCHAR synchronizedBlockTypeTable[5][5] = |
| { |
| /* LONG_WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW LOWOV_WINDOW*/ |
| /* LONG_WINDOW */ {LONG_WINDOW, START_WINDOW, SHORT_WINDOW, STOP_WINDOW, LOWOV_WINDOW}, |
| /* START_WINDOW */ {START_WINDOW, START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, LOWOV_WINDOW}, |
| /* SHORT_WINDOW */ {SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, WRONG_WINDOW}, |
| /* STOP_WINDOW */ {STOP_WINDOW, SHORT_WINDOW, SHORT_WINDOW, STOP_WINDOW, LOWOV_WINDOW}, |
| /* LOWOV_WINDOW */ {LOWOV_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, LOWOV_WINDOW, LOWOV_WINDOW}, |
| }; |
| |
| int FDKaacEnc_SyncBlockSwitching ( |
| BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft, |
| BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight, |
| const INT nChannels, |
| const INT commonWindow ) |
| { |
| UCHAR patchType = LONG_WINDOW; |
| |
| if( nChannels == 2 && commonWindow == TRUE) |
| { |
| /* could be better with a channel loop (need a handle to psy_data) */ |
| /* get suggested Block Types and synchronize */ |
| patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlLeft->lastWindowSequence]; |
| patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlRight->lastWindowSequence]; |
| |
| /* sanity check (no change from low overlap window to short winow and vice versa) */ |
| if (patchType == WRONG_WINDOW) |
| return -1; /* mixed up AAC-LC and AAC-LD */ |
| |
| /* Set synchronized Blocktype */ |
| blockSwitchingControlLeft->lastWindowSequence = patchType; |
| blockSwitchingControlRight->lastWindowSequence = patchType; |
| |
| /* update window shape */ |
| blockSwitchingControlLeft->windowShape = blockType2windowShape[blockSwitchingControlLeft->allowShortFrames][blockSwitchingControlLeft->lastWindowSequence]; |
| blockSwitchingControlRight->windowShape = blockType2windowShape[blockSwitchingControlLeft->allowShortFrames][blockSwitchingControlRight->lastWindowSequence]; |
| } |
| |
| if (blockSwitchingControlLeft->allowShortFrames) |
| { |
| int i; |
| |
| if( nChannels == 2 ) |
| { |
| if (commonWindow == TRUE) |
| { |
| /* Synchronize grouping info */ |
| int windowSequenceLeftOld = blockSwitchingControlLeft->lastWindowSequence; |
| int windowSequenceRightOld = blockSwitchingControlRight->lastWindowSequence; |
| |
| /* Long Blocks */ |
| if(patchType != SHORT_WINDOW) { |
| /* Set grouping info */ |
| blockSwitchingControlLeft->noOfGroups = 1; |
| blockSwitchingControlRight->noOfGroups = 1; |
| blockSwitchingControlLeft->groupLen[0] = 1; |
| blockSwitchingControlRight->groupLen[0] = 1; |
| |
| for (i = 1; i < MAX_NO_OF_GROUPS; i++) |
| { |
| blockSwitchingControlLeft->groupLen[i] = 0; |
| blockSwitchingControlRight->groupLen[i] = 0; |
| } |
| } |
| |
| /* Short Blocks */ |
| else { |
| /* in case all two channels were detected as short-blocks before syncing, use the grouping of channel with higher maxWindowNrg */ |
| if( (windowSequenceLeftOld == SHORT_WINDOW) && |
| (windowSequenceRightOld == SHORT_WINDOW) ) |
| { |
| if(blockSwitchingControlLeft->maxWindowNrg > blockSwitchingControlRight->maxWindowNrg) { |
| /* Left Channel wins */ |
| blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups; |
| for (i = 0; i < MAX_NO_OF_GROUPS; i++){ |
| blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i]; |
| } |
| } |
| else { |
| /* Right Channel wins */ |
| blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups; |
| for (i = 0; i < MAX_NO_OF_GROUPS; i++){ |
| blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i]; |
| } |
| } |
| } |
| else if ( (windowSequenceLeftOld == SHORT_WINDOW) && |
| (windowSequenceRightOld != SHORT_WINDOW) ) |
| { |
| /* else use grouping of short-block channel */ |
| blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups; |
| for (i = 0; i < MAX_NO_OF_GROUPS; i++){ |
| blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i]; |
| } |
| } |
| else if ( (windowSequenceRightOld == SHORT_WINDOW) && |
| (windowSequenceLeftOld != SHORT_WINDOW) ) |
| { |
| blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups; |
| for (i = 0; i < MAX_NO_OF_GROUPS; i++){ |
| blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i]; |
| } |
| } else { |
| /* syncing a start and stop window ... */ |
| blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups = 2; |
| blockSwitchingControlLeft->groupLen[0] = blockSwitchingControlRight->groupLen[0] = 4; |
| blockSwitchingControlLeft->groupLen[1] = blockSwitchingControlRight->groupLen[1] = 4; |
| } |
| } /* Short Blocks */ |
| } |
| else { |
| /* stereo, no common window */ |
| if (blockSwitchingControlLeft->lastWindowSequence!=SHORT_WINDOW){ |
| blockSwitchingControlLeft->noOfGroups = 1; |
| blockSwitchingControlLeft->groupLen[0] = 1; |
| for (i = 1; i < MAX_NO_OF_GROUPS; i++) |
| { |
| blockSwitchingControlLeft->groupLen[i] = 0; |
| } |
| } |
| if (blockSwitchingControlRight->lastWindowSequence!=SHORT_WINDOW){ |
| blockSwitchingControlRight->noOfGroups = 1; |
| blockSwitchingControlRight->groupLen[0] = 1; |
| for (i = 1; i < MAX_NO_OF_GROUPS; i++) |
| { |
| blockSwitchingControlRight->groupLen[i] = 0; |
| } |
| } |
| } /* common window */ |
| } else { |
| /* Mono */ |
| if (blockSwitchingControlLeft->lastWindowSequence!=SHORT_WINDOW){ |
| blockSwitchingControlLeft->noOfGroups = 1; |
| blockSwitchingControlLeft->groupLen[0] = 1; |
| |
| for (i = 1; i < MAX_NO_OF_GROUPS; i++) |
| { |
| blockSwitchingControlLeft->groupLen[i] = 0; |
| } |
| } |
| } |
| } /* allowShortFrames */ |
| |
| |
| /* Translate LOWOV_WINDOW block type to a meaningful window shape. */ |
| if ( ! blockSwitchingControlLeft->allowShortFrames ) { |
| if ( blockSwitchingControlLeft->lastWindowSequence != LONG_WINDOW |
| && blockSwitchingControlLeft->lastWindowSequence != STOP_WINDOW ) |
| { |
| blockSwitchingControlLeft->lastWindowSequence = LONG_WINDOW; |
| blockSwitchingControlLeft->windowShape = LOL_WINDOW; |
| } |
| } |
| if (nChannels == 2) { |
| if ( ! blockSwitchingControlRight->allowShortFrames ) { |
| if ( blockSwitchingControlRight->lastWindowSequence != LONG_WINDOW |
| && blockSwitchingControlRight->lastWindowSequence != STOP_WINDOW ) |
| { |
| blockSwitchingControlRight->lastWindowSequence = LONG_WINDOW; |
| blockSwitchingControlRight->windowShape = LOL_WINDOW; |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| |