• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 **********************************************************************************/
InitBlockSwitching(BLOCK_SWITCHING_CONTROL * blockSwitchingControl,const Word32 bitRate,const Word16 nChannels)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 **********************************************************************************/
BlockSwitching(BLOCK_SWITCHING_CONTROL * blockSwitchingControl,Word16 * timeSignal,Word32 sampleRate,Word16 chIncrement)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 **********************************************************************************/
SrchMaxWithIndex(const Word32 in[],Word16 * index,Word16 n)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
CalcWindowEnergy(BLOCK_SWITCHING_CONTROL * blockSwitchingControl,Word16 * timeSignal,Word16 chIncrement,Word16 windowLen)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 **********************************************************************************/
SyncBlockSwitching(BLOCK_SWITCHING_CONTROL * blockSwitchingControlLeft,BLOCK_SWITCHING_CONTROL * blockSwitchingControlRight,const Word16 nChannels)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