Home | History | Annotate | Download | only in src
      1 /*
      2  ** Copyright 2003-2010, VisualOn, Inc.
      3  **
      4  ** Licensed under the Apache License, Version 2.0 (the "License");
      5  ** you may not use this file except in compliance with the License.
      6  ** You may obtain a copy of the License at
      7  **
      8  **     http://www.apache.org/licenses/LICENSE-2.0
      9  **
     10  ** Unless required by applicable law or agreed to in writing, software
     11  ** distributed under the License is distributed on an "AS IS" BASIS,
     12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  ** See the License for the specific language governing permissions and
     14  ** limitations under the License.
     15  */
     16 /*******************************************************************************
     17 	File:		block_switch.c
     18 
     19 	Content:	Block switching functions
     20 
     21 *******************************************************************************/
     22 
     23 #include "typedef.h"
     24 #include "basic_op.h"
     25 #include "oper_32b.h"
     26 #include "psy_const.h"
     27 #include "block_switch.h"
     28 
     29 
     30 #define ENERGY_SHIFT (8 - 1)
     31 
     32 /**************** internal function prototypes ***********/
     33 static Word32
     34 SrchMaxWithIndex(const Word32 *in, Word16 *index, Word16 n);
     35 
     36 
     37 Word32
     38 CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *blockSwitchingControl,
     39                  Word16 *timeSignal,
     40                  Word16 chIncrement,
     41                  Word16 windowLen);
     42 
     43 
     44 
     45 /****************** Constants *****************************/
     46 
     47 
     48 /*
     49   IIR high pass coeffs
     50 */
     51 const Word32 hiPassCoeff[BLOCK_SWITCHING_IIR_LEN] = {
     52   0xbec8b439, 0x609d4952  /* -0.5095f, 0.7548f */
     53 };
     54 
     55 static const Word32 accWindowNrgFac = 0x26666666;                   /* factor for accumulating filtered window energies 0.3 */
     56 static const Word32 oneMinusAccWindowNrgFac = 0x5999999a;			/* 0.7 */
     57 static const Word32 invAttackRatioHighBr = 0x0ccccccd;              /* inverted lower ratio limit for attacks 0.1*/
     58 static const Word32 invAttackRatioLowBr =  0x072b020c;              /* 0.056 */
     59 static const Word32 minAttackNrg = 0x00001e84;                      /* minimum energy for attacks 1e+6 */
     60 
     61 
     62 /****************** Routines ****************************/
     63 
     64 
     65 /*****************************************************************************
     66 *
     67 * function name: InitBlockSwitching
     68 * description:  init Block Switching parameter.
     69 * returns:      TRUE if success
     70 *
     71 **********************************************************************************/
     72 Word16 InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl,
     73                           const Word32 bitRate, const Word16 nChannels)
     74 {
     75   /* select attackRatio */
     76 
     77   if ((sub(nChannels,1)==0 && L_sub(bitRate, 24000) > 0) ||
     78       (sub(nChannels,1)>0 && bitRate > (nChannels * 16000))) {
     79     blockSwitchingControl->invAttackRatio = invAttackRatioHighBr;
     80   }
     81   else  {
     82     blockSwitchingControl->invAttackRatio = invAttackRatioLowBr;
     83   }
     84 
     85   return(TRUE);
     86 }
     87 
     88 static Word16 suggestedGroupingTable[TRANS_FAC][MAX_NO_OF_GROUPS] = {
     89   /* Attack in Window 0 */ {1,  3,  3,  1},
     90   /* Attack in Window 1 */ {1,  1,  3,  3},
     91   /* Attack in Window 2 */ {2,  1,  3,  2},
     92   /* Attack in Window 3 */ {3,  1,  3,  1},
     93   /* Attack in Window 4 */ {3,  1,  1,  3},
     94   /* Attack in Window 5 */ {3,  2,  1,  2},
     95   /* Attack in Window 6 */ {3,  3,  1,  1},
     96   /* Attack in Window 7 */ {3,  3,  1,  1}
     97 };
     98 
     99 /*****************************************************************************
    100 *
    101 * function name: BlockSwitching
    102 * description:  detect this frame whether there is an attack
    103 * returns:      TRUE if success
    104 *
    105 **********************************************************************************/
    106 Word16 BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl,
    107                       Word16 *timeSignal,
    108 					  Word32 sampleRate,
    109                       Word16 chIncrement)
    110 {
    111   Word32 i, w;
    112   Word32 enM1, enMax;
    113 
    114   /* Reset grouping info */
    115   for (i=0; i<TRANS_FAC; i++) {
    116     blockSwitchingControl->groupLen[i] = 0;
    117   }
    118 
    119 
    120   /* Search for position and amplitude of attack in last frame (1 windows delay) */
    121   blockSwitchingControl->maxWindowNrg = SrchMaxWithIndex( &blockSwitchingControl->windowNrg[0][BLOCK_SWITCH_WINDOWS-1],
    122                                                           &blockSwitchingControl->attackIndex,
    123                                                           BLOCK_SWITCH_WINDOWS);
    124 
    125   blockSwitchingControl->attackIndex = blockSwitchingControl->lastAttackIndex;
    126 
    127   /* Set grouping info */
    128   blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS;
    129 
    130   for (i=0; i<MAX_NO_OF_GROUPS; i++) {
    131     blockSwitchingControl->groupLen[i] = suggestedGroupingTable[blockSwitchingControl->attackIndex][i];
    132   }
    133 
    134   /* if the samplerate is less than 16000, it should be all the short block, avoid pre&post echo */
    135   if(sampleRate >= 16000) {
    136 	  /* Save current window energy as last window energy */
    137 	  for (w=0; w<BLOCK_SWITCH_WINDOWS; w++) {
    138 		  blockSwitchingControl->windowNrg[0][w] = blockSwitchingControl->windowNrg[1][w];
    139 		  blockSwitchingControl->windowNrgF[0][w] = blockSwitchingControl->windowNrgF[1][w];
    140 	  }
    141 
    142 
    143 	  /* Calculate unfiltered and filtered energies in subwindows and combine to segments */
    144 	  CalcWindowEnergy(blockSwitchingControl, timeSignal, chIncrement, BLOCK_SWITCH_WINDOW_LEN);
    145 
    146 	  /* reset attack */
    147 	  blockSwitchingControl->attack = FALSE;
    148 
    149 	  enMax = 0;
    150 	  enM1 = blockSwitchingControl->windowNrgF[0][BLOCK_SWITCH_WINDOWS-1];
    151 
    152 	  for (w=0; w<BLOCK_SWITCH_WINDOWS; w++) {
    153 		  Word32 enM1_Tmp, accWindowNrg_Tmp, windowNrgF_Tmp;
    154 		  Word16 enM1_Shf, accWindowNrg_Shf, windowNrgF_Shf;
    155 
    156 		  accWindowNrg_Shf = norm_l(blockSwitchingControl->accWindowNrg);
    157 		  enM1_Shf = norm_l(enM1);
    158 		  windowNrgF_Shf = norm_l(blockSwitchingControl->windowNrgF[1][w]);
    159 
    160 		  accWindowNrg_Tmp = blockSwitchingControl->accWindowNrg << accWindowNrg_Shf;
    161 		  enM1_Tmp = enM1 << enM1_Shf;
    162 		  windowNrgF_Tmp = blockSwitchingControl->windowNrgF[1][w] << windowNrgF_Shf;
    163 
    164 		  /* a sliding average of the previous energies */
    165 		  blockSwitchingControl->accWindowNrg = (fixmul(oneMinusAccWindowNrgFac, accWindowNrg_Tmp) >> accWindowNrg_Shf) +
    166 			  (fixmul(accWindowNrgFac, enM1_Tmp) >> enM1_Shf);
    167 
    168 
    169 		  /* if the energy with the ratio is bigger than the average, and the attack and short block  */
    170 		  if ((fixmul(windowNrgF_Tmp, blockSwitchingControl->invAttackRatio) >> windowNrgF_Shf) >
    171 			  blockSwitchingControl->accWindowNrg ) {
    172 				  blockSwitchingControl->attack = TRUE;
    173 				  blockSwitchingControl->lastAttackIndex = w;
    174 		  }
    175 		  enM1 = blockSwitchingControl->windowNrgF[1][w];
    176 		  enMax = max(enMax, enM1);
    177 	  }
    178 
    179 	  if (enMax < minAttackNrg) {
    180 		  blockSwitchingControl->attack = FALSE;
    181 	  }
    182   }
    183   else
    184   {
    185 	  blockSwitchingControl->attack = TRUE;
    186   }
    187 
    188   /* Check if attack spreads over frame border */
    189   if ((!blockSwitchingControl->attack) && (blockSwitchingControl->lastattack)) {
    190 
    191     if (blockSwitchingControl->attackIndex == TRANS_FAC-1) {
    192       blockSwitchingControl->attack = TRUE;
    193     }
    194 
    195     blockSwitchingControl->lastattack = FALSE;
    196   }
    197   else {
    198     blockSwitchingControl->lastattack = blockSwitchingControl->attack;
    199   }
    200 
    201   blockSwitchingControl->windowSequence =  blockSwitchingControl->nextwindowSequence;
    202 
    203 
    204   if (blockSwitchingControl->attack) {
    205     blockSwitchingControl->nextwindowSequence = SHORT_WINDOW;
    206   }
    207   else {
    208     blockSwitchingControl->nextwindowSequence = LONG_WINDOW;
    209   }
    210 
    211   /* update short block group */
    212   if (blockSwitchingControl->nextwindowSequence == SHORT_WINDOW) {
    213 
    214     if (blockSwitchingControl->windowSequence== LONG_WINDOW) {
    215       blockSwitchingControl->windowSequence = START_WINDOW;
    216     }
    217 
    218     if (blockSwitchingControl->windowSequence == STOP_WINDOW) {
    219       blockSwitchingControl->windowSequence = SHORT_WINDOW;
    220       blockSwitchingControl->noOfGroups = 3;
    221       blockSwitchingControl->groupLen[0] = 3;
    222       blockSwitchingControl->groupLen[1] = 3;
    223       blockSwitchingControl->groupLen[2] = 2;
    224     }
    225   }
    226 
    227   /* update block type */
    228   if (blockSwitchingControl->nextwindowSequence == LONG_WINDOW) {
    229 
    230     if (blockSwitchingControl->windowSequence == SHORT_WINDOW) {
    231       blockSwitchingControl->nextwindowSequence = STOP_WINDOW;
    232     }
    233   }
    234 
    235   return(TRUE);
    236 }
    237 
    238 
    239 /*****************************************************************************
    240 *
    241 * function name: SrchMaxWithIndex
    242 * description:  search for the biggest value in an array
    243 * returns:      the max value
    244 *
    245 **********************************************************************************/
    246 static Word32 SrchMaxWithIndex(const Word32 in[], Word16 *index, Word16 n)
    247 {
    248   Word32 max;
    249   Word32 i, idx;
    250 
    251   /* Search maximum value in array and return index and value */
    252   max = 0;
    253   idx = 0;
    254 
    255   for (i = 0; i < n; i++) {
    256 
    257     if (in[i+1]  > max) {
    258       max = in[i+1];
    259       idx = i;
    260     }
    261   }
    262   *index = idx;
    263 
    264   return(max);
    265 }
    266 
    267 /*****************************************************************************
    268 *
    269 * function name: CalcWindowEnergy
    270 * description:  calculate the energy before iir-filter and after irr-filter
    271 * returns:      TRUE if success
    272 *
    273 **********************************************************************************/
    274 #ifndef ARMV5E
    275 Word32 CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *blockSwitchingControl,
    276                         Word16 *timeSignal,
    277                         Word16 chIncrement,
    278                         Word16 windowLen)
    279 {
    280   Word32 w, i, tidx;
    281   Word32 accuUE, accuFE;
    282   Word32 tempUnfiltered;
    283   Word32 tempFiltered;
    284   Word32 states0, states1;
    285   Word32 Coeff0, Coeff1;
    286 
    287 
    288   states0 = blockSwitchingControl->iirStates[0];
    289   states1 = blockSwitchingControl->iirStates[1];
    290   Coeff0 = hiPassCoeff[0];
    291   Coeff1 = hiPassCoeff[1];
    292   tidx = 0;
    293   for (w=0; w < BLOCK_SWITCH_WINDOWS; w++) {
    294 
    295     accuUE = 0;
    296     accuFE = 0;
    297 
    298     for(i=0; i<windowLen; i++) {
    299 	  Word32 accu1, accu2, accu3;
    300 	  Word32 out;
    301 	  tempUnfiltered = timeSignal[tidx];
    302       tidx = tidx + chIncrement;
    303 
    304 	  accu1 = L_mpy_ls(Coeff1, tempUnfiltered);
    305 	  accu2 = fixmul( Coeff0, states1 );
    306 	  accu3 = accu1 - states0;
    307 	  out = accu3 - accu2;
    308 
    309 	  states0 = accu1;
    310 	  states1 = out;
    311 
    312       tempFiltered = extract_h(out);
    313       accuUE += (tempUnfiltered * tempUnfiltered) >> ENERGY_SHIFT;
    314       accuFE += (tempFiltered * tempFiltered) >> ENERGY_SHIFT;
    315     }
    316 
    317     blockSwitchingControl->windowNrg[1][w] = accuUE;
    318     blockSwitchingControl->windowNrgF[1][w] = accuFE;
    319 
    320   }
    321 
    322   blockSwitchingControl->iirStates[0] = states0;
    323   blockSwitchingControl->iirStates[1] = states1;
    324 
    325   return(TRUE);
    326 }
    327 #endif
    328 
    329 static Word16 synchronizedBlockTypeTable[4][4] = {
    330   /*                 LONG_WINDOW   START_WINDOW  SHORT_WINDOW  STOP_WINDOW */
    331   /* LONG_WINDOW  */{LONG_WINDOW,  START_WINDOW, SHORT_WINDOW, STOP_WINDOW},
    332   /* START_WINDOW */{START_WINDOW, START_WINDOW, SHORT_WINDOW, SHORT_WINDOW},
    333   /* SHORT_WINDOW */{SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW},
    334   /* STOP_WINDOW  */{STOP_WINDOW,  SHORT_WINDOW, SHORT_WINDOW, STOP_WINDOW}
    335 };
    336 
    337 
    338 /*****************************************************************************
    339 *
    340 * function name: SyncBlockSwitching
    341 * description:  update block type and group value
    342 * returns:      TRUE if success
    343 *
    344 **********************************************************************************/
    345 Word16 SyncBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft,
    346                           BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight,
    347                           const Word16 nChannels)
    348 {
    349   Word16 i;
    350   Word16 patchType = LONG_WINDOW;
    351 
    352 
    353   if (nChannels == 1) { /* Mono */
    354     if (blockSwitchingControlLeft->windowSequence != SHORT_WINDOW) {
    355       blockSwitchingControlLeft->noOfGroups = 1;
    356       blockSwitchingControlLeft->groupLen[0] = 1;
    357 
    358       for (i=1; i<TRANS_FAC; i++) {
    359         blockSwitchingControlLeft->groupLen[i] = 0;
    360       }
    361     }
    362   }
    363   else { /* Stereo common Window */
    364     patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlLeft->windowSequence];
    365     patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlRight->windowSequence];
    366 
    367     /* Set synchronized Blocktype */
    368     blockSwitchingControlLeft->windowSequence = patchType;
    369     blockSwitchingControlRight->windowSequence = patchType;
    370 
    371     /* Synchronize grouping info */
    372     if(patchType != SHORT_WINDOW) { /* Long Blocks */
    373       /* Set grouping info */
    374       blockSwitchingControlLeft->noOfGroups = 1;
    375       blockSwitchingControlRight->noOfGroups = 1;
    376       blockSwitchingControlLeft->groupLen[0] = 1;
    377       blockSwitchingControlRight->groupLen[0] = 1;
    378 
    379       for (i=1; i<TRANS_FAC; i++) {
    380         blockSwitchingControlLeft->groupLen[i] = 0;
    381         blockSwitchingControlRight->groupLen[i] = 0;
    382       }
    383     }
    384     else {
    385 
    386       if (blockSwitchingControlLeft->maxWindowNrg > blockSwitchingControlRight->maxWindowNrg) {
    387         /* Left Channel wins */
    388         blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups;
    389         for (i=0; i<TRANS_FAC; i++) {
    390           blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i];
    391         }
    392       }
    393       else {
    394         /* Right Channel wins */
    395         blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups;
    396         for (i=0; i<TRANS_FAC; i++) {
    397           blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i];
    398         }
    399       }
    400     }
    401   } /*endif Mono or Stereo */
    402 
    403   return(TRUE);
    404 }
    405