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