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