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: adj_thr.c
18
19 Content: Threshold compensation functions
20
21 *******************************************************************************/
22
23 /* Include system headers before local headers - the local headers
24 * redefine __inline, which can mess up definitions in libc headers if
25 * they happen to use __inline. */
26 #include <string.h>
27 #include "basic_op.h"
28 #include "oper_32b.h"
29 #include "adj_thr_data.h"
30 #include "adj_thr.h"
31 #include "qc_data.h"
32 #include "line_pe.h"
33
34
35 #define minSnrLimit 0x6666 /* 1 dB */
36 #define PEBITS_COEF 0x170a /* 0.18*(1 << 15)*/
37
38 #define HOLE_THR_LONG 0x2873 /* 0.316*(1 << 15) */
39 #define HOLE_THR_SHORT 0x4000 /* 0.5 *(1 << 15) */
40
41 #define MS_THRSPREAD_COEF 0x7333 /* 0.9 * (1 << 15) */
42
43 #define MIN_SNR_COEF 0x651f /* 3.16* (1 << (15 - 2)) */
44
45 /* values for avoid hole flag */
46 enum _avoid_hole_state {
47 NO_AH =0,
48 AH_INACTIVE =1,
49 AH_ACTIVE =2
50 };
51
52 /********************************************************************************
53 *
54 * function name:bits2pe
55 * description: convert from bits to pe
56 * pe = 1.18*desiredBits
57 *
58 **********************************************************************************/
bits2pe(const Word16 bits)59 Word16 bits2pe(const Word16 bits) {
60 return (bits + ((PEBITS_COEF * bits) >> 15));
61 }
62
63 /********************************************************************************
64 *
65 * function name:calcThreshExp
66 * description: loudness calculation (threshold to the power of redExp)
67 * thr(n)^0.25
68 *
69 **********************************************************************************/
calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],const Word16 nChannels)70 static void calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
71 PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
72 const Word16 nChannels)
73 {
74 Word16 ch, sfb, sfbGrp;
75 Word32 *pthrExp = NULL, *psfbThre;
76 for (ch=0; ch<nChannels; ch++) {
77 PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
78 for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup)
79 pthrExp = &(thrExp[ch][sfbGrp]);
80 psfbThre = psyOutChan->sfbThreshold + sfbGrp;
81 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
82 *pthrExp = rsqrt(rsqrt(*psfbThre,INT_BITS),INT_BITS);
83 pthrExp++; psfbThre++;
84 }
85 }
86 }
87
88 /********************************************************************************
89 *
90 * function name:adaptMinSnr
91 * description: reduce minSnr requirements for bands with relative low energies
92 *
93 **********************************************************************************/
adaptMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],MINSNR_ADAPT_PARAM * msaParam,const Word16 nChannels)94 static void adaptMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
95 Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
96 MINSNR_ADAPT_PARAM *msaParam,
97 const Word16 nChannels)
98 {
99 Word16 ch, sfb, sfbOffs;
100 Word32 nSfb, avgEn;
101 Word16 log_avgEn = 0;
102 Word32 startRatio_x_avgEn = 0;
103
104
105 for (ch=0; ch<nChannels; ch++) {
106 PSY_OUT_CHANNEL* psyOutChan = &psyOutChannel[ch];
107
108 /* calc average energy per scalefactor band */
109 avgEn = 0;
110 nSfb = 0;
111 for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
112 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
113 avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfbOffs+sfb]);
114 nSfb = nSfb + 1;
115 }
116 }
117
118 if (nSfb > 0) {
119 avgEn = avgEn / nSfb;
120
121 log_avgEn = iLog4(avgEn);
122 startRatio_x_avgEn = fixmul(msaParam->startRatio, avgEn);
123 }
124
125
126 /* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */
127 for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
128 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
129 if (psyOutChan->sfbEnergy[sfbOffs+sfb] < startRatio_x_avgEn) {
130 Word16 dbRatio, minSnrRed;
131 Word32 snrRed;
132 Word16 newMinSnr;
133
134 dbRatio = log_avgEn - logSfbEnergy[ch][sfbOffs+sfb];
135 dbRatio = dbRatio + (dbRatio << 1);
136
137 minSnrRed = 110 - ((dbRatio + (dbRatio << 1)) >> 2);
138 minSnrRed = max(minSnrRed, 20); /* 110: (0.375(redOffs)+1)*80,
139 3: 0.00375(redRatioFac)*80
140 20: 0.25(maxRed) * 80 */
141
142 snrRed = minSnrRed * iLog4((psyOutChan->sfbMinSnr[sfbOffs+sfb] << 16));
143 /*
144 snrRedI si now scaled by 80 (minSnrRed) and 4 (ffr_iLog4)
145 */
146
147 newMinSnr = round16(pow2_xy(snrRed,80*4));
148
149 psyOutChan->sfbMinSnr[sfbOffs+sfb] = min(newMinSnr, minSnrLimit);
150 }
151 }
152 }
153 }
154
155 }
156
157
158 /********************************************************************************
159 *
160 * function name:initAvoidHoleFlag
161 * description: determine bands where avoid hole is not necessary resp. possible
162 *
163 **********************************************************************************/
initAvoidHoleFlag(Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PSY_OUT_ELEMENT * psyOutElement,const Word16 nChannels,AH_PARAM * ahParam)164 static void initAvoidHoleFlag(Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
165 PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
166 PSY_OUT_ELEMENT* psyOutElement,
167 const Word16 nChannels,
168 AH_PARAM *ahParam)
169 {
170 Word16 ch, sfb, sfbGrp, shift;
171 Word32 threshold;
172 Word32* psfbSpreadEn;
173
174 for (ch=0; ch<nChannels; ch++) {
175 PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
176
177 if (psyOutChan->windowSequence != SHORT_WINDOW) {
178 for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
179 psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
180 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
181 *psfbSpreadEn = *psfbSpreadEn >> 1; /* 0.5 */
182 ++psfbSpreadEn;
183 }
184 }
185 }
186 else {
187 for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
188 psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
189 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
190 *psfbSpreadEn = (*psfbSpreadEn >> 1) + (*psfbSpreadEn >> 3); /* 0.63 */
191 ++psfbSpreadEn;
192 }
193 }
194 }
195 }
196
197 /* increase minSnr for local peaks, decrease it for valleys */
198 if (ahParam->modifyMinSnr) {
199 for(ch=0; ch<nChannels; ch++) {
200 PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
201
202 if (psyOutChan->windowSequence != SHORT_WINDOW)
203 threshold = HOLE_THR_LONG;
204 else
205 threshold = HOLE_THR_SHORT;
206
207 for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
208 Word16 *psfbMinSnr = psyOutChan->sfbMinSnr + sfbGrp;
209 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
210 Word32 sfbEn, sfbEnm1, sfbEnp1, avgEn;
211
212 if (sfb > 0)
213 sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp+sfb-1];
214 else
215 sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp];
216
217 if (sfb < (psyOutChan->maxSfbPerGroup-1))
218 sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb+1];
219 else
220 sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb];
221 avgEn = (sfbEnm1 + sfbEnp1) >> 1;
222 sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb];
223
224 if (sfbEn > avgEn && avgEn > 0) {
225 Word32 tmpMinSnr;
226 shift = norm_l(sfbEn);
227 tmpMinSnr = Div_32(L_mpy_ls(avgEn, minSnrLimit) << shift, sfbEn << shift );
228 tmpMinSnr = max(tmpMinSnr, HOLE_THR_LONG);
229 tmpMinSnr = max(tmpMinSnr, threshold);
230 *psfbMinSnr = min(*psfbMinSnr, tmpMinSnr);
231 }
232 /* valley ? */
233
234 if ((sfbEn < (avgEn >> 1)) && (sfbEn > 0)) {
235 Word32 tmpMinSnr;
236 Word32 minSnrEn = L_mpy_wx(avgEn, *psfbMinSnr);
237
238 if(minSnrEn < sfbEn) {
239 shift = norm_l(sfbEn);
240 tmpMinSnr = Div_32( minSnrEn << shift, sfbEn<<shift);
241 }
242 else {
243 tmpMinSnr = MAX_16;
244 }
245 tmpMinSnr = min(minSnrLimit, tmpMinSnr);
246
247 *psfbMinSnr =
248 (min((tmpMinSnr >> 2), mult(*psfbMinSnr, MIN_SNR_COEF)) << 2);
249 }
250 psfbMinSnr++;
251 }
252 }
253 }
254 }
255
256 /* stereo: adapt the minimum requirements sfbMinSnr of mid and
257 side channels */
258
259 if (nChannels == 2) {
260 PSY_OUT_CHANNEL *psyOutChanM = &psyOutChannel[0];
261 PSY_OUT_CHANNEL *psyOutChanS = &psyOutChannel[1];
262 for (sfb=0; sfb<psyOutChanM->sfbCnt; sfb++) {
263 if (psyOutElement->toolsInfo.msMask[sfb]) {
264 Word32 sfbEnM = psyOutChanM->sfbEnergy[sfb];
265 Word32 sfbEnS = psyOutChanS->sfbEnergy[sfb];
266 Word32 maxSfbEn = max(sfbEnM, sfbEnS);
267 Word32 maxThr = L_mpy_wx(maxSfbEn, psyOutChanM->sfbMinSnr[sfb]) >> 1;
268
269 if(maxThr >= sfbEnM) {
270 psyOutChanM->sfbMinSnr[sfb] = MAX_16;
271 }
272 else {
273 shift = norm_l(sfbEnM);
274 psyOutChanM->sfbMinSnr[sfb] = min(max(psyOutChanM->sfbMinSnr[sfb],
275 round16(Div_32(maxThr<<shift, sfbEnM << shift))), minSnrLimit);
276 }
277
278 if(maxThr >= sfbEnS) {
279 psyOutChanS->sfbMinSnr[sfb] = MAX_16;
280 }
281 else {
282 shift = norm_l(sfbEnS);
283 psyOutChanS->sfbMinSnr[sfb] = min(max(psyOutChanS->sfbMinSnr[sfb],
284 round16(Div_32(maxThr << shift, sfbEnS << shift))), minSnrLimit);
285 }
286
287
288 if (sfbEnM > psyOutChanM->sfbSpreadedEnergy[sfb])
289 psyOutChanS->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnS, MS_THRSPREAD_COEF);
290
291 if (sfbEnS > psyOutChanS->sfbSpreadedEnergy[sfb])
292 psyOutChanM->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnM, MS_THRSPREAD_COEF);
293 }
294 }
295 }
296
297
298 /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
299 for(ch=0; ch<nChannels; ch++) {
300 PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
301 for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
302 Word16 *pahFlag = ahFlag[ch] + sfbGrp;
303 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
304
305 if ((psyOutChan->sfbSpreadedEnergy[sfbGrp+sfb] > psyOutChan->sfbEnergy[sfbGrp+sfb]) ||
306 (psyOutChan->sfbEnergy[sfbGrp+sfb] <= psyOutChan->sfbThreshold[sfbGrp+sfb]) ||
307 (psyOutChan->sfbMinSnr[sfbGrp+sfb] == MAX_16)) {
308 *pahFlag++ = NO_AH;
309 }
310 else {
311 *pahFlag++ = AH_INACTIVE;
312 }
313 }
314 for (sfb=psyOutChan->maxSfbPerGroup; sfb<psyOutChan->sfbPerGroup; sfb++) {
315 *pahFlag++ = NO_AH;
316 }
317 }
318 }
319 }
320
321 /********************************************************************************
322 *
323 * function name:calcPeNoAH
324 * description: sum the pe data only for bands where avoid hole is inactive
325 *
326 **********************************************************************************/
calcPeNoAH(Word16 * pe,Word16 * constPart,Word16 * nActiveLines,PE_DATA * peData,Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],const Word16 nChannels)327 static void calcPeNoAH(Word16 *pe,
328 Word16 *constPart,
329 Word16 *nActiveLines,
330 PE_DATA *peData,
331 Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
332 PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
333 const Word16 nChannels)
334 {
335 Word16 ch, sfb, sfbGrp;
336 int ipe, iconstPart, inActiveLines;
337
338 ipe = 0;
339 iconstPart = 0;
340 inActiveLines = 0;
341 for(ch=0; ch<nChannels; ch++) {
342 PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
343 PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
344 for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
345 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
346
347 if (ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) {
348 ipe = ipe + peChanData->sfbPe[sfbGrp+sfb];
349 iconstPart = iconstPart + peChanData->sfbConstPart[sfbGrp+sfb];
350 inActiveLines = inActiveLines + peChanData->sfbNActiveLines[sfbGrp+sfb];
351 }
352 }
353 }
354 }
355
356 *pe = saturate(ipe);
357 *constPart = saturate(iconstPart);
358 *nActiveLines = saturate(inActiveLines);
359 }
360
361 /********************************************************************************
362 *
363 * function name:reduceThresholds
364 * description: apply reduction formula
365 *
366 **********************************************************************************/
reduceThresholds(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],const Word16 nChannels,const Word32 redVal)367 static void reduceThresholds(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
368 Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
369 Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
370 const Word16 nChannels,
371 const Word32 redVal)
372 {
373 Word32 sfbThrReduced;
374 Word32 *psfbEn, *psfbThr;
375 Word16 ch, sfb, sfbGrp;
376
377 for(ch=0; ch<nChannels; ch++) {
378 PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
379 for(sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) {
380 psfbEn = psyOutChan->sfbEnergy + sfbGrp;
381 psfbThr = psyOutChan->sfbThreshold + sfbGrp;
382 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
383
384 if (*psfbEn > *psfbThr) {
385 /* threshold reduction formula */
386 Word32 tmp = thrExp[ch][sfbGrp+sfb] + redVal;
387 tmp = fixmul(tmp, tmp);
388 sfbThrReduced = fixmul(tmp, tmp);
389 /* avoid holes */
390 tmp = L_mpy_ls(*psfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
391
392 if ((sfbThrReduced > tmp) &&
393 (ahFlag[ch][sfbGrp+sfb] != NO_AH)){
394 sfbThrReduced = max(tmp, *psfbThr);
395 ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
396 }
397 *psfbThr = sfbThrReduced;
398 }
399
400 psfbEn++; psfbThr++;
401 }
402 }
403 }
404 }
405
406
407 /********************************************************************************
408 *
409 * function name:correctThresh
410 * description: if pe difference deltaPe between desired pe and real pe is small enough,
411 * the difference can be distributed among the scale factor bands.
412 *
413 **********************************************************************************/
correctThresh(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],PE_DATA * peData,Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],const Word32 redVal,const Word16 nChannels,const Word32 deltaPe)414 static void correctThresh(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
415 Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
416 PE_DATA *peData,
417 Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
418 const Word32 redVal,
419 const Word16 nChannels,
420 const Word32 deltaPe)
421 {
422 Word16 ch, sfb, sfbGrp,shift;
423 PSY_OUT_CHANNEL *psyOutChan;
424 PE_CHANNEL_DATA *peChanData;
425 Word32 deltaSfbPe;
426 Word32 normFactor;
427 Word32 *psfbPeFactors;
428 Word16 *psfbNActiveLines, *pahFlag;
429 Word32 sfbEn, sfbThr;
430 Word32 sfbThrReduced;
431
432 /* for each sfb calc relative factors for pe changes */
433 normFactor = 1;
434 for(ch=0; ch<nChannels; ch++) {
435 psyOutChan = &psyOutChannel[ch];
436 peChanData = &peData->peChannelData[ch];
437 for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
438 psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
439 psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
440 pahFlag = ahFlag[ch] + sfbGrp;
441 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
442 Word32 redThrExp = thrExp[ch][sfbGrp+sfb] + redVal;
443
444 if (((*pahFlag < AH_ACTIVE) || (deltaPe > 0)) && (redThrExp > 0) && (redThrExp >= *psfbNActiveLines)) {
445
446 *psfbPeFactors = (*psfbNActiveLines) * (0x7fffffff / redThrExp);
447 normFactor = L_add(normFactor, *psfbPeFactors);
448 }
449 else {
450 *psfbPeFactors = 0;
451 }
452 psfbPeFactors++;
453 pahFlag++; psfbNActiveLines++;
454 }
455 }
456 }
457
458
459 /* calculate new thresholds */
460 for(ch=0; ch<nChannels; ch++) {
461 psyOutChan = &psyOutChannel[ch];
462 peChanData = &peData->peChannelData[ch];
463 for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
464 psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
465 psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
466 pahFlag = ahFlag[ch] + sfbGrp;
467 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
468 /* pe difference for this sfb */
469 deltaSfbPe = *psfbPeFactors * deltaPe;
470
471 /* thr3(n) = thr2(n)*2^deltaSfbPe/b(n) */
472 if (*psfbNActiveLines > 0 && (normFactor* (*psfbNActiveLines)) != 0) {
473 /* new threshold */
474 Word32 thrFactor;
475 sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb];
476 sfbThr = psyOutChan->sfbThreshold[sfbGrp+sfb];
477
478 if(deltaSfbPe >= 0){
479 /*
480 reduce threshold
481 */
482 thrFactor = pow2_xy(L_negate(deltaSfbPe), (normFactor* (*psfbNActiveLines)));
483
484 sfbThrReduced = L_mpy_ls(sfbThr, round16(thrFactor));
485 }
486 else {
487 /*
488 increase threshold
489 */
490 thrFactor = pow2_xy(deltaSfbPe, (normFactor * (*psfbNActiveLines)));
491
492
493 if(thrFactor > sfbThr) {
494 shift = norm_l(thrFactor);
495 sfbThrReduced = Div_32( sfbThr << shift, thrFactor<<shift );
496 }
497 else {
498 sfbThrReduced = MAX_32;
499 }
500
501 }
502
503 /* avoid hole */
504 sfbEn = L_mpy_ls(sfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
505
506 if ((sfbThrReduced > sfbEn) &&
507 (*pahFlag == AH_INACTIVE)) {
508 sfbThrReduced = max(sfbEn, sfbThr);
509 *pahFlag = AH_ACTIVE;
510 }
511
512 psyOutChan->sfbThreshold[sfbGrp+sfb] = sfbThrReduced;
513 }
514
515 pahFlag++; psfbNActiveLines++; psfbPeFactors++;
516 }
517 }
518 }
519 }
520
521
522 /********************************************************************************
523 *
524 * function name:reduceMinSnr
525 * description: if the desired pe can not be reached, reduce pe by reducing minSnr
526 *
527 **********************************************************************************/
reduceMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PE_DATA * peData,Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],const Word16 nChannels,const Word16 desiredPe)528 static void reduceMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
529 PE_DATA *peData,
530 Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
531 const Word16 nChannels,
532 const Word16 desiredPe)
533 {
534 Word16 ch, sfb, sfbSubWin;
535 Word16 deltaPe;
536
537 /* start at highest freq down to 0 */
538 sfbSubWin = psyOutChannel[0].maxSfbPerGroup;
539 while (peData->pe > desiredPe && sfbSubWin > 0) {
540
541 sfbSubWin = sfbSubWin - 1;
542 /* loop over all subwindows */
543 for (sfb=sfbSubWin; sfb<psyOutChannel[0].sfbCnt;
544 sfb+=psyOutChannel[0].sfbPerGroup) {
545 /* loop over all channels */
546 PE_CHANNEL_DATA* peChan = peData->peChannelData;
547 PSY_OUT_CHANNEL* psyOutCh = psyOutChannel;
548 for (ch=0; ch<nChannels; ch++) {
549 if (ahFlag[ch][sfb] != NO_AH &&
550 psyOutCh->sfbMinSnr[sfb] < minSnrLimit) {
551 psyOutCh->sfbMinSnr[sfb] = minSnrLimit;
552 psyOutCh->sfbThreshold[sfb] =
553 L_mpy_ls(psyOutCh->sfbEnergy[sfb], psyOutCh->sfbMinSnr[sfb]);
554
555 /* calc new pe */
556 deltaPe = ((peChan->sfbNLines4[sfb] + (peChan->sfbNLines4[sfb] >> 1)) >> 2) -
557 peChan->sfbPe[sfb];
558 peData->pe = peData->pe + deltaPe;
559 peChan->pe = peChan->pe + deltaPe;
560 }
561 peChan += 1; psyOutCh += 1;
562 }
563 /* stop if enough has been saved */
564
565 if (peData->pe <= desiredPe)
566 break;
567 }
568 }
569 }
570
571 /********************************************************************************
572 *
573 * function name:allowMoreHoles
574 * description: if the desired pe can not be reached, some more scalefactor bands
575 * have to be quantized to zero
576 *
577 **********************************************************************************/
allowMoreHoles(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PSY_OUT_ELEMENT * psyOutElement,PE_DATA * peData,Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],const AH_PARAM * ahParam,const Word16 nChannels,const Word16 desiredPe)578 static void allowMoreHoles(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
579 PSY_OUT_ELEMENT *psyOutElement,
580 PE_DATA *peData,
581 Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
582 const AH_PARAM *ahParam,
583 const Word16 nChannels,
584 const Word16 desiredPe)
585 {
586 Word16 ch, sfb;
587 Word16 actPe, shift;
588
589 actPe = peData->pe;
590
591 /* for MS allow hole in the channel with less energy */
592
593 if (nChannels==2 &&
594 psyOutChannel[0].windowSequence==psyOutChannel[1].windowSequence) {
595 PSY_OUT_CHANNEL *psyOutChanL = &psyOutChannel[0];
596 PSY_OUT_CHANNEL *psyOutChanR = &psyOutChannel[1];
597 for (sfb=0; sfb<psyOutChanL->sfbCnt; sfb++) {
598 Word32 minEn;
599
600 if (psyOutElement->toolsInfo.msMask[sfb]) {
601 /* allow hole in side channel ? */
602 minEn = L_mpy_ls(psyOutChanL->sfbEnergy[sfb], (minSnrLimit * psyOutChanL->sfbMinSnr[sfb]) >> 16);
603
604 if (ahFlag[1][sfb] != NO_AH &&
605 minEn > psyOutChanR->sfbEnergy[sfb]) {
606 ahFlag[1][sfb] = NO_AH;
607 psyOutChanR->sfbThreshold[sfb] = L_add(psyOutChanR->sfbEnergy[sfb], psyOutChanR->sfbEnergy[sfb]);
608 actPe = actPe - peData->peChannelData[1].sfbPe[sfb];
609 }
610 /* allow hole in mid channel ? */
611 else {
612 minEn = L_mpy_ls(psyOutChanR->sfbEnergy[sfb], (minSnrLimit * psyOutChanR->sfbMinSnr[sfb]) >> 16);
613
614 if (ahFlag[0][sfb]!= NO_AH &&
615 minEn > psyOutChanL->sfbEnergy[sfb]) {
616 ahFlag[0][sfb] = NO_AH;
617 psyOutChanL->sfbThreshold[sfb] = L_add(psyOutChanL->sfbEnergy[sfb], psyOutChanL->sfbEnergy[sfb]);
618 actPe = actPe - peData->peChannelData[0].sfbPe[sfb];
619 }
620 }
621
622 if (actPe < desiredPe)
623 break;
624 }
625 }
626 }
627
628 /* subsequently erase bands */
629 if (actPe > desiredPe) {
630 Word16 startSfb[2];
631 Word32 avgEn, minEn;
632 Word16 ahCnt;
633 Word16 enIdx;
634 Word16 enDiff;
635 Word32 en[4];
636 Word16 minSfb, maxSfb;
637 Flag done;
638
639 /* do not go below startSfb */
640 for (ch=0; ch<nChannels; ch++) {
641
642 if (psyOutChannel[ch].windowSequence != SHORT_WINDOW)
643 startSfb[ch] = ahParam->startSfbL;
644 else
645 startSfb[ch] = ahParam->startSfbS;
646 }
647
648 avgEn = 0;
649 minEn = MAX_32;
650 ahCnt = 0;
651 for (ch=0; ch<nChannels; ch++) {
652 PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
653 for (sfb=startSfb[ch]; sfb<psyOutChan->sfbCnt; sfb++) {
654
655 if ((ahFlag[ch][sfb] != NO_AH) &&
656 (psyOutChan->sfbEnergy[sfb] > psyOutChan->sfbThreshold[sfb])) {
657 minEn = min(minEn, psyOutChan->sfbEnergy[sfb]);
658 avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfb]);
659 ahCnt++;
660 }
661 }
662 }
663
664 if(ahCnt) {
665 Word32 iahCnt;
666 shift = norm_l(ahCnt);
667 iahCnt = Div_32( 1 << shift, ahCnt << shift );
668 avgEn = fixmul(avgEn, iahCnt);
669 }
670
671 enDiff = iLog4(avgEn) - iLog4(minEn);
672 /* calc some energy borders between minEn and avgEn */
673 for (enIdx=0; enIdx<4; enIdx++) {
674 Word32 enFac;
675 enFac = ((6-(enIdx << 1)) * enDiff);
676 en[enIdx] = fixmul(avgEn, pow2_xy(L_negate(enFac),7*4));
677 }
678
679 /* start with lowest energy border at highest sfb */
680 maxSfb = psyOutChannel[0].sfbCnt - 1;
681 minSfb = startSfb[0];
682
683 if (nChannels == 2) {
684 maxSfb = max(maxSfb, (psyOutChannel[1].sfbCnt - 1));
685 minSfb = min(minSfb, startSfb[1]);
686 }
687
688 sfb = maxSfb;
689 enIdx = 0;
690 done = 0;
691 while (!done) {
692
693 for (ch=0; ch<nChannels; ch++) {
694 PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
695
696 if (sfb>=startSfb[ch] && sfb<psyOutChan->sfbCnt) {
697 /* sfb energy below border ? */
698
699 if (ahFlag[ch][sfb] != NO_AH && psyOutChan->sfbEnergy[sfb] < en[enIdx]){
700 /* allow hole */
701 ahFlag[ch][sfb] = NO_AH;
702 psyOutChan->sfbThreshold[sfb] = L_add(psyOutChan->sfbEnergy[sfb], psyOutChan->sfbEnergy[sfb]);
703 actPe = actPe - peData->peChannelData[ch].sfbPe[sfb];
704 }
705
706 if (actPe < desiredPe) {
707 done = 1;
708 break;
709 }
710 }
711 }
712 sfb = sfb - 1;
713
714 if (sfb < minSfb) {
715 /* restart with next energy border */
716 sfb = maxSfb;
717 enIdx = enIdx + 1;
718
719 if (enIdx - 4 >= 0)
720 done = 1;
721 }
722 }
723 }
724 }
725
726 /********************************************************************************
727 *
728 * function name:adaptThresholdsToPe
729 * description: two guesses for the reduction value and one final correction of the
730 * thresholds
731 *
732 **********************************************************************************/
adaptThresholdsToPe(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PSY_OUT_ELEMENT * psyOutElement,Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],PE_DATA * peData,const Word16 nChannels,const Word16 desiredPe,AH_PARAM * ahParam,MINSNR_ADAPT_PARAM * msaParam)733 static void adaptThresholdsToPe(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
734 PSY_OUT_ELEMENT *psyOutElement,
735 Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
736 PE_DATA *peData,
737 const Word16 nChannels,
738 const Word16 desiredPe,
739 AH_PARAM *ahParam,
740 MINSNR_ADAPT_PARAM *msaParam)
741 {
742 Word16 noRedPe, redPe, redPeNoAH;
743 Word16 constPart, constPartNoAH;
744 Word16 nActiveLines, nActiveLinesNoAH;
745 Word16 desiredPeNoAH;
746 Word32 redVal, avgThrExp;
747 Word32 iter;
748
749 calcThreshExp(peData->thrExp, psyOutChannel, nChannels);
750
751 adaptMinSnr(psyOutChannel, logSfbEnergy, msaParam, nChannels);
752
753 initAvoidHoleFlag(peData->ahFlag, psyOutChannel, psyOutElement, nChannels, ahParam);
754
755 noRedPe = peData->pe;
756 constPart = peData->constPart;
757 nActiveLines = peData->nActiveLines;
758
759 /* first guess of reduction value t^0.25 = 2^((a-pen)/4*b) */
760 avgThrExp = pow2_xy((constPart - noRedPe), (nActiveLines << 2));
761
762 /* r1 = 2^((a-per)/4*b) - t^0.25 */
763 redVal = pow2_xy((constPart - desiredPe), (nActiveLines << 2)) - avgThrExp;
764
765 /* reduce thresholds */
766 reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
767
768 /* pe after first guess */
769 calcSfbPe(peData, psyOutChannel, nChannels);
770 redPe = peData->pe;
771
772 iter = 0;
773 do {
774 /* pe for bands where avoid hole is inactive */
775 calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH,
776 peData, peData->ahFlag, psyOutChannel, nChannels);
777
778 desiredPeNoAH = desiredPe -(redPe - redPeNoAH);
779
780 if (desiredPeNoAH < 0) {
781 desiredPeNoAH = 0;
782 }
783
784 /* second guess */
785
786 if (nActiveLinesNoAH > 0) {
787
788 avgThrExp = pow2_xy((constPartNoAH - redPeNoAH), (nActiveLinesNoAH << 2));
789
790 redVal = (redVal + pow2_xy((constPartNoAH - desiredPeNoAH), (nActiveLinesNoAH << 2))) - avgThrExp;
791
792 /* reduce thresholds */
793 reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
794 }
795
796 calcSfbPe(peData, psyOutChannel, nChannels);
797 redPe = peData->pe;
798
799 iter = iter+1;
800
801 } while ((20 * abs_s(redPe - desiredPe) > desiredPe) && (iter < 2));
802
803
804 if ((100 * redPe < 115 * desiredPe)) {
805 correctThresh(psyOutChannel, peData->ahFlag, peData, peData->thrExp, redVal,
806 nChannels, desiredPe - redPe);
807 }
808 else {
809 Word16 desiredPe105 = (105 * desiredPe) / 100;
810 reduceMinSnr(psyOutChannel, peData, peData->ahFlag,
811 nChannels, desiredPe105);
812 allowMoreHoles(psyOutChannel, psyOutElement, peData, peData->ahFlag,
813 ahParam, nChannels, desiredPe105);
814 }
815 }
816
817
818 /*****************************************************************************
819 *
820 * function name: calcBitSave
821 * description: Calculates percentage of bit save, see figure below
822 * returns:
823 * input: parameters and bitres-fullness
824 * output: percentage of bit save
825 *
826 *****************************************************************************/
calcBitSave(Word16 fillLevel,const Word16 clipLow,const Word16 clipHigh,const Word16 minBitSave,const Word16 maxBitSave)827 static Word16 calcBitSave(Word16 fillLevel,
828 const Word16 clipLow,
829 const Word16 clipHigh,
830 const Word16 minBitSave,
831 const Word16 maxBitSave)
832 {
833 Word16 bitsave = 0;
834
835 fillLevel = max(fillLevel, clipLow);
836 fillLevel = min(fillLevel, clipHigh);
837
838 if(clipHigh-clipLow)
839 bitsave = (maxBitSave - (((maxBitSave-minBitSave)*(fillLevel-clipLow))/
840 (clipHigh-clipLow)));
841
842 return (bitsave);
843 }
844
845
846
847 /*****************************************************************************
848 *
849 * function name: calcBitSpend
850 * description: Calculates percentage of bit spend, see figure below
851 * returns:
852 * input: parameters and bitres-fullness
853 * output: percentage of bit spend
854 *
855 *****************************************************************************/
calcBitSpend(Word16 fillLevel,const Word16 clipLow,const Word16 clipHigh,const Word16 minBitSpend,const Word16 maxBitSpend)856 static Word16 calcBitSpend(Word16 fillLevel,
857 const Word16 clipLow,
858 const Word16 clipHigh,
859 const Word16 minBitSpend,
860 const Word16 maxBitSpend)
861 {
862 Word16 bitspend = 1;
863
864 fillLevel = max(fillLevel, clipLow);
865 fillLevel = min(fillLevel, clipHigh);
866
867 if(clipHigh-clipLow)
868 bitspend = (minBitSpend + ((maxBitSpend - minBitSpend)*(fillLevel - clipLow) /
869 (clipHigh-clipLow)));
870
871 return (bitspend);
872 }
873
874
875 /*****************************************************************************
876 *
877 * function name: adjustPeMinMax()
878 * description: adjusts peMin and peMax parameters over time
879 * returns:
880 * input: current pe, peMin, peMax
881 * output: adjusted peMin/peMax
882 *
883 *****************************************************************************/
adjustPeMinMax(const Word16 currPe,Word16 * peMin,Word16 * peMax)884 static void adjustPeMinMax(const Word16 currPe,
885 Word16 *peMin,
886 Word16 *peMax)
887 {
888 Word16 minFacHi, maxFacHi, minFacLo, maxFacLo;
889 Word16 diff;
890 Word16 minDiff = extract_l(currPe / 6);
891 minFacHi = 30;
892 maxFacHi = 100;
893 minFacLo = 14;
894 maxFacLo = 7;
895
896 diff = currPe - *peMax ;
897
898 if (diff > 0) {
899 *peMin = *peMin + ((diff * minFacHi) / 100);
900 *peMax = *peMax + ((diff * maxFacHi) / 100);
901 } else {
902 diff = *peMin - currPe;
903
904 if (diff > 0) {
905 *peMin = *peMin - ((diff * minFacLo) / 100);
906 *peMax = *peMax - ((diff * maxFacLo) / 100);
907 } else {
908 *peMin = *peMin + ((currPe - *peMin) * minFacHi / 100);
909 *peMax = *peMax - ((*peMax - currPe) * maxFacLo / 100);
910 }
911 }
912
913
914 if ((*peMax - *peMin) < minDiff) {
915 Word16 partLo, partHi;
916
917 partLo = max(0, (currPe - *peMin));
918 partHi = max(0, (*peMax - currPe));
919
920 *peMax = currPe + ((partHi * minDiff) / (partLo + partHi));
921 *peMin = currPe - ((partLo * minDiff) / (partLo + partHi));
922 *peMin = max(0, *peMin);
923 }
924 }
925
926
927 /*****************************************************************************
928 *
929 * function name: BitresCalcBitFac
930 * description: calculates factor of spending bits for one frame
931 * 1.0 : take all frame dynpart bits
932 * >1.0 : take all frame dynpart bits + bitres
933 * <1.0 : put bits in bitreservoir
934 * returns: BitFac*100
935 * input: bitres-fullness, pe, blockType, parameter-settings
936 * output:
937 *
938 *****************************************************************************/
bitresCalcBitFac(const Word16 bitresBits,const Word16 maxBitresBits,const Word16 pe,const Word16 windowSequence,const Word16 avgBits,const Word16 maxBitFac,ADJ_THR_STATE * AdjThr,ATS_ELEMENT * adjThrChan)939 static Word16 bitresCalcBitFac( const Word16 bitresBits,
940 const Word16 maxBitresBits,
941 const Word16 pe,
942 const Word16 windowSequence,
943 const Word16 avgBits,
944 const Word16 maxBitFac,
945 ADJ_THR_STATE *AdjThr,
946 ATS_ELEMENT *adjThrChan)
947 {
948 BRES_PARAM *bresParam;
949 Word16 pex;
950 Word16 fillLevel;
951 Word16 bitSave, bitSpend, bitresFac;
952
953 fillLevel = extract_l((100* bitresBits) / maxBitresBits);
954
955 if (windowSequence != SHORT_WINDOW)
956 bresParam = &(AdjThr->bresParamLong);
957 else
958 bresParam = &(AdjThr->bresParamShort);
959
960 pex = max(pe, adjThrChan->peMin);
961 pex = min(pex,adjThrChan->peMax);
962
963 bitSave = calcBitSave(fillLevel,
964 bresParam->clipSaveLow, bresParam->clipSaveHigh,
965 bresParam->minBitSave, bresParam->maxBitSave);
966
967 bitSpend = calcBitSpend(fillLevel,
968 bresParam->clipSpendLow, bresParam->clipSpendHigh,
969 bresParam->minBitSpend, bresParam->maxBitSpend);
970
971 if(adjThrChan->peMax != adjThrChan->peMin)
972 bitresFac = (100 - bitSave) + extract_l(((bitSpend + bitSave) * (pex - adjThrChan->peMin)) /
973 (adjThrChan->peMax - adjThrChan->peMin));
974 else
975 bitresFac = 0x7fff;
976
977 bitresFac = min(bitresFac,
978 (100-30 + extract_l((100 * bitresBits) / avgBits)));
979
980 bitresFac = min(bitresFac, maxBitFac);
981
982 adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax);
983
984 return bitresFac;
985 }
986
987 /*****************************************************************************
988 *
989 * function name: AdjThrInit
990 * description: init thresholds parameter
991 *
992 *****************************************************************************/
AdjThrInit(ADJ_THR_STATE * hAdjThr,const Word32 meanPe,Word32 chBitrate)993 void AdjThrInit(ADJ_THR_STATE *hAdjThr,
994 const Word32 meanPe,
995 Word32 chBitrate)
996 {
997 ATS_ELEMENT* atsElem = &hAdjThr->adjThrStateElem;
998 MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
999
1000 /* common for all elements: */
1001 /* parameters for bitres control */
1002 hAdjThr->bresParamLong.clipSaveLow = 20;
1003 hAdjThr->bresParamLong.clipSaveHigh = 95;
1004 hAdjThr->bresParamLong.minBitSave = -5;
1005 hAdjThr->bresParamLong.maxBitSave = 30;
1006 hAdjThr->bresParamLong.clipSpendLow = 20;
1007 hAdjThr->bresParamLong.clipSpendHigh = 95;
1008 hAdjThr->bresParamLong.minBitSpend = -10;
1009 hAdjThr->bresParamLong.maxBitSpend = 40;
1010
1011 hAdjThr->bresParamShort.clipSaveLow = 20;
1012 hAdjThr->bresParamShort.clipSaveHigh = 75;
1013 hAdjThr->bresParamShort.minBitSave = 0;
1014 hAdjThr->bresParamShort.maxBitSave = 20;
1015 hAdjThr->bresParamShort.clipSpendLow = 20;
1016 hAdjThr->bresParamShort.clipSpendHigh = 75;
1017 hAdjThr->bresParamShort.minBitSpend = -5;
1018 hAdjThr->bresParamShort.maxBitSpend = 50;
1019
1020 /* specific for each element: */
1021
1022 /* parameters for bitres control */
1023 atsElem->peMin = extract_l(((80*meanPe) / 100));
1024 atsElem->peMax = extract_l(((120*meanPe) / 100));
1025
1026 /* additional pe offset to correct pe2bits for low bitrates */
1027 atsElem->peOffset = 0;
1028 if (chBitrate < 32000) {
1029 atsElem->peOffset = max(50, (100 - extract_l((100 * chBitrate) / 32000)));
1030 }
1031
1032 /* avoid hole parameters */
1033 if (chBitrate > 20000) {
1034 atsElem->ahParam.modifyMinSnr = TRUE;
1035 atsElem->ahParam.startSfbL = 15;
1036 atsElem->ahParam.startSfbS = 3;
1037 }
1038 else {
1039 atsElem->ahParam.modifyMinSnr = FALSE;
1040 atsElem->ahParam.startSfbL = 0;
1041 atsElem->ahParam.startSfbS = 0;
1042 }
1043
1044 /* minSnr adaptation */
1045 /* maximum reduction of minSnr goes down to minSnr^maxRed */
1046 msaParam->maxRed = 0x20000000; /* *0.25f */
1047 /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
1048 msaParam->startRatio = 0x0ccccccd; /* 10 */
1049 /* maximum minSnr reduction to minSnr^maxRed is reached for
1050 avgEn/sfbEn >= maxRatio */
1051 msaParam->maxRatio = 0x0020c49c; /* 1000 */
1052 /* helper variables to interpolate minSnr reduction for
1053 avgEn/sfbEn between startRatio and maxRatio */
1054
1055 msaParam->redRatioFac = 0xfb333333; /* -0.75/20 */
1056
1057 msaParam->redOffs = 0x30000000; /* msaParam->redRatioFac * 10*log10(msaParam->startRatio) */
1058
1059
1060 /* pe correction */
1061 atsElem->peLast = 0;
1062 atsElem->dynBitsLast = 0;
1063 atsElem->peCorrectionFactor = 100; /* 1.0 */
1064
1065 }
1066
1067 /*****************************************************************************
1068 *
1069 * function name: calcPeCorrection
1070 * description: calculates the desired perceptual entropy factor
1071 * It is between 0.85 and 1.15
1072 *
1073 *****************************************************************************/
calcPeCorrection(Word16 * correctionFac,const Word16 peAct,const Word16 peLast,const Word16 bitsLast)1074 static void calcPeCorrection(Word16 *correctionFac,
1075 const Word16 peAct,
1076 const Word16 peLast,
1077 const Word16 bitsLast)
1078 {
1079 Word32 peAct100 = 100 * peAct;
1080 Word32 peLast100 = 100 * peLast;
1081 Word16 peBitsLast = bits2pe(bitsLast);
1082
1083 if ((bitsLast > 0) &&
1084 (peAct100 < (150 * peLast)) && (peAct100 > (70 * peLast)) &&
1085 ((120 * peBitsLast) > peLast100 ) && (( 65 * peBitsLast) < peLast100))
1086 {
1087 Word16 newFac = (100 * peLast) / peBitsLast;
1088 /* dead zone */
1089
1090 if (newFac < 100) {
1091 newFac = min(((110 * newFac) / 100), 100);
1092 newFac = max(newFac, 85);
1093 }
1094 else {
1095 newFac = max(((90 * newFac) / 100), 100);
1096 newFac = min(newFac, 115);
1097 }
1098
1099 if ((newFac > 100 && *correctionFac < 100) ||
1100 (newFac < 100 && *correctionFac > 100)) {
1101 *correctionFac = 100;
1102 }
1103 /* faster adaptation towards 1.0, slower in the other direction */
1104
1105 if ((*correctionFac < 100 && newFac < *correctionFac) ||
1106 (*correctionFac > 100 && newFac > *correctionFac))
1107 *correctionFac = (85 * *correctionFac + 15 * newFac) / 100;
1108 else
1109 *correctionFac = (70 * *correctionFac + 30 * newFac) / 100;
1110 *correctionFac = min(*correctionFac, 115);
1111 *correctionFac = max(*correctionFac, 85);
1112 }
1113 else {
1114 *correctionFac = 100;
1115 }
1116 }
1117
1118 /********************************************************************************
1119 *
1120 * function name: AdjustThresholds
1121 * description: Adjust thresholds to the desired bitrate
1122 *
1123 **********************************************************************************/
AdjustThresholds(ADJ_THR_STATE * adjThrState,ATS_ELEMENT * AdjThrStateElement,PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PSY_OUT_ELEMENT * psyOutElement,Word16 * chBitDistribution,Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],QC_OUT_ELEMENT * qcOE,ELEMENT_BITS * elBits,const Word16 nChannels,const Word16 maxBitFac)1124 void AdjustThresholds(ADJ_THR_STATE *adjThrState,
1125 ATS_ELEMENT *AdjThrStateElement,
1126 PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
1127 PSY_OUT_ELEMENT *psyOutElement,
1128 Word16 *chBitDistribution,
1129 Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
1130 Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],
1131 QC_OUT_ELEMENT *qcOE,
1132 ELEMENT_BITS *elBits,
1133 const Word16 nChannels,
1134 const Word16 maxBitFac)
1135 {
1136 PE_DATA peData;
1137 Word16 noRedPe, grantedPe, grantedPeCorr;
1138 Word16 curWindowSequence;
1139 Word16 bitFactor;
1140 Word16 avgBits = (elBits->averageBits - (qcOE->staticBitsUsed + qcOE->ancBitsUsed));
1141 Word16 bitresBits = elBits->bitResLevel;
1142 Word16 maxBitresBits = elBits->maxBits;
1143 Word16 sideInfoBits = (qcOE->staticBitsUsed + qcOE->ancBitsUsed);
1144 Word16 ch;
1145 memset(&peData, 0, sizeof(peData));
1146
1147 prepareSfbPe(&peData, psyOutChannel, logSfbEnergy, sfbNRelevantLines, nChannels, AdjThrStateElement->peOffset);
1148
1149 /* pe without reduction */
1150 calcSfbPe(&peData, psyOutChannel, nChannels);
1151 noRedPe = peData.pe;
1152
1153
1154 curWindowSequence = LONG_WINDOW;
1155
1156 if (nChannels == 2) {
1157
1158 if ((psyOutChannel[0].windowSequence == SHORT_WINDOW) ||
1159 (psyOutChannel[1].windowSequence == SHORT_WINDOW)) {
1160 curWindowSequence = SHORT_WINDOW;
1161 }
1162 }
1163 else {
1164 curWindowSequence = psyOutChannel[0].windowSequence;
1165 }
1166
1167
1168 /* bit factor */
1169 bitFactor = bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe+5*sideInfoBits,
1170 curWindowSequence, avgBits, maxBitFac,
1171 adjThrState,
1172 AdjThrStateElement);
1173
1174 /* desired pe */
1175 grantedPe = ((bitFactor * bits2pe(avgBits)) / 100);
1176
1177 /* correction of pe value */
1178 calcPeCorrection(&(AdjThrStateElement->peCorrectionFactor),
1179 min(grantedPe, noRedPe),
1180 AdjThrStateElement->peLast,
1181 AdjThrStateElement->dynBitsLast);
1182 grantedPeCorr = (grantedPe * AdjThrStateElement->peCorrectionFactor) / 100;
1183
1184
1185 if (grantedPeCorr < noRedPe && noRedPe > peData.offset) {
1186 /* calc threshold necessary for desired pe */
1187 adaptThresholdsToPe(psyOutChannel,
1188 psyOutElement,
1189 logSfbEnergy,
1190 &peData,
1191 nChannels,
1192 grantedPeCorr,
1193 &AdjThrStateElement->ahParam,
1194 &AdjThrStateElement->minSnrAdaptParam);
1195 }
1196
1197 /* calculate relative distribution */
1198 for (ch=0; ch<nChannels; ch++) {
1199 Word16 peOffsDiff = peData.pe - peData.offset;
1200 chBitDistribution[ch] = 200;
1201
1202 if (peOffsDiff > 0) {
1203 Word32 temp = 1000 - (nChannels * 200);
1204 chBitDistribution[ch] = chBitDistribution[ch] +
1205 (temp * peData.peChannelData[ch].pe) / peOffsDiff;
1206 }
1207 }
1208
1209 /* store pe */
1210 qcOE->pe = noRedPe;
1211
1212 /* update last pe */
1213 AdjThrStateElement->peLast = grantedPe;
1214 }
1215
1216 /********************************************************************************
1217 *
1218 * function name: AdjThrUpdate
1219 * description: save dynBitsUsed for correction of bits2pe relation
1220 *
1221 **********************************************************************************/
AdjThrUpdate(ATS_ELEMENT * AdjThrStateElement,const Word16 dynBitsUsed)1222 void AdjThrUpdate(ATS_ELEMENT *AdjThrStateElement,
1223 const Word16 dynBitsUsed)
1224 {
1225 AdjThrStateElement->dynBitsLast = dynBitsUsed;
1226 }
1227
1228
1229