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