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