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