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: psy_main.c 18 19 Content: Psychoacoustic major functions 20 21 *******************************************************************************/ 22 23 #include "typedef.h" 24 #include "basic_op.h" 25 #include "oper_32b.h" 26 #include "psy_const.h" 27 #include "block_switch.h" 28 #include "transform.h" 29 #include "spreading.h" 30 #include "pre_echo_control.h" 31 #include "band_nrg.h" 32 #include "psy_configuration.h" 33 #include "psy_data.h" 34 #include "ms_stereo.h" 35 #include "interface.h" 36 #include "psy_main.h" 37 #include "grp_data.h" 38 #include "tns_func.h" 39 #include "memalign.h" 40 41 /* long start short stop */ 42 static Word16 blockType2windowShape[] = {KBD_WINDOW,SINE_WINDOW,SINE_WINDOW,KBD_WINDOW}; 43 44 /* 45 forward definitions 46 */ 47 static Word16 advancePsychLong(PSY_DATA* psyData, 48 TNS_DATA* tnsData, 49 PSY_CONFIGURATION_LONG *hPsyConfLong, 50 PSY_OUT_CHANNEL* psyOutChannel, 51 Word32 *pScratchTns, 52 const TNS_DATA *tnsData2, 53 const Word16 ch); 54 55 static Word16 advancePsychLongMS (PSY_DATA psyData[MAX_CHANNELS], 56 const PSY_CONFIGURATION_LONG *hPsyConfLong); 57 58 static Word16 advancePsychShort(PSY_DATA* psyData, 59 TNS_DATA* tnsData, 60 const PSY_CONFIGURATION_SHORT *hPsyConfShort, 61 PSY_OUT_CHANNEL* psyOutChannel, 62 Word32 *pScratchTns, 63 const TNS_DATA *tnsData2, 64 const Word16 ch); 65 66 static Word16 advancePsychShortMS (PSY_DATA psyData[MAX_CHANNELS], 67 const PSY_CONFIGURATION_SHORT *hPsyConfShort); 68 69 70 /***************************************************************************** 71 * 72 * function name: PsyNew 73 * description: allocates memory for psychoacoustic 74 * returns: an error code 75 * input: pointer to a psych handle 76 * 77 *****************************************************************************/ 78 Word16 PsyNew(PSY_KERNEL *hPsy, Word32 nChan, VO_MEM_OPERATOR *pMemOP) 79 { 80 Word16 i; 81 Word32 *mdctSpectrum; 82 Word32 *scratchTNS; 83 Word16 *mdctDelayBuffer; 84 85 mdctSpectrum = (Word32 *)mem_malloc(pMemOP, nChan * FRAME_LEN_LONG * sizeof(Word32), 32, VO_INDEX_ENC_AAC); 86 if(NULL == mdctSpectrum) 87 return 1; 88 89 scratchTNS = (Word32 *)mem_malloc(pMemOP, nChan * FRAME_LEN_LONG * sizeof(Word32), 32, VO_INDEX_ENC_AAC); 90 if(NULL == scratchTNS) 91 { 92 return 1; 93 } 94 95 mdctDelayBuffer = (Word16 *)mem_malloc(pMemOP, nChan * BLOCK_SWITCHING_OFFSET * sizeof(Word16), 32, VO_INDEX_ENC_AAC); 96 if(NULL == mdctDelayBuffer) 97 { 98 return 1; 99 } 100 101 for (i=0; i<nChan; i++){ 102 hPsy->psyData[i].mdctDelayBuffer = mdctDelayBuffer + i*BLOCK_SWITCHING_OFFSET; 103 hPsy->psyData[i].mdctSpectrum = mdctSpectrum + i*FRAME_LEN_LONG; 104 } 105 106 hPsy->pScratchTns = scratchTNS; 107 108 return 0; 109 } 110 111 112 /***************************************************************************** 113 * 114 * function name: PsyDelete 115 * description: allocates memory for psychoacoustic 116 * returns: an error code 117 * 118 *****************************************************************************/ 119 Word16 PsyDelete(PSY_KERNEL *hPsy, VO_MEM_OPERATOR *pMemOP) 120 { 121 Word32 nch; 122 123 if(hPsy) 124 { 125 if(hPsy->psyData[0].mdctDelayBuffer) 126 mem_free(pMemOP, hPsy->psyData[0].mdctDelayBuffer, VO_INDEX_ENC_AAC); 127 128 if(hPsy->psyData[0].mdctSpectrum) 129 mem_free(pMemOP, hPsy->psyData[0].mdctSpectrum, VO_INDEX_ENC_AAC); 130 131 for (nch=0; nch<MAX_CHANNELS; nch++){ 132 hPsy->psyData[nch].mdctDelayBuffer = NULL; 133 hPsy->psyData[nch].mdctSpectrum = NULL; 134 } 135 136 if(hPsy->pScratchTns) 137 { 138 mem_free(pMemOP, hPsy->pScratchTns, VO_INDEX_ENC_AAC); 139 hPsy->pScratchTns = NULL; 140 } 141 } 142 143 return 0; 144 } 145 146 147 /***************************************************************************** 148 * 149 * function name: PsyOutNew 150 * description: allocates memory for psyOut struc 151 * returns: an error code 152 * input: pointer to a psych handle 153 * 154 *****************************************************************************/ 155 Word16 PsyOutNew(PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP) 156 { 157 pMemOP->Set(VO_INDEX_ENC_AAC, hPsyOut, 0, sizeof(PSY_OUT)); 158 /* 159 alloc some more stuff, tbd 160 */ 161 return 0; 162 } 163 164 /***************************************************************************** 165 * 166 * function name: PsyOutDelete 167 * description: allocates memory for psychoacoustic 168 * returns: an error code 169 * 170 *****************************************************************************/ 171 Word16 PsyOutDelete(PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP) 172 { 173 hPsyOut=NULL; 174 return 0; 175 } 176 177 178 /***************************************************************************** 179 * 180 * function name: psyMainInit 181 * description: initializes psychoacoustic 182 * returns: an error code 183 * 184 *****************************************************************************/ 185 186 Word16 psyMainInit(PSY_KERNEL *hPsy, 187 Word32 sampleRate, 188 Word32 bitRate, 189 Word16 channels, 190 Word16 tnsMask, 191 Word16 bandwidth) 192 { 193 Word16 ch, err; 194 Word32 channelBitRate = bitRate/channels; 195 196 err = InitPsyConfigurationLong(channelBitRate, 197 sampleRate, 198 bandwidth, 199 &(hPsy->psyConfLong)); 200 201 if (!err) { 202 hPsy->sampleRateIdx = hPsy->psyConfLong.sampRateIdx; 203 err = InitTnsConfigurationLong(bitRate, sampleRate, channels, 204 &hPsy->psyConfLong.tnsConf, &hPsy->psyConfLong, tnsMask&2); 205 } 206 207 if (!err) 208 err = InitPsyConfigurationShort(channelBitRate, 209 sampleRate, 210 bandwidth, 211 &hPsy->psyConfShort); 212 if (!err) { 213 err = InitTnsConfigurationShort(bitRate, sampleRate, channels, 214 &hPsy->psyConfShort.tnsConf, &hPsy->psyConfShort, tnsMask&1); 215 } 216 217 if (!err) 218 for(ch=0;ch < channels;ch++){ 219 220 InitBlockSwitching(&hPsy->psyData[ch].blockSwitchingControl, 221 bitRate, channels); 222 223 InitPreEchoControl(hPsy->psyData[ch].sfbThresholdnm1, 224 hPsy->psyConfLong.sfbCnt, 225 hPsy->psyConfLong.sfbThresholdQuiet); 226 hPsy->psyData[ch].mdctScalenm1 = 0; 227 } 228 229 return(err); 230 } 231 232 /***************************************************************************** 233 * 234 * function name: psyMain 235 * description: psychoacoustic main function 236 * returns: an error code 237 * 238 * This function assumes that enough input data is in the modulo buffer. 239 * 240 *****************************************************************************/ 241 242 Word16 psyMain(Word16 nChannels, 243 ELEMENT_INFO *elemInfo, 244 Word16 *timeSignal, 245 PSY_DATA psyData[MAX_CHANNELS], 246 TNS_DATA tnsData[MAX_CHANNELS], 247 PSY_CONFIGURATION_LONG *hPsyConfLong, 248 PSY_CONFIGURATION_SHORT *hPsyConfShort, 249 PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], 250 PSY_OUT_ELEMENT *psyOutElement, 251 Word32 *pScratchTns, 252 Word32 sampleRate) 253 { 254 Word16 maxSfbPerGroup[MAX_CHANNELS]; 255 Word16 mdctScalingArray[MAX_CHANNELS]; 256 257 Word16 ch; /* counts through channels */ 258 Word16 sfb; /* counts through scalefactor bands */ 259 Word16 line; /* counts through lines */ 260 Word16 channels; 261 Word16 maxScale; 262 263 channels = elemInfo->nChannelsInEl; 264 maxScale = 0; 265 266 /* block switching */ 267 for(ch = 0; ch < channels; ch++) { 268 BlockSwitching(&psyData[ch].blockSwitchingControl, 269 timeSignal+elemInfo->ChannelIndex[ch], 270 sampleRate, 271 nChannels); 272 } 273 274 /* synch left and right block type */ 275 SyncBlockSwitching(&psyData[0].blockSwitchingControl, 276 &psyData[1].blockSwitchingControl, 277 channels); 278 279 /* transform 280 and get maxScale (max mdctScaling) for all channels */ 281 for(ch=0; ch<channels; ch++) { 282 Transform_Real(psyData[ch].mdctDelayBuffer, 283 timeSignal+elemInfo->ChannelIndex[ch], 284 nChannels, 285 psyData[ch].mdctSpectrum, 286 &(mdctScalingArray[ch]), 287 psyData[ch].blockSwitchingControl.windowSequence); 288 maxScale = max(maxScale, mdctScalingArray[ch]); 289 } 290 291 /* common scaling for all channels */ 292 for (ch=0; ch<channels; ch++) { 293 Word16 scaleDiff = maxScale - mdctScalingArray[ch]; 294 295 if (scaleDiff > 0) { 296 Word32 *Spectrum = psyData[ch].mdctSpectrum; 297 for(line=0; line<FRAME_LEN_LONG; line++) { 298 *Spectrum = (*Spectrum) >> scaleDiff; 299 Spectrum++; 300 } 301 } 302 psyData[ch].mdctScale = maxScale; 303 } 304 305 for (ch=0; ch<channels; ch++) { 306 307 if(psyData[ch].blockSwitchingControl.windowSequence != SHORT_WINDOW) { 308 /* update long block parameter */ 309 advancePsychLong(&psyData[ch], 310 &tnsData[ch], 311 hPsyConfLong, 312 &psyOutChannel[ch], 313 pScratchTns, 314 &tnsData[1 - ch], 315 ch); 316 317 /* determine maxSfb */ 318 for (sfb=hPsyConfLong->sfbCnt-1; sfb>=0; sfb--) { 319 for (line=hPsyConfLong->sfbOffset[sfb+1] - 1; line>=hPsyConfLong->sfbOffset[sfb]; line--) { 320 321 if (psyData[ch].mdctSpectrum[line] != 0) break; 322 } 323 if (line >= hPsyConfLong->sfbOffset[sfb]) break; 324 } 325 maxSfbPerGroup[ch] = sfb + 1; 326 327 /* Calc bandwise energies for mid and side channel 328 Do it only if 2 channels exist */ 329 330 if (ch == 1) 331 advancePsychLongMS(psyData, hPsyConfLong); 332 } 333 else { 334 advancePsychShort(&psyData[ch], 335 &tnsData[ch], 336 hPsyConfShort, 337 &psyOutChannel[ch], 338 pScratchTns, 339 &tnsData[1 - ch], 340 ch); 341 342 /* Calc bandwise energies for mid and side channel 343 Do it only if 2 channels exist */ 344 345 if (ch == 1) 346 advancePsychShortMS (psyData, hPsyConfShort); 347 } 348 } 349 350 /* group short data */ 351 for(ch=0; ch<channels; ch++) { 352 353 if (psyData[ch].blockSwitchingControl.windowSequence == SHORT_WINDOW) { 354 groupShortData(psyData[ch].mdctSpectrum, 355 pScratchTns, 356 &psyData[ch].sfbThreshold, 357 &psyData[ch].sfbEnergy, 358 &psyData[ch].sfbEnergyMS, 359 &psyData[ch].sfbSpreadedEnergy, 360 hPsyConfShort->sfbCnt, 361 hPsyConfShort->sfbOffset, 362 hPsyConfShort->sfbMinSnr, 363 psyOutElement->groupedSfbOffset[ch], 364 &maxSfbPerGroup[ch], 365 psyOutElement->groupedSfbMinSnr[ch], 366 psyData[ch].blockSwitchingControl.noOfGroups, 367 psyData[ch].blockSwitchingControl.groupLen); 368 } 369 } 370 371 372 #if (MAX_CHANNELS>1) 373 /* 374 stereo Processing 375 */ 376 if (channels == 2) { 377 psyOutElement->toolsInfo.msDigest = MS_NONE; 378 maxSfbPerGroup[0] = maxSfbPerGroup[1] = max(maxSfbPerGroup[0], maxSfbPerGroup[1]); 379 380 381 if (psyData[0].blockSwitchingControl.windowSequence != SHORT_WINDOW) 382 MsStereoProcessing(psyData[0].sfbEnergy.sfbLong, 383 psyData[1].sfbEnergy.sfbLong, 384 psyData[0].sfbEnergyMS.sfbLong, 385 psyData[1].sfbEnergyMS.sfbLong, 386 psyData[0].mdctSpectrum, 387 psyData[1].mdctSpectrum, 388 psyData[0].sfbThreshold.sfbLong, 389 psyData[1].sfbThreshold.sfbLong, 390 psyData[0].sfbSpreadedEnergy.sfbLong, 391 psyData[1].sfbSpreadedEnergy.sfbLong, 392 (Word16*)&psyOutElement->toolsInfo.msDigest, 393 (Word16*)psyOutElement->toolsInfo.msMask, 394 hPsyConfLong->sfbCnt, 395 hPsyConfLong->sfbCnt, 396 maxSfbPerGroup[0], 397 (const Word16*)hPsyConfLong->sfbOffset); 398 else 399 MsStereoProcessing(psyData[0].sfbEnergy.sfbLong, 400 psyData[1].sfbEnergy.sfbLong, 401 psyData[0].sfbEnergyMS.sfbLong, 402 psyData[1].sfbEnergyMS.sfbLong, 403 psyData[0].mdctSpectrum, 404 psyData[1].mdctSpectrum, 405 psyData[0].sfbThreshold.sfbLong, 406 psyData[1].sfbThreshold.sfbLong, 407 psyData[0].sfbSpreadedEnergy.sfbLong, 408 psyData[1].sfbSpreadedEnergy.sfbLong, 409 (Word16*)&psyOutElement->toolsInfo.msDigest, 410 (Word16*)psyOutElement->toolsInfo.msMask, 411 psyData[0].blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt, 412 hPsyConfShort->sfbCnt, 413 maxSfbPerGroup[0], 414 (const Word16*)psyOutElement->groupedSfbOffset[0]); 415 } 416 417 #endif /* (MAX_CHANNELS>1) */ 418 419 /* 420 build output 421 */ 422 for(ch=0;ch<channels;ch++) { 423 424 if (psyData[ch].blockSwitchingControl.windowSequence != SHORT_WINDOW) 425 BuildInterface(psyData[ch].mdctSpectrum, 426 psyData[ch].mdctScale, 427 &psyData[ch].sfbThreshold, 428 &psyData[ch].sfbEnergy, 429 &psyData[ch].sfbSpreadedEnergy, 430 psyData[ch].sfbEnergySum, 431 psyData[ch].sfbEnergySumMS, 432 psyData[ch].blockSwitchingControl.windowSequence, 433 blockType2windowShape[psyData[ch].blockSwitchingControl.windowSequence], 434 hPsyConfLong->sfbCnt, 435 hPsyConfLong->sfbOffset, 436 maxSfbPerGroup[ch], 437 hPsyConfLong->sfbMinSnr, 438 psyData[ch].blockSwitchingControl.noOfGroups, 439 psyData[ch].blockSwitchingControl.groupLen, 440 &psyOutChannel[ch]); 441 else 442 BuildInterface(psyData[ch].mdctSpectrum, 443 psyData[ch].mdctScale, 444 &psyData[ch].sfbThreshold, 445 &psyData[ch].sfbEnergy, 446 &psyData[ch].sfbSpreadedEnergy, 447 psyData[ch].sfbEnergySum, 448 psyData[ch].sfbEnergySumMS, 449 SHORT_WINDOW, 450 SINE_WINDOW, 451 psyData[0].blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt, 452 psyOutElement->groupedSfbOffset[ch], 453 maxSfbPerGroup[ch], 454 psyOutElement->groupedSfbMinSnr[ch], 455 psyData[ch].blockSwitchingControl.noOfGroups, 456 psyData[ch].blockSwitchingControl.groupLen, 457 &psyOutChannel[ch]); 458 } 459 460 return(0); /* no error */ 461 } 462 463 /***************************************************************************** 464 * 465 * function name: advancePsychLong 466 * description: psychoacoustic for long blocks 467 * 468 *****************************************************************************/ 469 470 static Word16 advancePsychLong(PSY_DATA* psyData, 471 TNS_DATA* tnsData, 472 PSY_CONFIGURATION_LONG *hPsyConfLong, 473 PSY_OUT_CHANNEL* psyOutChannel, 474 Word32 *pScratchTns, 475 const TNS_DATA* tnsData2, 476 const Word16 ch) 477 { 478 Word32 i; 479 Word32 normEnergyShift = (psyData->mdctScale + 1) << 1; /* in reference code, mdct spectrum must be multipied with 2, so +1 */ 480 Word32 clipEnergy = hPsyConfLong->clipEnergy >> normEnergyShift; 481 Word32 *data0, *data1, tdata; 482 483 /* low pass */ 484 data0 = psyData->mdctSpectrum + hPsyConfLong->lowpassLine; 485 for(i=hPsyConfLong->lowpassLine; i<FRAME_LEN_LONG; i++) { 486 *data0++ = 0; 487 } 488 489 /* Calc sfb-bandwise mdct-energies for left and right channel */ 490 CalcBandEnergy( psyData->mdctSpectrum, 491 hPsyConfLong->sfbOffset, 492 hPsyConfLong->sfbActive, 493 psyData->sfbEnergy.sfbLong, 494 &psyData->sfbEnergySum.sfbLong); 495 496 /* 497 TNS detect 498 */ 499 TnsDetect(tnsData, 500 hPsyConfLong->tnsConf, 501 pScratchTns, 502 (const Word16*)hPsyConfLong->sfbOffset, 503 psyData->mdctSpectrum, 504 0, 505 psyData->blockSwitchingControl.windowSequence, 506 psyData->sfbEnergy.sfbLong); 507 508 /* TnsSync */ 509 if (ch == 1) { 510 TnsSync(tnsData, 511 tnsData2, 512 hPsyConfLong->tnsConf, 513 0, 514 psyData->blockSwitchingControl.windowSequence); 515 } 516 517 /* Tns Encoder */ 518 TnsEncode(&psyOutChannel->tnsInfo, 519 tnsData, 520 hPsyConfLong->sfbCnt, 521 hPsyConfLong->tnsConf, 522 hPsyConfLong->lowpassLine, 523 psyData->mdctSpectrum, 524 0, 525 psyData->blockSwitchingControl.windowSequence); 526 527 /* first part of threshold calculation */ 528 data0 = psyData->sfbEnergy.sfbLong; 529 data1 = psyData->sfbThreshold.sfbLong; 530 for (i=hPsyConfLong->sfbCnt; i; i--) { 531 tdata = L_mpy_ls(*data0++, hPsyConfLong->ratio); 532 *data1++ = min(tdata, clipEnergy); 533 } 534 535 /* Calc sfb-bandwise mdct-energies for left and right channel again */ 536 if (tnsData->dataRaw.tnsLong.subBlockInfo.tnsActive!=0) { 537 Word16 tnsStartBand = hPsyConfLong->tnsConf.tnsStartBand; 538 CalcBandEnergy( psyData->mdctSpectrum, 539 hPsyConfLong->sfbOffset+tnsStartBand, 540 hPsyConfLong->sfbActive - tnsStartBand, 541 psyData->sfbEnergy.sfbLong+tnsStartBand, 542 &psyData->sfbEnergySum.sfbLong); 543 544 data0 = psyData->sfbEnergy.sfbLong; 545 tdata = psyData->sfbEnergySum.sfbLong; 546 for (i=0; i<tnsStartBand; i++) 547 tdata += *data0++; 548 549 psyData->sfbEnergySum.sfbLong = tdata; 550 } 551 552 553 /* spreading energy */ 554 SpreadingMax(hPsyConfLong->sfbCnt, 555 hPsyConfLong->sfbMaskLowFactor, 556 hPsyConfLong->sfbMaskHighFactor, 557 psyData->sfbThreshold.sfbLong); 558 559 /* threshold in quiet */ 560 data0 = psyData->sfbThreshold.sfbLong; 561 data1 = hPsyConfLong->sfbThresholdQuiet; 562 for (i=hPsyConfLong->sfbCnt; i; i--) 563 { 564 *data0 = max(*data0, (*data1 >> normEnergyShift)); 565 data0++; data1++; 566 } 567 568 /* preecho control */ 569 if (psyData->blockSwitchingControl.windowSequence == STOP_WINDOW) { 570 data0 = psyData->sfbThresholdnm1; 571 for (i=hPsyConfLong->sfbCnt; i; i--) { 572 *data0++ = MAX_32; 573 } 574 psyData->mdctScalenm1 = 0; 575 } 576 577 PreEchoControl( psyData->sfbThresholdnm1, 578 hPsyConfLong->sfbCnt, 579 hPsyConfLong->maxAllowedIncreaseFactor, 580 hPsyConfLong->minRemainingThresholdFactor, 581 psyData->sfbThreshold.sfbLong, 582 psyData->mdctScale, 583 psyData->mdctScalenm1); 584 psyData->mdctScalenm1 = psyData->mdctScale; 585 586 587 if (psyData->blockSwitchingControl.windowSequence== START_WINDOW) { 588 data0 = psyData->sfbThresholdnm1; 589 for (i=hPsyConfLong->sfbCnt; i; i--) { 590 *data0++ = MAX_32; 591 } 592 psyData->mdctScalenm1 = 0; 593 } 594 595 /* apply tns mult table on cb thresholds */ 596 ApplyTnsMultTableToRatios(hPsyConfLong->tnsConf.tnsRatioPatchLowestCb, 597 hPsyConfLong->tnsConf.tnsStartBand, 598 tnsData->dataRaw.tnsLong.subBlockInfo, 599 psyData->sfbThreshold.sfbLong); 600 601 602 /* spreaded energy */ 603 data0 = psyData->sfbSpreadedEnergy.sfbLong; 604 data1 = psyData->sfbEnergy.sfbLong; 605 for (i=hPsyConfLong->sfbCnt; i; i--) { 606 //psyData->sfbSpreadedEnergy.sfbLong[i] = psyData->sfbEnergy.sfbLong[i]; 607 *data0++ = *data1++; 608 } 609 610 /* spreading energy */ 611 SpreadingMax(hPsyConfLong->sfbCnt, 612 hPsyConfLong->sfbMaskLowFactorSprEn, 613 hPsyConfLong->sfbMaskHighFactorSprEn, 614 psyData->sfbSpreadedEnergy.sfbLong); 615 616 return 0; 617 } 618 619 /***************************************************************************** 620 * 621 * function name: advancePsychLongMS 622 * description: update mdct-energies for left add or minus right channel 623 * for long block 624 * 625 *****************************************************************************/ 626 static Word16 advancePsychLongMS (PSY_DATA psyData[MAX_CHANNELS], 627 const PSY_CONFIGURATION_LONG *hPsyConfLong) 628 { 629 CalcBandEnergyMS(psyData[0].mdctSpectrum, 630 psyData[1].mdctSpectrum, 631 hPsyConfLong->sfbOffset, 632 hPsyConfLong->sfbActive, 633 psyData[0].sfbEnergyMS.sfbLong, 634 &psyData[0].sfbEnergySumMS.sfbLong, 635 psyData[1].sfbEnergyMS.sfbLong, 636 &psyData[1].sfbEnergySumMS.sfbLong); 637 638 return 0; 639 } 640 641 642 /***************************************************************************** 643 * 644 * function name: advancePsychShort 645 * description: psychoacoustic for short blocks 646 * 647 *****************************************************************************/ 648 649 static Word16 advancePsychShort(PSY_DATA* psyData, 650 TNS_DATA* tnsData, 651 const PSY_CONFIGURATION_SHORT *hPsyConfShort, 652 PSY_OUT_CHANNEL* psyOutChannel, 653 Word32 *pScratchTns, 654 const TNS_DATA *tnsData2, 655 const Word16 ch) 656 { 657 Word32 w; 658 Word32 normEnergyShift = (psyData->mdctScale + 1) << 1; /* in reference code, mdct spectrum must be multipied with 2, so +1 */ 659 Word32 clipEnergy = hPsyConfShort->clipEnergy >> normEnergyShift; 660 Word32 wOffset = 0; 661 Word32 *data0; 662 const Word32 *data1; 663 664 for(w = 0; w < TRANS_FAC; w++) { 665 Word32 i, tdata; 666 667 /* low pass */ 668 data0 = psyData->mdctSpectrum + wOffset + hPsyConfShort->lowpassLine; 669 for(i=hPsyConfShort->lowpassLine; i<FRAME_LEN_SHORT; i++){ 670 *data0++ = 0; 671 } 672 673 /* Calc sfb-bandwise mdct-energies for left and right channel */ 674 CalcBandEnergy( psyData->mdctSpectrum+wOffset, 675 hPsyConfShort->sfbOffset, 676 hPsyConfShort->sfbActive, 677 psyData->sfbEnergy.sfbShort[w], 678 &psyData->sfbEnergySum.sfbShort[w]); 679 /* 680 TNS 681 */ 682 TnsDetect(tnsData, 683 hPsyConfShort->tnsConf, 684 pScratchTns, 685 (const Word16*)hPsyConfShort->sfbOffset, 686 psyData->mdctSpectrum+wOffset, 687 w, 688 psyData->blockSwitchingControl.windowSequence, 689 psyData->sfbEnergy.sfbShort[w]); 690 691 /* TnsSync */ 692 if (ch == 1) { 693 TnsSync(tnsData, 694 tnsData2, 695 hPsyConfShort->tnsConf, 696 w, 697 psyData->blockSwitchingControl.windowSequence); 698 } 699 700 TnsEncode(&psyOutChannel->tnsInfo, 701 tnsData, 702 hPsyConfShort->sfbCnt, 703 hPsyConfShort->tnsConf, 704 hPsyConfShort->lowpassLine, 705 psyData->mdctSpectrum+wOffset, 706 w, 707 psyData->blockSwitchingControl.windowSequence); 708 709 /* first part of threshold calculation */ 710 data0 = psyData->sfbThreshold.sfbShort[w]; 711 data1 = psyData->sfbEnergy.sfbShort[w]; 712 for (i=hPsyConfShort->sfbCnt; i; i--) { 713 tdata = L_mpy_ls(*data1++, hPsyConfShort->ratio); 714 *data0++ = min(tdata, clipEnergy); 715 } 716 717 /* Calc sfb-bandwise mdct-energies for left and right channel again */ 718 if (tnsData->dataRaw.tnsShort.subBlockInfo[w].tnsActive != 0) { 719 Word16 tnsStartBand = hPsyConfShort->tnsConf.tnsStartBand; 720 CalcBandEnergy( psyData->mdctSpectrum+wOffset, 721 hPsyConfShort->sfbOffset+tnsStartBand, 722 (hPsyConfShort->sfbActive - tnsStartBand), 723 psyData->sfbEnergy.sfbShort[w]+tnsStartBand, 724 &psyData->sfbEnergySum.sfbShort[w]); 725 726 tdata = psyData->sfbEnergySum.sfbShort[w]; 727 data0 = psyData->sfbEnergy.sfbShort[w]; 728 for (i=tnsStartBand; i; i--) 729 tdata += *data0++; 730 731 psyData->sfbEnergySum.sfbShort[w] = tdata; 732 } 733 734 /* spreading */ 735 SpreadingMax(hPsyConfShort->sfbCnt, 736 hPsyConfShort->sfbMaskLowFactor, 737 hPsyConfShort->sfbMaskHighFactor, 738 psyData->sfbThreshold.sfbShort[w]); 739 740 741 /* threshold in quiet */ 742 data0 = psyData->sfbThreshold.sfbShort[w]; 743 data1 = hPsyConfShort->sfbThresholdQuiet; 744 for (i=hPsyConfShort->sfbCnt; i; i--) 745 { 746 *data0 = max(*data0, (*data1 >> normEnergyShift)); 747 748 data0++; data1++; 749 } 750 751 752 /* preecho */ 753 PreEchoControl( psyData->sfbThresholdnm1, 754 hPsyConfShort->sfbCnt, 755 hPsyConfShort->maxAllowedIncreaseFactor, 756 hPsyConfShort->minRemainingThresholdFactor, 757 psyData->sfbThreshold.sfbShort[w], 758 psyData->mdctScale, 759 w==0 ? psyData->mdctScalenm1 : psyData->mdctScale); 760 761 /* apply tns mult table on cb thresholds */ 762 ApplyTnsMultTableToRatios( hPsyConfShort->tnsConf.tnsRatioPatchLowestCb, 763 hPsyConfShort->tnsConf.tnsStartBand, 764 tnsData->dataRaw.tnsShort.subBlockInfo[w], 765 psyData->sfbThreshold.sfbShort[w]); 766 767 /* spreaded energy */ 768 data0 = psyData->sfbSpreadedEnergy.sfbShort[w]; 769 data1 = psyData->sfbEnergy.sfbShort[w]; 770 for (i=hPsyConfShort->sfbCnt; i; i--) { 771 *data0++ = *data1++; 772 } 773 SpreadingMax(hPsyConfShort->sfbCnt, 774 hPsyConfShort->sfbMaskLowFactorSprEn, 775 hPsyConfShort->sfbMaskHighFactorSprEn, 776 psyData->sfbSpreadedEnergy.sfbShort[w]); 777 778 wOffset += FRAME_LEN_SHORT; 779 } /* for TRANS_FAC */ 780 781 psyData->mdctScalenm1 = psyData->mdctScale; 782 783 return 0; 784 } 785 786 /***************************************************************************** 787 * 788 * function name: advancePsychShortMS 789 * description: update mdct-energies for left add or minus right channel 790 * for short block 791 * 792 *****************************************************************************/ 793 static Word16 advancePsychShortMS (PSY_DATA psyData[MAX_CHANNELS], 794 const PSY_CONFIGURATION_SHORT *hPsyConfShort) 795 { 796 Word32 w, wOffset; 797 wOffset = 0; 798 for(w=0; w<TRANS_FAC; w++) { 799 CalcBandEnergyMS(psyData[0].mdctSpectrum+wOffset, 800 psyData[1].mdctSpectrum+wOffset, 801 hPsyConfShort->sfbOffset, 802 hPsyConfShort->sfbActive, 803 psyData[0].sfbEnergyMS.sfbShort[w], 804 &psyData[0].sfbEnergySumMS.sfbShort[w], 805 psyData[1].sfbEnergyMS.sfbShort[w], 806 &psyData[1].sfbEnergySumMS.sfbShort[w]); 807 wOffset += FRAME_LEN_SHORT; 808 } 809 810 return 0; 811 } 812