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