block_switch.c revision 54e96f62859d933a5c8d4716cc5ab7bb00bd8711
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 Word32
34SrchMaxWithIndex(const Word32 *in, Word16 *index, Word16 n);
35
36
37Word32
38CalcWindowEnergy(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*/
51const Word32 hiPassCoeff[BLOCK_SWITCHING_IIR_LEN] = {
52  0xbec8b439, 0x609d4952  /* -0.5095f, 0.7548f */
53};
54
55static const Word32 accWindowNrgFac = 0x26666666;                   /* factor for accumulating filtered window energies 0.3 */
56static const Word32 oneMinusAccWindowNrgFac = 0x5999999a;			/* 0.7 */
57static const Word32 invAttackRatioHighBr = 0x0ccccccd;              /* inverted lower ratio limit for attacks 0.1*/
58static const Word32 invAttackRatioLowBr =  0x072b020c;              /* 0.056 */
59static 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**********************************************************************************/
72Word16 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
88static 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**********************************************************************************/
106Word16 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**********************************************************************************/
246static 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
275Word32 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
329static 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**********************************************************************************/
345Word16 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