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