1
2/* -----------------------------------------------------------------------------------------------------------
3Software License for The Fraunhofer FDK AAC Codec Library for Android
4
5© Copyright  1995 - 2012 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    /* clear scaling buffer */
231    FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR)*PS_MAX_BANDS);
232    FDKmemclear(hParametricStereo->maxBandValue, sizeof(FIXP_QMF)*PS_MAX_BANDS);
233
234  } /* valid handle */
235bail:
236  return error;
237}
238
239
240FDK_PSENC_ERROR PSEnc_Destroy(
241        HANDLE_PARAMETRIC_STEREO *phParametricStereo
242        )
243{
244  FDK_PSENC_ERROR error = PSENC_OK;
245
246  if (NULL!=phParametricStereo) {
247    HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo;
248    if(hParametricStereo != NULL){
249      FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode);
250      FreeRam_ParamStereo(phParametricStereo);
251    }
252  }
253
254  return error;
255}
256
257static FDK_PSENC_ERROR ExtractPSParameters(
258        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
259        const int                 sendHeader,
260        FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2]
261        )
262{
263  FDK_PSENC_ERROR error = PSENC_OK;
264
265  if (hParametricStereo == NULL) {
266    error = PSENC_INVALID_HANDLE;
267  }
268  else {
269    /* call ps encode function */
270    if (hParametricStereo->initPS){
271      hParametricStereo->psOut[1] = hParametricStereo->psOut[0];
272    }
273    hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
274
275    if (PSENC_OK != (error = FDKsbrEnc_PSEncode(
276            hParametricStereo->hPsEncode,
277           &hParametricStereo->psOut[1],
278            hParametricStereo->dynBandScale,
279            hParametricStereo->maxEnvelopes,
280            hybridData,
281            hParametricStereo->noQmfSlots,
282            sendHeader)))
283    {
284      goto bail;
285    }
286
287    if (hParametricStereo->initPS) {
288      hParametricStereo->psOut[0] = hParametricStereo->psOut[1];
289      hParametricStereo->initPS = 0;
290    }
291  }
292bail:
293  return error;
294}
295
296
297static FDK_PSENC_ERROR DownmixPSQmfData(
298       HANDLE_PARAMETRIC_STEREO  hParametricStereo,
299       HANDLE_QMF_FILTER_BANK    sbrSynthQmf,
300       FIXP_QMF       **RESTRICT mixRealQmfData,
301       FIXP_QMF       **RESTRICT mixImagQmfData,
302       INT_PCM                  *downsampledOutSignal,
303       FIXP_DBL                 *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2],
304       const INT                 noQmfSlots,
305       const INT                 psQmfScale[MAX_PS_CHANNELS],
306       SCHAR                    *qmfScale
307       )
308{
309  FDK_PSENC_ERROR error = PSENC_OK;
310
311  if(hParametricStereo == NULL){
312    error = PSENC_INVALID_HANDLE;
313  }
314  else {
315    int n, k;
316    C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_QMF, QMF_CHANNELS*2);
317
318    /* define scalings */
319    int dynQmfScale = fixMax(0, hParametricStereo->dmxScale-1); /* scale one bit more for addition of left and right */
320    int downmixScale = psQmfScale[0] - dynQmfScale;
321    const FIXP_DBL maxStereoScaleFactor = MAXVAL_DBL; /* 2.f/2.f */
322
323    for (n = 0; n<noQmfSlots; n++) {
324
325      FIXP_DBL tmpHybrid[2][MAX_HYBRID_BANDS];
326
327      for(k = 0; k<71; k++){
328          int dynScale, sc; /* scaling */
329          FIXP_QMF tmpLeftReal, tmpRightReal, tmpLeftImag, tmpRightImag;
330          FIXP_DBL tmpScaleFactor, stereoScaleFactor;
331
332          tmpLeftReal  = hybridData[n][0][0][k];
333          tmpLeftImag  = hybridData[n][0][1][k];
334          tmpRightReal = hybridData[n][1][0][k];
335          tmpRightImag = hybridData[n][1][1][k];
336
337          sc = fixMax(0,CntLeadingZeros( fixMax(fixMax(fixp_abs(tmpLeftReal),fixp_abs(tmpLeftImag)),fixMax(fixp_abs(tmpRightReal),fixp_abs(tmpRightImag))) )-2);
338
339          tmpLeftReal  <<= sc; tmpLeftImag  <<= sc;
340          tmpRightReal <<= sc; tmpRightImag <<= sc;
341          dynScale = fixMin(sc-dynQmfScale,DFRACT_BITS-1);
342
343          /* calc stereo scale factor to avoid loss of energy in bands                                                 */
344          /* 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))) )) */
345          stereoScaleFactor = fPow2Div2(tmpLeftReal)  + fPow2Div2(tmpLeftImag)
346                            + fPow2Div2(tmpRightReal) + fPow2Div2(tmpRightImag) ;
347
348          /* might be that tmpScaleFactor becomes negative, so fabs(.) */
349          tmpScaleFactor    = fixp_abs(stereoScaleFactor + fMult(tmpLeftReal,tmpRightReal) + fMult(tmpLeftImag,tmpRightImag));
350
351          /* min(2.0f, sqrt(stereoScaleFactor/(0.5f*tmpScaleFactor)))  */
352          if ( (stereoScaleFactor>>1) < fMult(maxStereoScaleFactor,tmpScaleFactor) ) {
353
354              int sc_num   = CountLeadingBits(stereoScaleFactor) ;
355              int sc_denum = CountLeadingBits(tmpScaleFactor) ;
356              sc       = -(sc_num-sc_denum);
357
358              tmpScaleFactor = schur_div((stereoScaleFactor<<(sc_num))>>1,
359                                          tmpScaleFactor<<sc_denum,
360                                          16) ;
361
362              /* prevent odd scaling for next sqrt calculation */
363              if (sc&0x1) {
364                sc++;
365                tmpScaleFactor>>=1;
366              }
367              stereoScaleFactor = sqrtFixp(tmpScaleFactor);
368              stereoScaleFactor <<= (sc>>1);
369          }
370          else {
371              stereoScaleFactor = maxStereoScaleFactor;
372          }
373
374          /* write data to hybrid output */
375          tmpHybrid[0][k] = fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftReal + tmpRightReal))>>dynScale;
376          tmpHybrid[1][k] = fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftImag + tmpRightImag))>>dynScale;
377
378      } /* hybrid bands - k */
379
380      FDKhybridSynthesisApply(
381            &hParametricStereo->fdkHybSynFilter,
382             tmpHybrid[0],
383             tmpHybrid[1],
384             mixRealQmfData[n],
385             mixImagQmfData[n]);
386
387      qmfSynthesisFilteringSlot(
388            sbrSynthQmf,
389            mixRealQmfData[n],
390            mixImagQmfData[n],
391            downmixScale-7,
392            downmixScale-7,
393            downsampledOutSignal+(n*sbrSynthQmf->no_channels),
394            1,
395            pWorkBuffer);
396
397    } /* slots */
398
399    *qmfScale = -downmixScale + 7;
400
401    C_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_QMF, QMF_CHANNELS*2);
402
403
404  {
405    const INT noQmfSlots2 = hParametricStereo->noQmfSlots>>1;
406    const int noQmfBands  = hParametricStereo->noQmfBands;
407
408    INT scale, i, j, slotOffset;
409
410    FIXP_QMF tmp[2][QMF_CHANNELS];
411
412    for (i=0; i<noQmfSlots2; i++) {
413      FDKmemcpy(tmp[0], hParametricStereo->qmfDelayLines[0][i], noQmfBands*sizeof(FIXP_QMF));
414      FDKmemcpy(tmp[1], hParametricStereo->qmfDelayLines[1][i], noQmfBands*sizeof(FIXP_QMF));
415
416      FDKmemcpy(hParametricStereo->qmfDelayLines[0][i], mixRealQmfData[i+noQmfSlots2], noQmfBands*sizeof(FIXP_QMF));
417      FDKmemcpy(hParametricStereo->qmfDelayLines[1][i], mixImagQmfData[i+noQmfSlots2], noQmfBands*sizeof(FIXP_QMF));
418
419      FDKmemcpy(mixRealQmfData[i+noQmfSlots2], mixRealQmfData[i], noQmfBands*sizeof(FIXP_QMF));
420      FDKmemcpy(mixImagQmfData[i+noQmfSlots2], mixImagQmfData[i], noQmfBands*sizeof(FIXP_QMF));
421
422      FDKmemcpy(mixRealQmfData[i], tmp[0], noQmfBands*sizeof(FIXP_QMF));
423      FDKmemcpy(mixImagQmfData[i], tmp[1], noQmfBands*sizeof(FIXP_QMF));
424    }
425
426    if (hParametricStereo->qmfDelayScale > *qmfScale) {
427      scale = hParametricStereo->qmfDelayScale - *qmfScale;
428      slotOffset = 0;
429    }
430    else {
431      scale = *qmfScale - hParametricStereo->qmfDelayScale;
432      slotOffset = noQmfSlots2;
433    }
434
435    for (i=0; i<noQmfSlots2; i++) {
436      for (j=0; j<noQmfBands; j++) {
437        mixRealQmfData[i+slotOffset][j] >>= scale;
438        mixImagQmfData[i+slotOffset][j] >>= scale;
439      }
440    }
441
442    scale = *qmfScale;
443    *qmfScale = FDKmin(*qmfScale, hParametricStereo->qmfDelayScale);
444    hParametricStereo->qmfDelayScale = scale;
445  }
446
447  } /* valid handle */
448
449  return error;
450}
451
452
453INT FDKsbrEnc_PSEnc_WritePSData(
454        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
455        HANDLE_FDK_BITSTREAM      hBitstream
456        )
457{
458  return ( (hParametricStereo!=NULL) ? FDKsbrEnc_WritePSBitstream(&hParametricStereo->psOut[0], hBitstream) : 0 );
459}
460
461
462FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing(
463        HANDLE_PARAMETRIC_STEREO  hParametricStereo,
464        INT_PCM                  *samples[2],
465        UINT                      timeInStride,
466        QMF_FILTER_BANK         **hQmfAnalysis,
467        FIXP_QMF **RESTRICT       downmixedRealQmfData,
468        FIXP_QMF **RESTRICT       downmixedImagQmfData,
469        INT_PCM                  *downsampledOutSignal,
470        HANDLE_QMF_FILTER_BANK    sbrSynthQmf,
471        SCHAR                    *qmfScale,
472        const int                 sendHeader
473        )
474{
475  FDK_PSENC_ERROR error = PSENC_OK;
476  INT noQmfBands  = hParametricStereo->noQmfBands;
477  INT psQmfScale[MAX_PS_CHANNELS] = {0};
478  int psCh, i;
479  C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, QMF_CHANNELS*4);
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_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, QMF_CHANNELS*4);
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