psy_main.c revision e2e838afcf03e603a41a0455846eaf9614537c16
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 */
42static Word16 blockType2windowShape[] = {KBD_WINDOW,SINE_WINDOW,SINE_WINDOW,KBD_WINDOW};
43
44/*
45  forward definitions
46*/
47static 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
55static Word16 advancePsychLongMS (PSY_DATA  psyData[MAX_CHANNELS],
56                                  const PSY_CONFIGURATION_LONG *hPsyConfLong);
57
58static 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
66static 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*****************************************************************************/
78Word16 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*****************************************************************************/
119Word16 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*****************************************************************************/
155Word16 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*****************************************************************************/
171Word16 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
186Word16 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
242Word16 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
470static 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*****************************************************************************/
626static 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
649static 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, *data1;
662
663  for(w = 0; w < TRANS_FAC; w++) {
664    Word32 i, tdata;
665
666    /* low pass */
667    data0 = psyData->mdctSpectrum + wOffset + hPsyConfShort->lowpassLine;
668	for(i=hPsyConfShort->lowpassLine; i<FRAME_LEN_SHORT; i++){
669      *data0++ = 0;
670    }
671
672    /* Calc sfb-bandwise mdct-energies for left and right channel */
673    CalcBandEnergy( psyData->mdctSpectrum+wOffset,
674                    hPsyConfShort->sfbOffset,
675                    hPsyConfShort->sfbActive,
676                    psyData->sfbEnergy.sfbShort[w],
677                    &psyData->sfbEnergySum.sfbShort[w]);
678    /*
679       TNS
680    */
681    TnsDetect(tnsData,
682              hPsyConfShort->tnsConf,
683              pScratchTns,
684              (const Word16*)hPsyConfShort->sfbOffset,
685              psyData->mdctSpectrum+wOffset,
686              w,
687              psyData->blockSwitchingControl.windowSequence,
688              psyData->sfbEnergy.sfbShort[w]);
689
690    /*  TnsSync */
691    if (ch == 1) {
692      TnsSync(tnsData,
693              tnsData2,
694              hPsyConfShort->tnsConf,
695              w,
696              psyData->blockSwitchingControl.windowSequence);
697    }
698
699    TnsEncode(&psyOutChannel->tnsInfo,
700              tnsData,
701              hPsyConfShort->sfbCnt,
702              hPsyConfShort->tnsConf,
703              hPsyConfShort->lowpassLine,
704              psyData->mdctSpectrum+wOffset,
705              w,
706              psyData->blockSwitchingControl.windowSequence);
707
708    /* first part of threshold calculation */
709    data0 = psyData->sfbThreshold.sfbShort[w];
710	data1 = psyData->sfbEnergy.sfbShort[w];
711	for (i=hPsyConfShort->sfbCnt; i; i--) {
712      tdata = L_mpy_ls(*data1++, hPsyConfShort->ratio);
713      *data0++ = min(tdata, clipEnergy);
714    }
715
716    /* Calc sfb-bandwise mdct-energies for left and right channel again */
717    if (tnsData->dataRaw.tnsShort.subBlockInfo[w].tnsActive != 0) {
718      Word16 tnsStartBand = hPsyConfShort->tnsConf.tnsStartBand;
719      CalcBandEnergy( psyData->mdctSpectrum+wOffset,
720                      hPsyConfShort->sfbOffset+tnsStartBand,
721                      (hPsyConfShort->sfbActive - tnsStartBand),
722                      psyData->sfbEnergy.sfbShort[w]+tnsStartBand,
723                      &psyData->sfbEnergySum.sfbShort[w]);
724
725      tdata = psyData->sfbEnergySum.sfbShort[w];
726	  data0 = psyData->sfbEnergy.sfbShort[w];
727	  for (i=tnsStartBand; i; i--)
728        tdata += *data0++;
729
730	  psyData->sfbEnergySum.sfbShort[w] = tdata;
731    }
732
733    /* spreading */
734    SpreadingMax(hPsyConfShort->sfbCnt,
735                 hPsyConfShort->sfbMaskLowFactor,
736                 hPsyConfShort->sfbMaskHighFactor,
737                 psyData->sfbThreshold.sfbShort[w]);
738
739
740    /* threshold in quiet */
741    data0 = psyData->sfbThreshold.sfbShort[w];
742	data1 = hPsyConfShort->sfbThresholdQuiet;
743	for (i=hPsyConfShort->sfbCnt; i; i--)
744    {
745		*data0 = max(*data0, (*data1 >> normEnergyShift));
746
747		data0++; data1++;
748	}
749
750
751    /* preecho */
752    PreEchoControl( psyData->sfbThresholdnm1,
753                    hPsyConfShort->sfbCnt,
754                    hPsyConfShort->maxAllowedIncreaseFactor,
755                    hPsyConfShort->minRemainingThresholdFactor,
756                    psyData->sfbThreshold.sfbShort[w],
757                    psyData->mdctScale,
758                    w==0 ? psyData->mdctScalenm1 : psyData->mdctScale);
759
760    /* apply tns mult table on cb thresholds */
761    ApplyTnsMultTableToRatios( hPsyConfShort->tnsConf.tnsRatioPatchLowestCb,
762                               hPsyConfShort->tnsConf.tnsStartBand,
763                               tnsData->dataRaw.tnsShort.subBlockInfo[w],
764                               psyData->sfbThreshold.sfbShort[w]);
765
766    /* spreaded energy */
767    data0 = psyData->sfbSpreadedEnergy.sfbShort[w];
768	data1 = psyData->sfbEnergy.sfbShort[w];
769	for (i=hPsyConfShort->sfbCnt; i; i--) {
770	  *data0++ = *data1++;
771    }
772    SpreadingMax(hPsyConfShort->sfbCnt,
773                 hPsyConfShort->sfbMaskLowFactorSprEn,
774                 hPsyConfShort->sfbMaskHighFactorSprEn,
775                 psyData->sfbSpreadedEnergy.sfbShort[w]);
776
777    wOffset += FRAME_LEN_SHORT;
778  } /* for TRANS_FAC */
779
780  psyData->mdctScalenm1 = psyData->mdctScale;
781
782  return 0;
783}
784
785/*****************************************************************************
786*
787* function name: advancePsychShortMS
788* description:   update mdct-energies for left add or minus right channel
789*				for short block
790*
791*****************************************************************************/
792static Word16 advancePsychShortMS (PSY_DATA psyData[MAX_CHANNELS],
793                                   const PSY_CONFIGURATION_SHORT *hPsyConfShort)
794{
795  Word32 w, wOffset;
796  wOffset = 0;
797  for(w=0; w<TRANS_FAC; w++) {
798    CalcBandEnergyMS(psyData[0].mdctSpectrum+wOffset,
799                     psyData[1].mdctSpectrum+wOffset,
800                     hPsyConfShort->sfbOffset,
801                     hPsyConfShort->sfbActive,
802                     psyData[0].sfbEnergyMS.sfbShort[w],
803                     &psyData[0].sfbEnergySumMS.sfbShort[w],
804                     psyData[1].sfbEnergyMS.sfbShort[w],
805                     &psyData[1].sfbEnergySumMS.sfbShort[w]);
806    wOffset += FRAME_LEN_SHORT;
807  }
808
809  return 0;
810}
811