2
** Copyright 2003-2010, VisualOn, Inc.
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
8
** http://www.apache.org/licenses/LICENSE-2.0
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.
16
/*******************************************************************************
19
Content: Threshold compensation functions
21
*******************************************************************************/
26
#include "adj_thr_data.h"
32
#define minSnrLimit 0x6666 /* 1 dB */
33
#define PEBITS_COEF 0x170a /* 0.18*(1 << 15)*/
35
#define HOLE_THR_LONG 0x2873 /* 0.316*(1 << 15) */
36
#define HOLE_THR_SHORT 0x4000 /* 0.5 *(1 << 15) */
38
#define MS_THRSPREAD_COEF 0x7333 /* 0.9 * (1 << 15) */
40
#define MIN_SNR_COEF 0x651f /* 3.16* (1 << (15 - 2)) */
42
/* values for avoid hole flag */
43
enum _avoid_hole_state {
49
/********************************************************************************
51
* function name:bits2pe
52
* description: convert from bits to pe
53
* pe = 1.18*desiredBits
55
**********************************************************************************/
56
Word16 bits2pe(const Word16 bits) {
57
return (bits + ((PEBITS_COEF * bits) >> 15));
60
/********************************************************************************
62
* function name:calcThreshExp
63
* description: loudness calculation (threshold to the power of redExp)
66
**********************************************************************************/
67
static void calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
68
PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
69
const Word16 nChannels)
71
Word16 ch, sfb, sfbGrp;
72
Word32 *pthrExp, *psfbThre;
73
for (ch=0; ch<nChannels; ch++) {
74
PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
75
for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup)
76
pthrExp = &(thrExp[ch][sfbGrp]);
77
psfbThre = psyOutChan->sfbThreshold + sfbGrp;
78
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
79
*pthrExp = rsqrt(rsqrt(*psfbThre,INT_BITS),INT_BITS);
80
pthrExp++; psfbThre++;
85
/********************************************************************************
87
* function name:adaptMinSnr
88
* description: reduce minSnr requirements for bands with relative low energies
90
**********************************************************************************/
91
static void adaptMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
92
Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
93
MINSNR_ADAPT_PARAM *msaParam,
94
const Word16 nChannels)
96
Word16 ch, sfb, sfbOffs, shift;
99
Word32 startRatio_x_avgEn = 0;
102
for (ch=0; ch<nChannels; ch++) {
103
PSY_OUT_CHANNEL* psyOutChan = &psyOutChannel[ch];
105
/* calc average energy per scalefactor band */
108
for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
109
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
110
avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfbOffs+sfb]);
116
avgEn = avgEn / nSfb;
118
log_avgEn = iLog4(avgEn);
119
startRatio_x_avgEn = fixmul(msaParam->startRatio, avgEn);
123
/* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */
124
for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
125
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
126
if (psyOutChan->sfbEnergy[sfbOffs+sfb] < startRatio_x_avgEn) {
127
Word16 dbRatio, minSnrRed;
131
dbRatio = log_avgEn - logSfbEnergy[ch][sfbOffs+sfb];
132
dbRatio = dbRatio + (dbRatio << 1);
134
minSnrRed = 110 - ((dbRatio + (dbRatio << 1)) >> 2);
135
minSnrRed = max(minSnrRed, 20); /* 110: (0.375(redOffs)+1)*80,
136
3: 0.00375(redRatioFac)*80
137
20: 0.25(maxRed) * 80 */
139
snrRed = minSnrRed * iLog4((psyOutChan->sfbMinSnr[sfbOffs+sfb] << 16));
141
snrRedI si now scaled by 80 (minSnrRed) and 4 (ffr_iLog4)
144
newMinSnr = round16(pow2_xy(snrRed,80*4));
146
psyOutChan->sfbMinSnr[sfbOffs+sfb] = min(newMinSnr, minSnrLimit);
155
/********************************************************************************
157
* function name:initAvoidHoleFlag
158
* description: determine bands where avoid hole is not necessary resp. possible
160
**********************************************************************************/
161
static void initAvoidHoleFlag(Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
162
PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
163
PSY_OUT_ELEMENT* psyOutElement,
164
const Word16 nChannels,
167
Word16 ch, sfb, sfbGrp, shift;
169
Word32* psfbSpreadEn;
171
for (ch=0; ch<nChannels; ch++) {
172
PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
174
if (psyOutChan->windowSequence != SHORT_WINDOW) {
175
for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
176
psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
177
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
178
*psfbSpreadEn = *psfbSpreadEn >> 1; /* 0.5 */
184
for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
185
psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
186
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
187
*psfbSpreadEn = (*psfbSpreadEn >> 1) + (*psfbSpreadEn >> 3); /* 0.63 */
194
/* increase minSnr for local peaks, decrease it for valleys */
195
if (ahParam->modifyMinSnr) {
196
for(ch=0; ch<nChannels; ch++) {
197
PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
199
if (psyOutChan->windowSequence != SHORT_WINDOW)
200
threshold = HOLE_THR_LONG;
202
threshold = HOLE_THR_SHORT;
204
for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
205
Word16 *psfbMinSnr = psyOutChan->sfbMinSnr + sfbGrp;
206
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
207
Word32 sfbEn, sfbEnm1, sfbEnp1, avgEn;
210
sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp+sfb-1];
212
sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp];
214
if (sfb < (psyOutChan->maxSfbPerGroup-1))
215
sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb+1];
217
sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb];
218
avgEn = (sfbEnm1 + sfbEnp1) >> 1;
219
sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb];
221
if (sfbEn > avgEn && avgEn > 0) {
223
shift = norm_l(sfbEn);
224
tmpMinSnr = Div_32(L_mpy_ls(avgEn, minSnrLimit) << shift, sfbEn << shift );
225
tmpMinSnr = max(tmpMinSnr, HOLE_THR_LONG);
226
tmpMinSnr = max(tmpMinSnr, threshold);
227
*psfbMinSnr = min(*psfbMinSnr, tmpMinSnr);
231
if ((sfbEn < (avgEn >> 1)) && (sfbEn > 0)) {
233
Word32 minSnrEn = L_mpy_wx(avgEn, *psfbMinSnr);
235
if(minSnrEn < sfbEn) {
236
shift = norm_l(sfbEn);
237
tmpMinSnr = Div_32( minSnrEn << shift, sfbEn<<shift);
242
tmpMinSnr = min(minSnrLimit, tmpMinSnr);
245
(min((tmpMinSnr >> 2), mult(*psfbMinSnr, MIN_SNR_COEF)) << 2);
253
/* stereo: adapt the minimum requirements sfbMinSnr of mid and
256
if (nChannels == 2) {
257
PSY_OUT_CHANNEL *psyOutChanM = &psyOutChannel[0];
258
PSY_OUT_CHANNEL *psyOutChanS = &psyOutChannel[1];
259
for (sfb=0; sfb<psyOutChanM->sfbCnt; sfb++) {
260
if (psyOutElement->toolsInfo.msMask[sfb]) {
261
Word32 sfbEnM = psyOutChanM->sfbEnergy[sfb];
262
Word32 sfbEnS = psyOutChanS->sfbEnergy[sfb];
263
Word32 maxSfbEn = max(sfbEnM, sfbEnS);
264
Word32 maxThr = L_mpy_wx(maxSfbEn, psyOutChanM->sfbMinSnr[sfb]) >> 1;
266
if(maxThr >= sfbEnM) {
267
psyOutChanM->sfbMinSnr[sfb] = MAX_16;
270
shift = norm_l(sfbEnM);
271
psyOutChanM->sfbMinSnr[sfb] = min(max(psyOutChanM->sfbMinSnr[sfb],
272
round16(Div_32(maxThr<<shift, sfbEnM << shift))), minSnrLimit);
275
if(maxThr >= sfbEnS) {
276
psyOutChanS->sfbMinSnr[sfb] = MAX_16;
279
shift = norm_l(sfbEnS);
280
psyOutChanS->sfbMinSnr[sfb] = min(max(psyOutChanS->sfbMinSnr[sfb],
281
round16(Div_32(maxThr << shift, sfbEnS << shift))), minSnrLimit);
285
if (sfbEnM > psyOutChanM->sfbSpreadedEnergy[sfb])
286
psyOutChanS->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnS, MS_THRSPREAD_COEF);
288
if (sfbEnS > psyOutChanS->sfbSpreadedEnergy[sfb])
289
psyOutChanM->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnM, MS_THRSPREAD_COEF);
295
/* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
296
for(ch=0; ch<nChannels; ch++) {
297
PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
298
for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
299
Word16 *pahFlag = ahFlag[ch] + sfbGrp;
300
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
302
if ((psyOutChan->sfbSpreadedEnergy[sfbGrp+sfb] > psyOutChan->sfbEnergy[sfbGrp+sfb]) ||
303
(psyOutChan->sfbEnergy[sfbGrp+sfb] <= psyOutChan->sfbThreshold[sfbGrp+sfb]) ||
304
(psyOutChan->sfbMinSnr[sfbGrp+sfb] == MAX_16)) {
308
*pahFlag++ = AH_INACTIVE;
311
for (sfb=psyOutChan->maxSfbPerGroup; sfb<psyOutChan->sfbPerGroup; sfb++) {
318
/********************************************************************************
320
* function name:calcPeNoAH
321
* description: sum the pe data only for bands where avoid hole is inactive
323
**********************************************************************************/
324
static void calcPeNoAH(Word16 *pe,
326
Word16 *nActiveLines,
328
Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
329
PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
330
const Word16 nChannels)
332
Word16 ch, sfb, sfbGrp;
333
int ipe, iconstPart, inActiveLines;
338
for(ch=0; ch<nChannels; ch++) {
339
PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
340
PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
341
for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
342
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
344
if (ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) {
345
ipe = ipe + peChanData->sfbPe[sfbGrp+sfb];
346
iconstPart = iconstPart + peChanData->sfbConstPart[sfbGrp+sfb];
347
inActiveLines = inActiveLines + peChanData->sfbNActiveLines[sfbGrp+sfb];
354
*constPart = saturate(iconstPart);
355
*nActiveLines = saturate(inActiveLines);
358
/********************************************************************************
360
* function name:reduceThresholds
361
* description: apply reduction formula
363
**********************************************************************************/
364
static void reduceThresholds(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
365
Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
366
Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
367
const Word16 nChannels,
370
Word32 sfbThrReduced;
371
Word32 *psfbEn, *psfbThr;
372
Word16 ch, sfb, sfbGrp;
374
for(ch=0; ch<nChannels; ch++) {
375
PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
376
for(sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) {
377
psfbEn = psyOutChan->sfbEnergy + sfbGrp;
378
psfbThr = psyOutChan->sfbThreshold + sfbGrp;
379
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
381
if (*psfbEn > *psfbThr) {
382
/* threshold reduction formula */
383
Word32 tmp = thrExp[ch][sfbGrp+sfb] + redVal;
384
tmp = fixmul(tmp, tmp);
385
sfbThrReduced = fixmul(tmp, tmp);
387
tmp = L_mpy_ls(*psfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
389
if ((sfbThrReduced > tmp) &&
390
(ahFlag[ch][sfbGrp+sfb] != NO_AH)){
391
sfbThrReduced = max(tmp, *psfbThr);
392
ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
394
*psfbThr = sfbThrReduced;
404
/********************************************************************************
406
* function name:correctThresh
407
* description: if pe difference deltaPe between desired pe and real pe is small enough,
408
* the difference can be distributed among the scale factor bands.
410
**********************************************************************************/
411
static void correctThresh(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
412
Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
414
Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
416
const Word16 nChannels,
417
const Word32 deltaPe)
419
Word16 ch, sfb, sfbGrp,shift;
420
PSY_OUT_CHANNEL *psyOutChan;
421
PE_CHANNEL_DATA *peChanData;
424
Word32 *psfbPeFactors;
425
Word16 *psfbNActiveLines, *pahFlag;
426
Word32 sfbEn, sfbThr;
427
Word32 sfbThrReduced;
429
/* for each sfb calc relative factors for pe changes */
431
for(ch=0; ch<nChannels; ch++) {
432
psyOutChan = &psyOutChannel[ch];
433
peChanData = &peData->peChannelData[ch];
434
for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
435
psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
436
psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
437
pahFlag = ahFlag[ch] + sfbGrp;
438
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
439
Word32 redThrExp = thrExp[ch][sfbGrp+sfb] + redVal;
441
if (((*pahFlag < AH_ACTIVE) || (deltaPe > 0)) && (redThrExp > 0) ) {
443
*psfbPeFactors = (*psfbNActiveLines) * (0x7fffffff / redThrExp);
444
normFactor = L_add(normFactor, *psfbPeFactors);
450
pahFlag++; psfbNActiveLines++;
456
/* calculate new thresholds */
457
for(ch=0; ch<nChannels; ch++) {
458
psyOutChan = &psyOutChannel[ch];
459
peChanData = &peData->peChannelData[ch];
460
for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
461
psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
462
psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
463
pahFlag = ahFlag[ch] + sfbGrp;
464
for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
465
/* pe difference for this sfb */
466
deltaSfbPe = *psfbPeFactors * deltaPe;
468
/* thr3(n) = thr2(n)*2^deltaSfbPe/b(n) */
469
if (*psfbNActiveLines > 0) {
472
sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb];
473
sfbThr = psyOutChan->sfbThreshold[sfbGrp+sfb];
479
thrFactor = pow2_xy(L_negate(deltaSfbPe), (normFactor* (*psfbNActiveLines)));
481
sfbThrReduced = L_mpy_ls(sfbThr, round16(thrFactor));
487
thrFactor = pow2_xy(deltaSfbPe, (normFactor * (*psfbNActiveLines)));
490
if(thrFactor > sfbThr) {
491
shift = norm_l(thrFactor);
492
sfbThrReduced = Div_32( sfbThr << shift, thrFactor<<shift );
495
sfbThrReduced = MAX_32;
501
sfbEn = L_mpy_ls(sfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
503
if ((sfbThrReduced > sfbEn) &&
504
(*pahFlag == AH_INACTIVE)) {
505
sfbThrReduced = max(sfbEn, sfbThr);
506
*pahFlag = AH_ACTIVE;
509
psyOutChan->sfbThreshold[sfbGrp+sfb] = sfbThrReduced;
512
pahFlag++; psfbNActiveLines++; psfbPeFactors++;
519
/********************************************************************************
521
* function name:reduceMinSnr
522
* description: if the desired pe can not be reached, reduce pe by reducing minSnr
524
**********************************************************************************/
525
static void reduceMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
527
Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
528
const Word16 nChannels,
529
const Word16 desiredPe)
531
Word16 ch, sfb, sfbSubWin;
534
/* start at highest freq down to 0 */
535
sfbSubWin = psyOutChannel[0].maxSfbPerGroup;
536
while (peData->pe > desiredPe && sfbSubWin > 0) {
538
sfbSubWin = sfbSubWin - 1;
539
/* loop over all subwindows */
540
for (sfb=sfbSubWin; sfb<psyOutChannel[0].sfbCnt;
541
sfb+=psyOutChannel[0].sfbPerGroup) {
542
/* loop over all channels */
543
PE_CHANNEL_DATA* peChan = peData->peChannelData;
544
PSY_OUT_CHANNEL* psyOutCh = psyOutChannel;
545
for (ch=0; ch<nChannels; ch++) {
546
if (ahFlag[ch][sfb] != NO_AH &&
547
psyOutCh->sfbMinSnr[sfb] < minSnrLimit) {
548
psyOutCh->sfbMinSnr[sfb] = minSnrLimit;
549
psyOutCh->sfbThreshold[sfb] =
550
L_mpy_ls(psyOutCh->sfbEnergy[sfb], psyOutCh->sfbMinSnr[sfb]);
553
deltaPe = ((peChan->sfbNLines4[sfb] + (peChan->sfbNLines4[sfb] >> 1)) >> 2) -
555
peData->pe = peData->pe + deltaPe;
556
peChan->pe = peChan->pe + deltaPe;
558
peChan += 1; psyOutCh += 1;
560
/* stop if enough has been saved */
562
if (peData->pe <= desiredPe)
568
/********************************************************************************
570
* function name:allowMoreHoles
571
* description: if the desired pe can not be reached, some more scalefactor bands
572
* have to be quantized to zero
574
**********************************************************************************/
575
static void allowMoreHoles(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
576
PSY_OUT_ELEMENT *psyOutElement,
578
Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
579
const AH_PARAM *ahParam,
580
const Word16 nChannels,
581
const Word16 desiredPe)
588
/* for MS allow hole in the channel with less energy */
591
psyOutChannel[0].windowSequence==psyOutChannel[1].windowSequence) {
592
PSY_OUT_CHANNEL *psyOutChanL = &psyOutChannel[0];
593
PSY_OUT_CHANNEL *psyOutChanR = &psyOutChannel[1];
594
for (sfb=0; sfb<psyOutChanL->sfbCnt; sfb++) {
597
if (psyOutElement->toolsInfo.msMask[sfb]) {
598
/* allow hole in side channel ? */
599
minEn = L_mpy_ls(psyOutChanL->sfbEnergy[sfb], (minSnrLimit * psyOutChanL->sfbMinSnr[sfb]) >> 16);
601
if (ahFlag[1][sfb] != NO_AH &&
602
minEn > psyOutChanR->sfbEnergy[sfb]) {
603
ahFlag[1][sfb] = NO_AH;
604
psyOutChanR->sfbThreshold[sfb] = L_add(psyOutChanR->sfbEnergy[sfb], psyOutChanR->sfbEnergy[sfb]);
605
actPe = actPe - peData->peChannelData[1].sfbPe[sfb];
607
/* allow hole in mid channel ? */
609
minEn = L_mpy_ls(psyOutChanR->sfbEnergy[sfb], (minSnrLimit * psyOutChanR->sfbMinSnr[sfb]) >> 16);
611
if (ahFlag[0][sfb]!= NO_AH &&
612
minEn > psyOutChanL->sfbEnergy[sfb]) {
613
ahFlag[0][sfb] = NO_AH;
614
psyOutChanL->sfbThreshold[sfb] = L_add(psyOutChanL->sfbEnergy[sfb], psyOutChanL->sfbEnergy[sfb]);
615
actPe = actPe - peData->peChannelData[0].sfbPe[sfb];
619
if (actPe < desiredPe)
625
/* subsequently erase bands */
626
if (actPe > desiredPe) {
633
Word16 minSfb, maxSfb;
636
/* do not go below startSfb */
637
for (ch=0; ch<nChannels; ch++) {
639
if (psyOutChannel[ch].windowSequence != SHORT_WINDOW)
640
startSfb[ch] = ahParam->startSfbL;
642
startSfb[ch] = ahParam->startSfbS;
648
for (ch=0; ch<nChannels; ch++) {
649
PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
650
for (sfb=startSfb[ch]; sfb<psyOutChan->sfbCnt; sfb++) {
652
if ((ahFlag[ch][sfb] != NO_AH) &&
653
(psyOutChan->sfbEnergy[sfb] > psyOutChan->sfbThreshold[sfb])) {
654
minEn = min(minEn, psyOutChan->sfbEnergy[sfb]);
655
avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfb]);
663
shift = norm_l(ahCnt);
664
iahCnt = Div_32( 1 << shift, ahCnt << shift );
665
avgEn = fixmul(avgEn, iahCnt);
668
enDiff = iLog4(avgEn) - iLog4(minEn);
669
/* calc some energy borders between minEn and avgEn */
670
for (enIdx=0; enIdx<4; enIdx++) {
672
enFac = ((6-(enIdx << 1)) * enDiff);
673
en[enIdx] = fixmul(avgEn, pow2_xy(L_negate(enFac),7*4));
676
/* start with lowest energy border at highest sfb */
677
maxSfb = psyOutChannel[0].sfbCnt - 1;
678
minSfb = startSfb[0];
680
if (nChannels == 2) {
681
maxSfb = max(maxSfb, (psyOutChannel[1].sfbCnt - 1));
682
minSfb = min(minSfb, startSfb[1]);
690
for (ch=0; ch<nChannels; ch++) {
691
PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
693
if (sfb>=startSfb[ch] && sfb<psyOutChan->sfbCnt) {
694
/* sfb energy below border ? */
696
if (ahFlag[ch][sfb] != NO_AH && psyOutChan->sfbEnergy[sfb] < en[enIdx]){
698
ahFlag[ch][sfb] = NO_AH;
699
psyOutChan->sfbThreshold[sfb] = L_add(psyOutChan->sfbEnergy[sfb], psyOutChan->sfbEnergy[sfb]);
700
actPe = actPe - peData->peChannelData[ch].sfbPe[sfb];
703
if (actPe < desiredPe) {
712
/* restart with next energy border */
723
/********************************************************************************
725
* function name:adaptThresholdsToPe
726
* description: two guesses for the reduction value and one final correction of the
729
**********************************************************************************/
730
static void adaptThresholdsToPe(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
731
PSY_OUT_ELEMENT *psyOutElement,
732
Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
734
const Word16 nChannels,
735
const Word16 desiredPe,
737
MINSNR_ADAPT_PARAM *msaParam)
739
Word16 noRedPe, redPe, redPeNoAH;
740
Word16 constPart, constPartNoAH;
741
Word16 nActiveLines, nActiveLinesNoAH;
742
Word16 desiredPeNoAH;
743
Word32 redVal, avgThrExp;
746
calcThreshExp(peData->thrExp, psyOutChannel, nChannels);
748
adaptMinSnr(psyOutChannel, logSfbEnergy, msaParam, nChannels);
750
initAvoidHoleFlag(peData->ahFlag, psyOutChannel, psyOutElement, nChannels, ahParam);
752
noRedPe = peData->pe;
753
constPart = peData->constPart;
754
nActiveLines = peData->nActiveLines;
756
/* first guess of reduction value t^0.25 = 2^((a-pen)/4*b) */
757
avgThrExp = pow2_xy((constPart - noRedPe), (nActiveLines << 2));
759
/* r1 = 2^((a-per)/4*b) - t^0.25 */
760
redVal = pow2_xy((constPart - desiredPe), (nActiveLines << 2)) - avgThrExp;
762
/* reduce thresholds */
763
reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
765
/* pe after first guess */
766
calcSfbPe(peData, psyOutChannel, nChannels);
771
/* pe for bands where avoid hole is inactive */
772
calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH,
773
peData, peData->ahFlag, psyOutChannel, nChannels);
775
desiredPeNoAH = desiredPe -(redPe - redPeNoAH);
777
if (desiredPeNoAH < 0) {
783
if (nActiveLinesNoAH > 0) {
785
avgThrExp = pow2_xy((constPartNoAH - redPeNoAH), (nActiveLinesNoAH << 2));
787
redVal = (redVal + pow2_xy((constPartNoAH - desiredPeNoAH), (nActiveLinesNoAH << 2))) - avgThrExp;
789
/* reduce thresholds */
790
reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
793
calcSfbPe(peData, psyOutChannel, nChannels);
798
} while ((20 * abs_s(redPe - desiredPe) > desiredPe) && (iter < 2));
801
if ((100 * redPe < 115 * desiredPe)) {
802
correctThresh(psyOutChannel, peData->ahFlag, peData, peData->thrExp, redVal,
803
nChannels, desiredPe - redPe);
806
Word16 desiredPe105 = (105 * desiredPe) / 100;
807
reduceMinSnr(psyOutChannel, peData, peData->ahFlag,
808
nChannels, desiredPe105);
809
allowMoreHoles(psyOutChannel, psyOutElement, peData, peData->ahFlag,
810
ahParam, nChannels, desiredPe105);
815
/*****************************************************************************
817
* function name: calcBitSave
818
* description: Calculates percentage of bit save, see figure below
820
* input: parameters and bitres-fullness
821
* output: percentage of bit save
823
*****************************************************************************/
824
static Word16 calcBitSave(Word16 fillLevel,
825
const Word16 clipLow,
826
const Word16 clipHigh,
827
const Word16 minBitSave,
828
const Word16 maxBitSave)
832
fillLevel = max(fillLevel, clipLow);
833
fillLevel = min(fillLevel, clipHigh);
836
bitsave = (maxBitSave - (((maxBitSave-minBitSave)*(fillLevel-clipLow))/
837
(clipHigh-clipLow)));
844
/*****************************************************************************
846
* function name: calcBitSpend
847
* description: Calculates percentage of bit spend, see figure below
849
* input: parameters and bitres-fullness
850
* output: percentage of bit spend
852
*****************************************************************************/
853
static Word16 calcBitSpend(Word16 fillLevel,
854
const Word16 clipLow,
855
const Word16 clipHigh,
856
const Word16 minBitSpend,
857
const Word16 maxBitSpend)
861
fillLevel = max(fillLevel, clipLow);
862
fillLevel = min(fillLevel, clipHigh);
865
bitspend = (minBitSpend + ((maxBitSpend - minBitSpend)*(fillLevel - clipLow) /
866
(clipHigh-clipLow)));
872
/*****************************************************************************
874
* function name: adjustPeMinMax()
875
* description: adjusts peMin and peMax parameters over time
877
* input: current pe, peMin, peMax
878
* output: adjusted peMin/peMax
880
*****************************************************************************/
881
static void adjustPeMinMax(const Word16 currPe,
885
Word16 minFacHi, maxFacHi, minFacLo, maxFacLo;
887
Word16 minDiff = extract_l(currPe / 6);
893
diff = currPe - *peMax ;
896
*peMin = *peMin + ((diff * minFacHi) / 100);
897
*peMax = *peMax + ((diff * maxFacHi) / 100);
899
diff = *peMin - currPe;
902
*peMin = *peMin - ((diff * minFacLo) / 100);
903
*peMax = *peMax - ((diff * maxFacLo) / 100);
905
*peMin = *peMin + ((currPe - *peMin) * minFacHi / 100);
906
*peMax = *peMax - ((*peMax - currPe) * maxFacLo / 100);
911
if ((*peMax - *peMin) < minDiff) {
912
Word16 partLo, partHi;
914
partLo = max(0, (currPe - *peMin));
915
partHi = max(0, (*peMax - currPe));
917
*peMax = currPe + ((partHi * minDiff) / (partLo + partHi));
918
*peMin = currPe - ((partLo * minDiff) / (partLo + partHi));
919
*peMin = max(0, *peMin);
924
/*****************************************************************************
926
* function name: BitresCalcBitFac
927
* description: calculates factor of spending bits for one frame
928
* 1.0 : take all frame dynpart bits
929
* >1.0 : take all frame dynpart bits + bitres
930
* <1.0 : put bits in bitreservoir
931
* returns: BitFac*100
932
* input: bitres-fullness, pe, blockType, parameter-settings
935
*****************************************************************************/
936
static Word16 bitresCalcBitFac( const Word16 bitresBits,
937
const Word16 maxBitresBits,
939
const Word16 windowSequence,
940
const Word16 avgBits,
941
const Word16 maxBitFac,
942
ADJ_THR_STATE *AdjThr,
943
ATS_ELEMENT *adjThrChan)
945
BRES_PARAM *bresParam;
948
Word16 bitSave, bitSpend, bitresFac;
950
fillLevel = extract_l((100* bitresBits) / maxBitresBits);
952
if (windowSequence != SHORT_WINDOW)
953
bresParam = &(AdjThr->bresParamLong);
955
bresParam = &(AdjThr->bresParamShort);
957
pex = max(pe, adjThrChan->peMin);
958
pex = min(pex,adjThrChan->peMax);
960
bitSave = calcBitSave(fillLevel,
961
bresParam->clipSaveLow, bresParam->clipSaveHigh,
962
bresParam->minBitSave, bresParam->maxBitSave);
964
bitSpend = calcBitSpend(fillLevel,
965
bresParam->clipSpendLow, bresParam->clipSpendHigh,
966
bresParam->minBitSpend, bresParam->maxBitSpend);
968
if(adjThrChan->peMax != adjThrChan->peMin)
969
bitresFac = (100 - bitSave) + extract_l(((bitSpend + bitSave) * (pex - adjThrChan->peMin)) /
970
(adjThrChan->peMax - adjThrChan->peMin));
974
bitresFac = min(bitresFac,
975
(100-30 + extract_l((100 * bitresBits) / avgBits)));
977
bitresFac = min(bitresFac, maxBitFac);
979
adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax);
984
/*****************************************************************************
986
* function name: AdjThrInit
987
* description: init thresholds parameter
989
*****************************************************************************/
990
void AdjThrInit(ADJ_THR_STATE *hAdjThr,
994
ATS_ELEMENT* atsElem = &hAdjThr->adjThrStateElem;
995
MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
997
/* common for all elements: */
998
/* parameters for bitres control */
999
hAdjThr->bresParamLong.clipSaveLow = 20;
1000
hAdjThr->bresParamLong.clipSaveHigh = 95;
1001
hAdjThr->bresParamLong.minBitSave = -5;
1002
hAdjThr->bresParamLong.maxBitSave = 30;
1003
hAdjThr->bresParamLong.clipSpendLow = 20;
1004
hAdjThr->bresParamLong.clipSpendHigh = 95;
1005
hAdjThr->bresParamLong.minBitSpend = -10;
1006
hAdjThr->bresParamLong.maxBitSpend = 40;
1008
hAdjThr->bresParamShort.clipSaveLow = 20;
1009
hAdjThr->bresParamShort.clipSaveHigh = 75;
1010
hAdjThr->bresParamShort.minBitSave = 0;
1011
hAdjThr->bresParamShort.maxBitSave = 20;
1012
hAdjThr->bresParamShort.clipSpendLow = 20;
1013
hAdjThr->bresParamShort.clipSpendHigh = 75;
1014
hAdjThr->bresParamShort.minBitSpend = -5;
1015
hAdjThr->bresParamShort.maxBitSpend = 50;
1017
/* specific for each element: */
1019
/* parameters for bitres control */
1020
atsElem->peMin = extract_l(((80*meanPe) / 100));
1021
atsElem->peMax = extract_l(((120*meanPe) / 100));
1023
/* additional pe offset to correct pe2bits for low bitrates */
1024
atsElem->peOffset = 0;
1025
if (chBitrate < 32000) {
1026
atsElem->peOffset = max(50, (100 - extract_l((100 * chBitrate) / 32000)));
1029
/* avoid hole parameters */
1030
if (chBitrate > 20000) {
1031
atsElem->ahParam.modifyMinSnr = TRUE;
1032
atsElem->ahParam.startSfbL = 15;
1033
atsElem->ahParam.startSfbS = 3;
1036
atsElem->ahParam.modifyMinSnr = FALSE;
1037
atsElem->ahParam.startSfbL = 0;
1038
atsElem->ahParam.startSfbS = 0;
1041
/* minSnr adaptation */
1042
/* maximum reduction of minSnr goes down to minSnr^maxRed */
1043
msaParam->maxRed = 0x20000000; /* *0.25f /
1044
/* start adaptation of minSnr for avgEn/sfbEn > startRatio */
1045
msaParam->startRatio = 0x0ccccccd; /* 10 */
1046
/* maximum minSnr reduction to minSnr^maxRed is reached for
1047
avgEn/sfbEn >= maxRatio */
1048
msaParam->maxRatio = 0x0020c49c; /* 1000 */
1049
/* helper variables to interpolate minSnr reduction for
1050
avgEn/sfbEn between startRatio and maxRatio */
1052
msaParam->redRatioFac = 0xfb333333; /* -0.75/20 */
1054
msaParam->redOffs = 0x30000000; /* msaParam->redRatioFac * 10*log10(msaParam->startRatio) */
1058
atsElem->peLast = 0;
1059
atsElem->dynBitsLast = 0;
1060
atsElem->peCorrectionFactor = 100; /* 1.0 */
1064
/*****************************************************************************
1066
* function name: calcPeCorrection
1067
* description: calculates the desired perceptual entropy factor
1068
* It is between 0.85 and 1.15
1070
*****************************************************************************/
1071
static void calcPeCorrection(Word16 *correctionFac,
1073
const Word16 peLast,
1074
const Word16 bitsLast)
1076
Word32 peAct100 = 100 * peAct;
1077
Word32 peLast100 = 100 * peLast;
1078
Word16 peBitsLast = bits2pe(bitsLast);
1080
if ((bitsLast > 0) &&
1081
(peAct100 < (150 * peLast)) && (peAct100 > (70 * peLast)) &&
1082
((120 * peBitsLast) > peLast100 ) && (( 65 * peBitsLast) < peLast100))
1084
Word16 newFac = (100 * peLast) / peBitsLast;
1088
newFac = min(((110 * newFac) / 100), 100);
1089
newFac = max(newFac, 85);
1092
newFac = max(((90 * newFac) / 100), 100);
1093
newFac = min(newFac, 115);
1096
if ((newFac > 100 && *correctionFac < 100) ||
1097
(newFac < 100 && *correctionFac > 100)) {
1098
*correctionFac = 100;
1100
/* faster adaptation towards 1.0, slower in the other direction */
1102
if ((*correctionFac < 100 && newFac < *correctionFac) ||
1103
(*correctionFac > 100 && newFac > *correctionFac))
1104
*correctionFac = (85 * *correctionFac + 15 * newFac) / 100;
1106
*correctionFac = (70 * *correctionFac + 30 * newFac) / 100;
1107
*correctionFac = min(*correctionFac, 115);
1108
*correctionFac = max(*correctionFac, 85);
1111
*correctionFac = 100;
1115
/********************************************************************************
1117
* function name: AdjustThresholds
1118
* description: Adjust thresholds to the desired bitrate
1120
**********************************************************************************/
1121
void AdjustThresholds(ADJ_THR_STATE *adjThrState,
1122
ATS_ELEMENT *AdjThrStateElement,
1123
PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
1124
PSY_OUT_ELEMENT *psyOutElement,
1125
Word16 *chBitDistribution,
1126
Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
1127
Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],
1128
QC_OUT_ELEMENT *qcOE,
1129
ELEMENT_BITS *elBits,
1130
const Word16 nChannels,
1131
const Word16 maxBitFac)
1134
Word16 noRedPe, grantedPe, grantedPeCorr;
1135
Word16 curWindowSequence;
1137
Word16 avgBits = (elBits->averageBits - (qcOE->staticBitsUsed + qcOE->ancBitsUsed));
1138
Word16 bitresBits = elBits->bitResLevel;
1139
Word16 maxBitresBits = elBits->maxBits;
1140
Word16 sideInfoBits = (qcOE->staticBitsUsed + qcOE->ancBitsUsed);
1142
memset(&peData, 0, sizeof(peData));
1144
prepareSfbPe(&peData, psyOutChannel, logSfbEnergy, sfbNRelevantLines, nChannels, AdjThrStateElement->peOffset);
1146
/* pe without reduction */
1147
calcSfbPe(&peData, psyOutChannel, nChannels);
1148
noRedPe = peData.pe;
1151
curWindowSequence = LONG_WINDOW;
1153
if (nChannels == 2) {
1155
if ((psyOutChannel[0].windowSequence == SHORT_WINDOW) ||
1156
(psyOutChannel[1].windowSequence == SHORT_WINDOW)) {
1157
curWindowSequence = SHORT_WINDOW;
1161
curWindowSequence = psyOutChannel[0].windowSequence;
1166
bitFactor = bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe+5*sideInfoBits,
1167
curWindowSequence, avgBits, maxBitFac,
1169
AdjThrStateElement);
1172
grantedPe = ((bitFactor * bits2pe(avgBits)) / 100);
1174
/* correction of pe value */
1175
calcPeCorrection(&(AdjThrStateElement->peCorrectionFactor),
1176
min(grantedPe, noRedPe),
1177
AdjThrStateElement->peLast,
1178
AdjThrStateElement->dynBitsLast);
1179
grantedPeCorr = (grantedPe * AdjThrStateElement->peCorrectionFactor) / 100;
1182
if (grantedPeCorr < noRedPe && noRedPe > peData.offset) {
1183
/* calc threshold necessary for desired pe */
1184
adaptThresholdsToPe(psyOutChannel,
1190
&AdjThrStateElement->ahParam,
1191
&AdjThrStateElement->minSnrAdaptParam);
1194
/* calculate relative distribution */
1195
for (ch=0; ch<nChannels; ch++) {
1196
Word16 peOffsDiff = peData.pe - peData.offset;
1197
chBitDistribution[ch] = 200;
1199
if (peOffsDiff > 0) {
1200
Word32 temp = 1000 - (nChannels * 200);
1201
chBitDistribution[ch] = chBitDistribution[ch] +
1202
(temp * peData.peChannelData[ch].pe) / peOffsDiff;
1209
/* update last pe */
1210
AdjThrStateElement->peLast = grantedPe;
1213
/********************************************************************************
1215
* function name: AdjThrUpdate
1216
* description: save dynBitsUsed for correction of bits2pe relation
1218
**********************************************************************************/
1219
void AdjThrUpdate(ATS_ELEMENT *AdjThrStateElement,
1220
const Word16 dynBitsUsed)
1222
AdjThrStateElement->dynBitsLast = dynBitsUsed;