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