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 *****************************************************************************/
PsyNew(PSY_KERNEL * hPsy,Word32 nChan,VO_MEM_OPERATOR * pMemOP)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 *****************************************************************************/
PsyDelete(PSY_KERNEL * hPsy,VO_MEM_OPERATOR * pMemOP)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 *****************************************************************************/
PsyOutNew(PSY_OUT * hPsyOut,VO_MEM_OPERATOR * pMemOP)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 *****************************************************************************/
PsyOutDelete(PSY_OUT * hPsyOut,VO_MEM_OPERATOR * pMemOP)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 
psyMainInit(PSY_KERNEL * hPsy,Word32 sampleRate,Word32 bitRate,Word16 channels,Word16 tnsMask,Word16 bandwidth)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 
psyMain(Word16 nChannels,ELEMENT_INFO * elemInfo,Word16 * timeSignal,PSY_DATA psyData[MAX_CHANNELS],TNS_DATA tnsData[MAX_CHANNELS],PSY_CONFIGURATION_LONG * hPsyConfLong,PSY_CONFIGURATION_SHORT * hPsyConfShort,PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PSY_OUT_ELEMENT * psyOutElement,Word32 * pScratchTns,Word32 sampleRate)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 
advancePsychLong(PSY_DATA * psyData,TNS_DATA * tnsData,PSY_CONFIGURATION_LONG * hPsyConfLong,PSY_OUT_CHANNEL * psyOutChannel,Word32 * pScratchTns,const TNS_DATA * tnsData2,const Word16 ch)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 *****************************************************************************/
advancePsychLongMS(PSY_DATA psyData[MAX_CHANNELS],const PSY_CONFIGURATION_LONG * hPsyConfLong)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 
advancePsychShort(PSY_DATA * psyData,TNS_DATA * tnsData,const PSY_CONFIGURATION_SHORT * hPsyConfShort,PSY_OUT_CHANNEL * psyOutChannel,Word32 * pScratchTns,const TNS_DATA * tnsData2,const Word16 ch)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 *****************************************************************************/
advancePsychShortMS(PSY_DATA psyData[MAX_CHANNELS],const PSY_CONFIGURATION_SHORT * hPsyConfShort)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