block_switch.c revision 956c553ab0ce72f8074ad0fda2ffd66a0305700c
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 ***********/
33static Word16
34IIRFilter(const Word16 in, const Word32 coeff[], Word32 states[]);
35
36static Word32
37SrchMaxWithIndex(const Word32 *in, Word16 *index, Word16 n);
38
39
40Word32
41CalcWindowEnergy(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*/
54Word32 hiPassCoeff[BLOCK_SWITCHING_IIR_LEN] = {
55  0xbec8b439, 0x609d4952  /* -0.5095f, 0.7548f */
56};
57
58static const Word32 accWindowNrgFac = 0x26666666;                   /* factor for accumulating filtered window energies 0.3 */
59static const Word32 oneMinusAccWindowNrgFac = 0x5999999a;			/* 0.7 */
60static const Word32 invAttackRatioHighBr = 0x0ccccccd;              /* inverted lower ratio limit for attacks 0.1*/
61static const Word32 invAttackRatioLowBr =  0x072b020c;              /* 0.056 */
62static 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**********************************************************************************/
75Word16 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
91static 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**********************************************************************************/
109Word16 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**********************************************************************************/
249static 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
278Word32 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**********************************************************************************/
339static 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
356static 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**********************************************************************************/
372Word16 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