1
2/* -----------------------------------------------------------------------------------------------------------
3Software License for The Fraunhofer FDK AAC Codec Library for Android
4
5� Copyright  1995 - 2013 Fraunhofer-Gesellschaft zur F�rderung der angewandten Forschung e.V.
6  All rights reserved.
7
8 1.    INTRODUCTION
9The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16of the MPEG specifications.
17
18Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20individually for the purpose of encoding or decoding bit streams in products that are compliant with
21the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23software may already be covered under those patent licenses when it is used for those licensed purposes only.
24
25Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27applications information and documentation.
28
292.    COPYRIGHT LICENSE
30
31Redistribution and use in source and binary forms, with or without modification, are permitted without
32payment of copyright license fees provided that you satisfy the following conditions:
33
34You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35your modifications thereto in source code form.
36
37You must retain the complete text of this software license in the documentation and/or other materials
38provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40modifications thereto to recipients of copies in binary form.
41
42The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43prior written permission.
44
45You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46software or your modifications thereto.
47
48Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49and the date of any change. For modified versions of the FDK AAC Codec, the term
50"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
51"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
52
533.    NO PATENT LICENSE
54
55NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57respect to this software.
58
59You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60by appropriate patent licenses.
61
624.    DISCLAIMER
63
64This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
65"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
66of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69or business interruption, however caused and on any theory of liability, whether in contract, strict
70liability, or tort (including negligence), arising in any way out of the use of this software, even if
71advised of the possibility of such damage.
72
735.    CONTACT INFORMATION
74
75Fraunhofer Institute for Integrated Circuits IIS
76Attention: Audio and Multimedia Departments - FDK AAC LL
77Am Wolfsmantel 33
7891058 Erlangen, Germany
79
80www.iis.fraunhofer.de/amm
81amm-info@iis.fraunhofer.de
82----------------------------------------------------------------------------------------------------------- */
83
84/*****************************  MPEG Audio Encoder  ***************************
85
86   Initial Authors:      M. Multrus
87   Contents/Description: PS Wrapper, Downmix
88
89******************************************************************************/
90
91#include "ps_main.h"
92
93
94/* Includes ******************************************************************/
95
96#include "ps_const.h"
97#include "ps_bitenc.h"
98
99#include "sbr_ram.h"
100
101/*--------------- function declarations --------------------*/
102static void psFindBestScaling(
103        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
104        FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
105        UCHAR                    *dynBandScale,
106        FIXP_QMF                 *maxBandValue,
107        SCHAR                    *dmxScale
108        );
109
110/*------------- function definitions ----------------*/
111FDK_PSENC_ERROR PSEnc_Create(
112        HANDLE_PARAMETRIC_STEREO *phParametricStereo
113        )
114{
115  FDK_PSENC_ERROR error = PSENC_OK;
116
117  if (phParametricStereo==NULL) {
118    error = PSENC_INVALID_HANDLE;
119  }
120  else {
121    int i;
122    HANDLE_PARAMETRIC_STEREO hParametricStereo = NULL;
123
124    if (NULL==(hParametricStereo = GetRam_ParamStereo())) {
125      error = PSENC_MEMORY_ERROR;
126      goto bail;
127    }
128    FDKmemclear(hParametricStereo, sizeof(PARAMETRIC_STEREO));
129
130    if (PSENC_OK != (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) {
131      goto bail;
132    }
133
134    for (i=0; i<MAX_PS_CHANNELS; i++) {
135      if (FDKhybridAnalysisOpen(
136            &hParametricStereo->fdkHybAnaFilter[i],
137             hParametricStereo->__staticHybAnaStatesLF[i],
138             sizeof(hParametricStereo->__staticHybAnaStatesLF[i]),
139             hParametricStereo->__staticHybAnaStatesHF[i],
140             sizeof(hParametricStereo->__staticHybAnaStatesHF[i])
141             ) !=0 )
142      {
143        error = PSENC_MEMORY_ERROR;
144        goto bail;
145      }
146    }
147
148    *phParametricStereo = hParametricStereo; /* return allocated handle */
149  }
150bail:
151  return error;
152}
153
154FDK_PSENC_ERROR PSEnc_Init(
155        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
156        const HANDLE_PSENC_CONFIG hPsEncConfig,
157        INT                       noQmfSlots,
158        INT                       noQmfBands
159       ,UCHAR                    *dynamic_RAM
160        )
161{
162  FDK_PSENC_ERROR error = PSENC_OK;
163
164  if ( (NULL==hParametricStereo) || (NULL==hPsEncConfig) ) {
165    error = PSENC_INVALID_HANDLE;
166  }
167  else {
168    int ch, i;
169
170    hParametricStereo->initPS = 1;
171    hParametricStereo->noQmfSlots = noQmfSlots;
172    hParametricStereo->noQmfBands = noQmfBands;
173
174    /* clear delay lines */
175    FDKmemclear(hParametricStereo->qmfDelayLines, sizeof(hParametricStereo->qmfDelayLines));
176
177    hParametricStereo->qmfDelayScale = FRACT_BITS-1;
178
179    /* create configuration for hybrid filter bank */
180    for (ch=0; ch<MAX_PS_CHANNELS; ch++) {
181      FDKhybridAnalysisInit(
182            &hParametricStereo->fdkHybAnaFilter[ch],
183             THREE_TO_TEN,
184             QMF_CHANNELS,
185             QMF_CHANNELS,
186             1
187             );
188    } /* ch */
189
190    FDKhybridSynthesisInit(
191          &hParametricStereo->fdkHybSynFilter,
192           THREE_TO_TEN,
193           QMF_CHANNELS,
194           QMF_CHANNELS
195           );
196
197    /* determine average delay */
198    hParametricStereo->psDelay = (HYBRID_FILTER_DELAY*hParametricStereo->noQmfBands);
199
200    if ( (hPsEncConfig->maxEnvelopes < PSENC_NENV_1) || (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX) ) {
201      hPsEncConfig->maxEnvelopes = PSENC_NENV_DEFAULT;
202    }
203    hParametricStereo->maxEnvelopes = hPsEncConfig->maxEnvelopes;
204
205    if (PSENC_OK != (error = FDKsbrEnc_InitPSEncode(hParametricStereo->hPsEncode, (PS_BANDS) hPsEncConfig->nStereoBands, hPsEncConfig->iidQuantErrorThreshold))){
206      goto bail;
207    }
208
209    for (ch = 0; ch<MAX_PS_CHANNELS; ch ++) {
210      FIXP_DBL *pDynReal = GetRam_Sbr_envRBuffer (ch, dynamic_RAM);
211      FIXP_DBL *pDynImag = GetRam_Sbr_envIBuffer (ch, dynamic_RAM);
212
213      for (i=0; i<HYBRID_FRAMESIZE; i++) {
214        hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][ch][0] = &pDynReal[i*MAX_HYBRID_BANDS];
215        hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][ch][1] = &pDynImag[i*MAX_HYBRID_BANDS];;
216      }
217
218      for (i=0; i<HYBRID_READ_OFFSET; i++) {
219        hParametricStereo->pHybridData[i][ch][0] = hParametricStereo->__staticHybridData[i][ch][0];
220        hParametricStereo->pHybridData[i][ch][1] = hParametricStereo->__staticHybridData[i][ch][1];
221      }
222    } /* ch */
223
224    /* clear static hybrid buffer */
225    FDKmemclear(hParametricStereo->__staticHybridData, sizeof(hParametricStereo->__staticHybridData));
226
227    /* clear bs buffer */
228    FDKmemclear(hParametricStereo->psOut, sizeof(hParametricStereo->psOut));
229
230    hParametricStereo->psOut[0].enablePSHeader = 1; /* write ps header in first frame */
231
232    /* clear scaling buffer */
233    FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR)*PS_MAX_BANDS);
234    FDKmemclear(hParametricStereo->maxBandValue, sizeof(FIXP_QMF)*PS_MAX_BANDS);
235
236  } /* valid handle */
237bail:
238  return error;
239}
240
241
242FDK_PSENC_ERROR PSEnc_Destroy(
243        HANDLE_PARAMETRIC_STEREO *phParametricStereo
244        )
245{
246  FDK_PSENC_ERROR error = PSENC_OK;
247
248  if (NULL!=phParametricStereo) {
249    HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo;
250    if(hParametricStereo != NULL){
251      FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode);
252      FreeRam_ParamStereo(phParametricStereo);
253    }
254  }
255
256  return error;
257}
258
259static FDK_PSENC_ERROR ExtractPSParameters(
260        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
261        const int                 sendHeader,
262        FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2]
263        )
264{
265  FDK_PSENC_ERROR error = PSENC_OK;
266
267  if (hParametricStereo == NULL) {
268    error = PSENC_INVALID_HANDLE;
269  }
270  else {
271    /* call ps encode function */
272    if (hParametricStereo->initPS){
273      hParametricStereo->psOut[1] = hParametricStereo->psOut[0];
274    }
275    hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
276
277    if (PSENC_OK != (error = FDKsbrEnc_PSEncode(
278            hParametricStereo->hPsEncode,
279           &hParametricStereo->psOut[1],
280            hParametricStereo->dynBandScale,
281            hParametricStereo->maxEnvelopes,
282            hybridData,
283            hParametricStereo->noQmfSlots,
284            sendHeader)))
285    {
286      goto bail;
287    }
288
289    if (hParametricStereo->initPS) {
290      hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
291      hParametricStereo->initPS = 0;
292    }
293  }
294bail:
295  return error;
296}
297
298
299static FDK_PSENC_ERROR DownmixPSQmfData(
300       HANDLE_PARAMETRIC_STEREO  hParametricStereo,
301       HANDLE_QMF_FILTER_BANK    sbrSynthQmf,
302       FIXP_QMF       **RESTRICT mixRealQmfData,
303       FIXP_QMF       **RESTRICT mixImagQmfData,
304       INT_PCM                  *downsampledOutSignal,
305       FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
306       const INT                 noQmfSlots,
307       const INT                 psQmfScale[MAX_PS_CHANNELS],
308       SCHAR                    *qmfScale
309       )
310{
311  FDK_PSENC_ERROR error = PSENC_OK;
312
313  if(hParametricStereo == NULL){
314    error = PSENC_INVALID_HANDLE;
315  }
316  else {
317    int n, k;
318    C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_QMF, 2*QMF_CHANNELS)
319
320    /* define scalings */
321    int dynQmfScale = fixMax(0, hParametricStereo->dmxScale-1); /* scale one bit more for addition of left and right */
322    int downmixScale = psQmfScale[0] - dynQmfScale;
323    const FIXP_DBL maxStereoScaleFactor = MAXVAL_DBL; /* 2.f/2.f */
324
325    for (n = 0; n<noQmfSlots; n++) {
326
327      FIXP_DBL tmpHybrid[2][MAX_HYBRID_BANDS];
328
329      for(k = 0; k<71; k++){
330          int dynScale, sc; /* scaling */
331          FIXP_QMF tmpLeftReal, tmpRightReal, tmpLeftImag, tmpRightImag;
332          FIXP_DBL tmpScaleFactor, stereoScaleFactor;
333
334          tmpLeftReal  = hybridData[n][0][0][k];
335          tmpLeftImag  = hybridData[n][0][1][k];
336          tmpRightReal = hybridData[n][1][0][k];
337          tmpRightImag = hybridData[n][1][1][k];
338
339          sc = fixMax(0,CntLeadingZeros( fixMax(fixMax(fixp_abs(tmpLeftReal),fixp_abs(tmpLeftImag)),fixMax(fixp_abs(tmpRightReal),fixp_abs(tmpRightImag))) )-2);
340
341          tmpLeftReal  <<= sc; tmpLeftImag  <<= sc;
342          tmpRightReal <<= sc; tmpRightImag <<= sc;
343          dynScale = fixMin(sc-dynQmfScale,DFRACT_BITS-1);
344
345          /* calc stereo scale factor to avoid loss of energy in bands                                                 */
346          /* stereo scale factor = min(2.0f, sqrt( (abs(l(k, n)^2 + abs(r(k, n)^2 )))/(0.5f*abs(l(k, n) + r(k, n))) )) */
347          stereoScaleFactor = fPow2Div2(tmpLeftReal)  + fPow2Div2(tmpLeftImag)
348                            + fPow2Div2(tmpRightReal) + fPow2Div2(tmpRightImag) ;
349
350          /* might be that tmpScaleFactor becomes negative, so fabs(.) */
351          tmpScaleFactor    = fixp_abs(stereoScaleFactor + fMult(tmpLeftReal,tmpRightReal) + fMult(tmpLeftImag,tmpRightImag));
352
353          /* min(2.0f, sqrt(stereoScaleFactor/(0.5f*tmpScaleFactor)))  */
354          if ( (stereoScaleFactor>>1) < fMult(maxStereoScaleFactor,tmpScaleFactor) ) {
355
356              int sc_num   = CountLeadingBits(stereoScaleFactor) ;
357              int sc_denum = CountLeadingBits(tmpScaleFactor) ;
358              sc       = -(sc_num-sc_denum);
359
360              tmpScaleFactor = schur_div((stereoScaleFactor<<(sc_num))>>1,
361                                          tmpScaleFactor<<sc_denum,
362                                          16) ;
363
364              /* prevent odd scaling for next sqrt calculation */
365              if (sc&0x1) {
366                sc++;
367                tmpScaleFactor>>=1;
368              }
369              stereoScaleFactor = sqrtFixp(tmpScaleFactor);
370              stereoScaleFactor <<= (sc>>1);
371          }
372          else {
373              stereoScaleFactor = maxStereoScaleFactor;
374          }
375
376          /* write data to hybrid output */
377          tmpHybrid[0][k] = fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftReal + tmpRightReal))>>dynScale;
378          tmpHybrid[1][k] = fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftImag + tmpRightImag))>>dynScale;
379
380      } /* hybrid bands - k */
381
382      FDKhybridSynthesisApply(
383            &hParametricStereo->fdkHybSynFilter,
384             tmpHybrid[0],
385             tmpHybrid[1],
386             mixRealQmfData[n],
387             mixImagQmfData[n]);
388
389      qmfSynthesisFilteringSlot(
390            sbrSynthQmf,
391            mixRealQmfData[n],
392            mixImagQmfData[n],
393            downmixScale-7,
394            downmixScale-7,
395            downsampledOutSignal+(n*sbrSynthQmf->no_channels),
396            1,
397            pWorkBuffer);
398
399    } /* slots */
400
401    *qmfScale = -downmixScale + 7;
402
403    C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_QMF, 2*QMF_CHANNELS)
404
405  {
406    const INT noQmfSlots2 = hParametricStereo->noQmfSlots>>1;
407    const int noQmfBands  = hParametricStereo->noQmfBands;
408
409    INT scale, i, j, slotOffset;
410
411    FIXP_QMF tmp[2][QMF_CHANNELS];
412
413    for (i=0; i<noQmfSlots2; i++) {
414      FDKmemcpy(tmp[0], hParametricStereo->qmfDelayLines[0][i], noQmfBands*sizeof(FIXP_QMF));
415      FDKmemcpy(tmp[1], hParametricStereo->qmfDelayLines[1][i], noQmfBands*sizeof(FIXP_QMF));
416
417      FDKmemcpy(hParametricStereo->qmfDelayLines[0][i], mixRealQmfData[i+noQmfSlots2], noQmfBands*sizeof(FIXP_QMF));
418      FDKmemcpy(hParametricStereo->qmfDelayLines[1][i], mixImagQmfData[i+noQmfSlots2], noQmfBands*sizeof(FIXP_QMF));
419
420      FDKmemcpy(mixRealQmfData[i+noQmfSlots2], mixRealQmfData[i], noQmfBands*sizeof(FIXP_QMF));
421      FDKmemcpy(mixImagQmfData[i+noQmfSlots2], mixImagQmfData[i], noQmfBands*sizeof(FIXP_QMF));
422
423      FDKmemcpy(mixRealQmfData[i], tmp[0], noQmfBands*sizeof(FIXP_QMF));
424      FDKmemcpy(mixImagQmfData[i], tmp[1], noQmfBands*sizeof(FIXP_QMF));
425    }
426
427    if (hParametricStereo->qmfDelayScale > *qmfScale) {
428      scale = hParametricStereo->qmfDelayScale - *qmfScale;
429      slotOffset = 0;
430    }
431    else {
432      scale = *qmfScale - hParametricStereo->qmfDelayScale;
433      slotOffset = noQmfSlots2;
434    }
435
436    for (i=0; i<noQmfSlots2; i++) {
437      for (j=0; j<noQmfBands; j++) {
438        mixRealQmfData[i+slotOffset][j] >>= scale;
439        mixImagQmfData[i+slotOffset][j] >>= scale;
440      }
441    }
442
443    scale = *qmfScale;
444    *qmfScale = FDKmin(*qmfScale, hParametricStereo->qmfDelayScale);
445    hParametricStereo->qmfDelayScale = scale;
446  }
447
448  } /* valid handle */
449
450  return error;
451}
452
453
454INT FDKsbrEnc_PSEnc_WritePSData(
455        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
456        HANDLE_FDK_BITSTREAM      hBitstream
457        )
458{
459  return ( (hParametricStereo!=NULL) ? FDKsbrEnc_WritePSBitstream(&hParametricStereo->psOut[0], hBitstream) : 0 );
460}
461
462
463FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing(
464        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
465        INT_PCM                  *samples[2],
466        UINT                      timeInStride,
467        QMF_FILTER_BANK         **hQmfAnalysis,
468        FIXP_QMF **RESTRICT       downmixedRealQmfData,
469        FIXP_QMF **RESTRICT       downmixedImagQmfData,
470        INT_PCM                  *downsampledOutSignal,
471        HANDLE_QMF_FILTER_BANK    sbrSynthQmf,
472        SCHAR                    *qmfScale,
473        const int                 sendHeader
474        )
475{
476  FDK_PSENC_ERROR error = PSENC_OK;
477  INT psQmfScale[MAX_PS_CHANNELS] = {0};
478  int psCh, i;
479  C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_QMF, 4*QMF_CHANNELS)
480
481  for (psCh = 0; psCh<MAX_PS_CHANNELS; psCh ++) {
482
483    for (i = 0; i < hQmfAnalysis[psCh]->no_col; i++) {
484
485      qmfAnalysisFilteringSlot(
486          hQmfAnalysis[psCh],
487         &pWorkBuffer[2*QMF_CHANNELS], /* qmfReal[QMF_CHANNELS] */
488         &pWorkBuffer[3*QMF_CHANNELS], /* qmfImag[QMF_CHANNELS] */
489          samples[psCh]+i*(hQmfAnalysis[psCh]->no_channels*timeInStride),
490          timeInStride,
491         &pWorkBuffer[0*QMF_CHANNELS]  /* qmf workbuffer 2*QMF_CHANNELS */
492          );
493
494      FDKhybridAnalysisApply(
495         &hParametricStereo->fdkHybAnaFilter[psCh],
496         &pWorkBuffer[2*QMF_CHANNELS],  /* qmfReal[QMF_CHANNELS] */
497         &pWorkBuffer[3*QMF_CHANNELS],  /* qmfImag[QMF_CHANNELS] */
498          hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][psCh][0],
499          hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][psCh][1]
500          );
501
502    } /* no_col loop  i  */
503
504    psQmfScale[psCh] = hQmfAnalysis[psCh]->outScalefactor;
505
506  } /* for psCh */
507
508  C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_QMF, 4*QMF_CHANNELS)
509
510  /* find best scaling in new QMF and Hybrid data */
511  psFindBestScaling( hParametricStereo,
512                    &hParametricStereo->pHybridData[HYBRID_READ_OFFSET],
513                     hParametricStereo->dynBandScale,
514                     hParametricStereo->maxBandValue,
515                    &hParametricStereo->dmxScale ) ;
516
517
518  /* extract the ps parameters */
519  if(PSENC_OK != (error = ExtractPSParameters(hParametricStereo, sendHeader, &hParametricStereo->pHybridData[0]))){
520    goto bail;
521  }
522
523  /* save hybrid date for next frame */
524  for (i=0; i<HYBRID_READ_OFFSET; i++) {
525    FDKmemcpy(hParametricStereo->pHybridData[i][0][0], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][0][0], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* left, real */
526    FDKmemcpy(hParametricStereo->pHybridData[i][0][1], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][0][1], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* left, imag */
527    FDKmemcpy(hParametricStereo->pHybridData[i][1][0], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][1][0], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* right, real */
528    FDKmemcpy(hParametricStereo->pHybridData[i][1][1], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][1][1], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* right, imag */
529  }
530
531  /* downmix and hybrid synthesis */
532  if (PSENC_OK != (error = DownmixPSQmfData(hParametricStereo, sbrSynthQmf, downmixedRealQmfData, downmixedImagQmfData, downsampledOutSignal, &hParametricStereo->pHybridData[HYBRID_READ_OFFSET], hParametricStereo->noQmfSlots, psQmfScale, qmfScale))) {
533    goto bail;
534  }
535
536bail:
537
538  return error;
539}
540
541static void psFindBestScaling(
542        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
543        FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
544        UCHAR                    *dynBandScale,
545        FIXP_QMF                 *maxBandValue,
546        SCHAR                    *dmxScale
547        )
548{
549  HANDLE_PS_ENCODE hPsEncode      =  hParametricStereo->hPsEncode;
550
551  INT group, bin, col, band;
552  const INT frameSize  = hParametricStereo->noQmfSlots;
553  const INT psBands    = (INT) hPsEncode->psEncMode;
554  const INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups;
555
556  /* group wise scaling */
557  FIXP_QMF maxVal [2][PS_MAX_BANDS];
558  FIXP_QMF maxValue = FL2FXCONST_DBL(0.f);
559
560  FDKmemclear(maxVal, sizeof(maxVal));
561
562  /* start with hybrid data */
563  for (group=0; group < nIidGroups; group++) {
564    /* Translate group to bin */
565    bin = hPsEncode->subband2parameterIndex[group];
566
567    /* Translate from 20 bins to 10 bins */
568    if (hPsEncode->psEncMode == PS_BANDS_COARSE) {
569      bin >>= 1;
570    }
571
572    /* QMF downmix scaling */
573    {
574      FIXP_QMF tmp = maxVal[0][bin];
575      int i;
576      for (col=0; col<frameSize-HYBRID_READ_OFFSET; col++) {
577        for (i = hPsEncode->iidGroupBorders[group]; i < hPsEncode->iidGroupBorders[group+1]; i++) {
578          tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][0][i]));
579          tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][1][i]));
580          tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][0][i]));
581          tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][1][i]));
582        }
583      }
584      maxVal[0][bin] = tmp;
585
586      tmp = maxVal[1][bin];
587      for (col=frameSize-HYBRID_READ_OFFSET; col<frameSize; col++) {
588        for (i = hPsEncode->iidGroupBorders[group]; i < hPsEncode->iidGroupBorders[group+1]; i++) {
589          tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][0][i]));
590          tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][1][i]));
591          tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][0][i]));
592          tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][1][i]));
593        }
594      }
595      maxVal[1][bin] = tmp;
596    }
597  } /* nIidGroups */
598
599  /* convert maxSpec to maxScaling, find scaling space */
600  for (band=0; band<psBands; band++) {
601#ifndef MULT_16x16
602    dynBandScale[band] = CountLeadingBits(fixMax(maxVal[0][band],maxBandValue[band]));
603#else
604    dynBandScale[band] = fixMax(0,CountLeadingBits(fixMax(maxVal[0][band],maxBandValue[band]))-FRACT_BITS);
605#endif
606    maxValue = fixMax(maxValue,fixMax(maxVal[0][band],maxVal[1][band]));
607    maxBandValue[band] = fixMax(maxVal[0][band], maxVal[1][band]);
608  }
609
610  /* calculate maximal scaling for QMF downmix */
611#ifndef MULT_16x16
612  *dmxScale = fixMin(DFRACT_BITS, CountLeadingBits(maxValue));
613#else
614  *dmxScale = fixMax(0,fixMin(FRACT_BITS, CountLeadingBits(FX_QMF2FX_DBL(maxValue))));
615#endif
616
617}
618
619