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