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 /*                                    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