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