| |
| /* ----------------------------------------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. |
| All rights reserved. |
| |
| 1. INTRODUCTION |
| The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements |
| the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. |
| This FDK AAC Codec software is intended to be used on a wide variety of Android devices. |
| |
| AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual |
| audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by |
| independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part |
| of the MPEG specifications. |
| |
| Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) |
| may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners |
| individually for the purpose of encoding or decoding bit streams in products that are compliant with |
| the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license |
| these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec |
| software may already be covered under those patent licenses when it is used for those licensed purposes only. |
| |
| Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, |
| are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional |
| applications information and documentation. |
| |
| 2. COPYRIGHT LICENSE |
| |
| Redistribution and use in source and binary forms, with or without modification, are permitted without |
| payment of copyright license fees provided that you satisfy the following conditions: |
| |
| You must retain the complete text of this software license in redistributions of the FDK AAC Codec or |
| your modifications thereto in source code form. |
| |
| You must retain the complete text of this software license in the documentation and/or other materials |
| provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. |
| You must make available free of charge copies of the complete source code of the FDK AAC Codec and your |
| modifications thereto to recipients of copies in binary form. |
| |
| The name of Fraunhofer may not be used to endorse or promote products derived from this library without |
| prior written permission. |
| |
| You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec |
| software or your modifications thereto. |
| |
| Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software |
| and the date of any change. For modified versions of the FDK AAC Codec, the term |
| "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term |
| "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." |
| |
| 3. NO PATENT LICENSE |
| |
| NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, |
| ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with |
| respect to this software. |
| |
| You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized |
| by appropriate patent licenses. |
| |
| 4. DISCLAIMER |
| |
| This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors |
| "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties |
| of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages, |
| including but not limited to procurement of substitute goods or services; loss of use, data, or profits, |
| or business interruption, however caused and on any theory of liability, whether in contract, strict |
| liability, or tort (including negligence), arising in any way out of the use of this software, even if |
| advised of the possibility of such damage. |
| |
| 5. CONTACT INFORMATION |
| |
| Fraunhofer Institute for Integrated Circuits IIS |
| Attention: Audio and Multimedia Departments - FDK AAC LL |
| Am Wolfsmantel 33 |
| 91058 Erlangen, Germany |
| |
| www.iis.fraunhofer.de/amm |
| amm-info@iis.fraunhofer.de |
| ----------------------------------------------------------------------------------------------------------- */ |
| |
| /*! |
| \file |
| \brief parametric stereo decoder |
| */ |
| |
| #include "psdec.h" |
| |
| |
| |
| #include "FDK_bitbuffer.h" |
| #include "psdec_hybrid.h" |
| |
| #include "sbr_rom.h" |
| #include "sbr_ram.h" |
| |
| #include "FDK_tools_rom.h" |
| |
| #include "genericStds.h" |
| |
| #include "FDK_trigFcts.h" |
| |
| |
| /********************************************************************/ |
| /* MLQUAL DEFINES */ |
| /********************************************************************/ |
| |
| #define FRACT_ZERO FRACT_BITS-1 |
| /********************************************************************/ |
| |
| SBR_ERROR ResetPsDec( HANDLE_PS_DEC h_ps_d ); |
| |
| void ResetPsDeCor( HANDLE_PS_DEC h_ps_d ); |
| |
| |
| /***** HELPERS *****/ |
| |
| static void assignTimeSlotsPS (FIXP_DBL *bufAdr, FIXP_DBL **bufPtr, const int numSlots, const int numChan); |
| |
| |
| |
| /*******************/ |
| |
| #define DIV3 FL2FXCONST_DBL(1.f/3.f) /* division 3.0 */ |
| #define DIV1_5 FL2FXCONST_DBL(2.f/3.f) /* division 1.5 */ |
| |
| /***************************************************************************/ |
| /*! |
| \brief Creates one instance of the PS_DEC struct |
| |
| \return Error info |
| |
| ****************************************************************************/ |
| int |
| CreatePsDec( HANDLE_PS_DEC *h_PS_DEC, /*!< pointer to the module state */ |
| int aacSamplesPerFrame |
| ) |
| { |
| SBR_ERROR errorInfo = SBRDEC_OK; |
| HANDLE_PS_DEC h_ps_d; |
| int i; |
| |
| if (*h_PS_DEC == NULL) { |
| /* Get ps dec ram */ |
| h_ps_d = GetRam_ps_dec(); |
| if (h_ps_d == NULL) { |
| errorInfo = SBRDEC_MEM_ALLOC_FAILED; |
| goto bail; |
| } |
| } else { |
| /* Reset an open instance */ |
| h_ps_d = *h_PS_DEC; |
| } |
| |
| /* initialisation */ |
| switch (aacSamplesPerFrame) { |
| case 960: |
| h_ps_d->noSubSamples = 30; /* col */ |
| break; |
| case 1024: |
| h_ps_d->noSubSamples = 32; /* col */ |
| break; |
| default: |
| h_ps_d->noSubSamples = -1; |
| break; |
| } |
| |
| if (h_ps_d->noSubSamples > MAX_NUM_COL |
| || h_ps_d->noSubSamples <= 0) |
| { |
| goto bail; |
| } |
| h_ps_d->noChannels = NO_QMF_CHANNELS; /* row */ |
| |
| h_ps_d->psDecodedPrv = 0; |
| h_ps_d->procFrameBased = -1; |
| for (i = 0; i < (1)+1; i++) { |
| h_ps_d->bPsDataAvail[i] = ppt_none; |
| } |
| |
| |
| for (i = 0; i < (1)+1; i++) { |
| FDKmemclear(&h_ps_d->bsData[i].mpeg, sizeof(MPEG_PS_BS_DATA)); |
| } |
| |
| errorInfo = ResetPsDec( h_ps_d ); |
| |
| if ( errorInfo != SBRDEC_OK ) |
| goto bail; |
| |
| ResetPsDeCor( h_ps_d ); |
| |
| *h_PS_DEC = h_ps_d; |
| |
| |
| |
| return 0; |
| |
| bail: |
| DeletePsDec(&h_ps_d); |
| |
| return -1; |
| } /*END CreatePsDec */ |
| |
| /***************************************************************************/ |
| /*! |
| \brief Delete one instance of the PS_DEC struct |
| |
| \return Error info |
| |
| ****************************************************************************/ |
| int |
| DeletePsDec( HANDLE_PS_DEC *h_PS_DEC) /*!< pointer to the module state */ |
| { |
| if (*h_PS_DEC == NULL) { |
| return -1; |
| } |
| |
| |
| FreeRam_ps_dec(h_PS_DEC); |
| |
| |
| return 0; |
| } /*END DeletePsDec */ |
| |
| /***************************************************************************/ |
| /*! |
| \brief resets some values of the PS handle to default states |
| |
| \return |
| |
| ****************************************************************************/ |
| SBR_ERROR ResetPsDec( HANDLE_PS_DEC h_ps_d ) /*!< pointer to the module state */ |
| { |
| SBR_ERROR errorInfo = SBRDEC_OK; |
| INT i; |
| |
| const UCHAR noQmfBandsInHybrid20 = 3; |
| /* const UCHAR noQmfBandsInHybrid34 = 5; */ |
| |
| const UCHAR aHybridResolution20[] = { HYBRID_8_CPLX, |
| HYBRID_2_REAL, |
| HYBRID_2_REAL }; |
| |
| h_ps_d->specificTo.mpeg.delayBufIndex = 0; |
| |
| /* explicitly init state variables to safe values (until first ps header arrives) */ |
| |
| h_ps_d->specificTo.mpeg.lastUsb = 0; |
| |
| h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer = -(DFRACT_BITS-1); |
| |
| FDKmemclear(h_ps_d->specificTo.mpeg.aDelayBufIndexDelayQmf, (NO_QMF_CHANNELS-FIRST_DELAY_SB)*sizeof(UCHAR)); |
| h_ps_d->specificTo.mpeg.noSampleDelay = delayIndexQmf[0]; |
| |
| for (i=0 ; i < NO_SERIAL_ALLPASS_LINKS; i++) { |
| h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[i] = 0; |
| } |
| |
| h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[0] = h_ps_d->specificTo.mpeg.aaQmfDelayBufReal; |
| |
| assignTimeSlotsPS ( h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[0] + (NO_QMF_CHANNELS-FIRST_DELAY_SB), |
| &h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[1], |
| h_ps_d->specificTo.mpeg.noSampleDelay-1, |
| (NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)); |
| |
| h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[0] = h_ps_d->specificTo.mpeg.aaQmfDelayBufImag; |
| |
| assignTimeSlotsPS ( h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[0] + (NO_QMF_CHANNELS-FIRST_DELAY_SB), |
| &h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[1], |
| h_ps_d->specificTo.mpeg.noSampleDelay-1, |
| (NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)); |
| |
| /* Hybrid Filter Bank 1 creation. */ |
| errorInfo = InitHybridFilterBank ( &h_ps_d->specificTo.mpeg.hybrid, |
| h_ps_d->noSubSamples, |
| noQmfBandsInHybrid20, |
| aHybridResolution20 ); |
| |
| for ( i = 0; i < NO_IID_GROUPS; i++ ) |
| { |
| h_ps_d->specificTo.mpeg.h11rPrev[i] = FL2FXCONST_DBL(0.5f); |
| h_ps_d->specificTo.mpeg.h12rPrev[i] = FL2FXCONST_DBL(0.5f); |
| } |
| |
| FDKmemclear( h_ps_d->specificTo.mpeg.h21rPrev, sizeof( h_ps_d->specificTo.mpeg.h21rPrev ) ); |
| FDKmemclear( h_ps_d->specificTo.mpeg.h22rPrev, sizeof( h_ps_d->specificTo.mpeg.h22rPrev ) ); |
| |
| return errorInfo; |
| } |
| |
| /***************************************************************************/ |
| /*! |
| \brief clear some buffers used in decorrelation process |
| |
| \return |
| |
| ****************************************************************************/ |
| void ResetPsDeCor( HANDLE_PS_DEC h_ps_d ) /*!< pointer to the module state */ |
| { |
| INT i; |
| |
| FDKmemclear(h_ps_d->specificTo.mpeg.aPeakDecayFastBin, NO_MID_RES_BINS*sizeof(FIXP_DBL)); |
| FDKmemclear(h_ps_d->specificTo.mpeg.aPrevNrgBin, NO_MID_RES_BINS*sizeof(FIXP_DBL)); |
| FDKmemclear(h_ps_d->specificTo.mpeg.aPrevPeakDiffBin, NO_MID_RES_BINS*sizeof(FIXP_DBL)); |
| FDKmemclear(h_ps_d->specificTo.mpeg.aPowerPrevScal, NO_MID_RES_BINS*sizeof(SCHAR)); |
| |
| for (i=0 ; i < FIRST_DELAY_SB ; i++) { |
| FDKmemclear(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); |
| FDKmemclear(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); |
| } |
| for (i=0 ; i < NO_SUB_QMF_CHANNELS ; i++) { |
| FDKmemclear(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); |
| FDKmemclear(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); |
| } |
| |
| } |
| |
| /*******************************************************************************/ |
| |
| /* slot based funcion prototypes */ |
| |
| static void deCorrelateSlotBased( HANDLE_PS_DEC h_ps_d, |
| |
| FIXP_DBL *mHybridRealLeft, |
| FIXP_DBL *mHybridImagLeft, |
| SCHAR sf_mHybridLeft, |
| |
| FIXP_DBL *rIntBufferLeft, |
| FIXP_DBL *iIntBufferLeft, |
| SCHAR sf_IntBuffer, |
| |
| FIXP_DBL *mHybridRealRight, |
| FIXP_DBL *mHybridImagRight, |
| |
| FIXP_DBL *rIntBufferRight, |
| FIXP_DBL *iIntBufferRight ); |
| |
| static void applySlotBasedRotation( HANDLE_PS_DEC h_ps_d, |
| |
| FIXP_DBL *mHybridRealLeft, |
| FIXP_DBL *mHybridImagLeft, |
| |
| FIXP_DBL *QmfLeftReal, |
| FIXP_DBL *QmfLeftImag, |
| |
| FIXP_DBL *mHybridRealRight, |
| FIXP_DBL *mHybridImagRight, |
| |
| FIXP_DBL *QmfRightReal, |
| FIXP_DBL *QmfRightImag |
| ); |
| |
| |
| /***************************************************************************/ |
| /*! |
| \brief Get scale factor for all ps delay buffer. |
| |
| \return |
| |
| ****************************************************************************/ |
| static |
| int getScaleFactorPsStatesBuffer(HANDLE_PS_DEC h_ps_d) |
| { |
| INT i; |
| int scale = DFRACT_BITS-1; |
| |
| for (i=0; i<NO_QMF_BANDS_HYBRID20; i++) { |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.hybrid.mQmfBufferRealSlot[i], NO_SUB_QMF_CHANNELS)); |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.hybrid.mQmfBufferImagSlot[i], NO_SUB_QMF_CHANNELS)); |
| } |
| |
| for (i=0; i<NO_SAMPLE_DELAY_ALLPASS; i++) { |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaRealDelayBufferQmf[i], FIRST_DELAY_SB)); |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaImagDelayBufferQmf[i], FIRST_DELAY_SB)); |
| } |
| |
| for (i=0; i<NO_SAMPLE_DELAY_ALLPASS; i++) { |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaRealDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS)); |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaImagDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS)); |
| } |
| |
| for (i=0; i<FIRST_DELAY_SB; i++) { |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS)); |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS)); |
| } |
| |
| for (i=0; i<NO_SUB_QMF_CHANNELS; i++) { |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS)); |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS)); |
| } |
| |
| for (i=0; i<MAX_DELAY_BUFFER_SIZE; i++) |
| { |
| INT len; |
| if (i==0) |
| len = NO_QMF_CHANNELS-FIRST_DELAY_SB; |
| else |
| len = NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB; |
| |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[i], len)); |
| scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[i], len)); |
| } |
| |
| return (scale); |
| } |
| |
| /***************************************************************************/ |
| /*! |
| \brief Rescale all ps delay buffer. |
| |
| \return |
| |
| ****************************************************************************/ |
| static |
| void scalePsStatesBuffer(HANDLE_PS_DEC h_ps_d, |
| int scale) |
| { |
| INT i; |
| |
| if (scale < 0) |
| scale = fixMax((INT)scale,(INT)-(DFRACT_BITS-1)); |
| else |
| scale = fixMin((INT)scale,(INT)DFRACT_BITS-1); |
| |
| for (i=0; i<NO_QMF_BANDS_HYBRID20; i++) { |
| scaleValues( h_ps_d->specificTo.mpeg.hybrid.mQmfBufferRealSlot[i], NO_SUB_QMF_CHANNELS, scale ); |
| scaleValues( h_ps_d->specificTo.mpeg.hybrid.mQmfBufferImagSlot[i], NO_SUB_QMF_CHANNELS, scale ); |
| } |
| |
| for (i=0; i<NO_SAMPLE_DELAY_ALLPASS; i++) { |
| scaleValues( h_ps_d->specificTo.mpeg.aaRealDelayBufferQmf[i], FIRST_DELAY_SB, scale ); |
| scaleValues( h_ps_d->specificTo.mpeg.aaImagDelayBufferQmf[i], FIRST_DELAY_SB, scale ); |
| } |
| |
| for (i=0; i<NO_SAMPLE_DELAY_ALLPASS; i++) { |
| scaleValues( h_ps_d->specificTo.mpeg.aaRealDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS, scale ); |
| scaleValues( h_ps_d->specificTo.mpeg.aaImagDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS, scale ); |
| } |
| |
| for (i=0; i<FIRST_DELAY_SB; i++) { |
| scaleValues( h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); |
| scaleValues( h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); |
| } |
| |
| for (i=0; i<NO_SUB_QMF_CHANNELS; i++) { |
| scaleValues( h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); |
| scaleValues( h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); |
| } |
| |
| for (i=0; i<MAX_DELAY_BUFFER_SIZE; i++) { |
| INT len; |
| if (i==0) |
| len = NO_QMF_CHANNELS-FIRST_DELAY_SB; |
| else |
| len = NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB; |
| |
| scaleValues( h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[i], len, scale ); |
| scaleValues( h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[i], len, scale ); |
| } |
| |
| scale <<= 1; |
| |
| scaleValues( h_ps_d->specificTo.mpeg.aPeakDecayFastBin, NO_MID_RES_BINS, scale ); |
| scaleValues( h_ps_d->specificTo.mpeg.aPrevPeakDiffBin, NO_MID_RES_BINS, scale ); |
| scaleValues( h_ps_d->specificTo.mpeg.aPrevNrgBin, NO_MID_RES_BINS, scale ); |
| } |
| |
| /***************************************************************************/ |
| /*! |
| \brief Scale input channel to the same scalefactor and rescale hybrid |
| filterbank values |
| |
| \return |
| |
| ****************************************************************************/ |
| |
| void scalFilterBankValues( HANDLE_PS_DEC h_ps_d, |
| FIXP_DBL **fixpQmfReal, |
| FIXP_DBL **fixpQmfImag, |
| int lsb, |
| int scaleFactorLowBandSplitLow, |
| int scaleFactorLowBandSplitHigh, |
| SCHAR *scaleFactorLowBand_lb, |
| SCHAR *scaleFactorLowBand_hb, |
| int scaleFactorHighBands, |
| INT *scaleFactorHighBand, |
| INT noCols |
| ) |
| { |
| INT maxScal; |
| |
| INT i; |
| |
| scaleFactorHighBands = -scaleFactorHighBands; |
| scaleFactorLowBandSplitLow = -scaleFactorLowBandSplitLow; |
| scaleFactorLowBandSplitHigh = -scaleFactorLowBandSplitHigh; |
| |
| /* get max scale factor */ |
| maxScal = fixMax(scaleFactorHighBands,fixMax(scaleFactorLowBandSplitLow, scaleFactorLowBandSplitHigh )); |
| |
| { |
| int headroom = getScaleFactorPsStatesBuffer(h_ps_d); |
| maxScal = fixMax(maxScal,(INT)(h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer-headroom)); |
| maxScal += 1; |
| } |
| |
| /* scale whole left channel to the same scale factor */ |
| |
| /* low band ( overlap buffer ) */ |
| if ( maxScal != scaleFactorLowBandSplitLow ) { |
| INT scale = scaleFactorLowBandSplitLow - maxScal; |
| for ( i=0; i<(6); i++ ) { |
| scaleValues( fixpQmfReal[i], lsb, scale ); |
| scaleValues( fixpQmfImag[i], lsb, scale ); |
| } |
| } |
| /* low band ( current frame ) */ |
| if ( maxScal != scaleFactorLowBandSplitHigh ) { |
| INT scale = scaleFactorLowBandSplitHigh - maxScal; |
| /* for ( i=(6); i<(6)+MAX_NUM_COL; i++ ) { */ |
| for ( i=(6); i<(6)+noCols; i++ ) { |
| scaleValues( fixpQmfReal[i], lsb, scale ); |
| scaleValues( fixpQmfImag[i], lsb, scale ); |
| } |
| } |
| /* high band */ |
| if ( maxScal != scaleFactorHighBands ) { |
| INT scale = scaleFactorHighBands - maxScal; |
| /* for ( i=0; i<MAX_NUM_COL; i++ ) { */ |
| for ( i=0; i<noCols; i++ ) { |
| scaleValues( &fixpQmfReal[i][lsb], (64)-lsb, scale ); |
| scaleValues( &fixpQmfImag[i][lsb], (64)-lsb, scale ); |
| } |
| } |
| |
| if ( maxScal != h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer ) |
| scalePsStatesBuffer(h_ps_d,(h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer-maxScal)); |
| |
| h_ps_d->specificTo.mpeg.hybrid.sf_mQmfBuffer = maxScal; |
| h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer = maxScal; |
| |
| *scaleFactorHighBand += maxScal - scaleFactorHighBands; |
| |
| h_ps_d->rescal = maxScal - scaleFactorLowBandSplitHigh; |
| h_ps_d->sf_IntBuffer = maxScal; |
| |
| *scaleFactorLowBand_lb += maxScal - scaleFactorLowBandSplitLow; |
| *scaleFactorLowBand_hb += maxScal - scaleFactorLowBandSplitHigh; |
| } |
| |
| void rescalFilterBankValues( HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */ |
| FIXP_DBL **QmfBufferReal, /* qmf filterbank values */ |
| FIXP_DBL **QmfBufferImag, /* qmf filterbank values */ |
| int lsb, /* sbr start subband */ |
| INT noCols) |
| { |
| int i; |
| /* scale back 6 timeslots look ahead for hybrid filterbank to original value */ |
| for ( i=noCols; i<noCols + (6); i++ ) { |
| scaleValues( QmfBufferReal[i], lsb, h_ps_d->rescal ); |
| scaleValues( QmfBufferImag[i], lsb, h_ps_d->rescal ); |
| } |
| } |
| |
| /***************************************************************************/ |
| /*! |
| \brief Generate decorrelated side channel using allpass/delay |
| |
| \return |
| |
| ****************************************************************************/ |
| static void |
| deCorrelateSlotBased( HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */ |
| |
| FIXP_DBL *mHybridRealLeft, /*!< left (mono) hybrid values real */ |
| FIXP_DBL *mHybridImagLeft, /*!< left (mono) hybrid values imag */ |
| SCHAR sf_mHybridLeft, /*!< scalefactor for left (mono) hybrid bands */ |
| |
| FIXP_DBL *rIntBufferLeft, /*!< real qmf bands left (mono) (38x64) */ |
| FIXP_DBL *iIntBufferLeft, /*!< real qmf bands left (mono) (38x64) */ |
| SCHAR sf_IntBuffer, /*!< scalefactor for all left and right qmf bands */ |
| |
| FIXP_DBL *mHybridRealRight, /*!< right (decorrelated) hybrid values real */ |
| FIXP_DBL *mHybridImagRight, /*!< right (decorrelated) hybrid values imag */ |
| |
| FIXP_DBL *rIntBufferRight, /*!< real qmf bands right (decorrelated) (38x64) */ |
| FIXP_DBL *iIntBufferRight ) /*!< real qmf bands right (decorrelated) (38x64) */ |
| { |
| |
| INT i, m, sb, gr, bin; |
| |
| FIXP_DBL peakDiff, nrg, transRatio; |
| |
| FIXP_DBL *RESTRICT aaLeftReal; |
| FIXP_DBL *RESTRICT aaLeftImag; |
| |
| FIXP_DBL *RESTRICT aaRightReal; |
| FIXP_DBL *RESTRICT aaRightImag; |
| |
| FIXP_DBL *RESTRICT pRealDelayBuffer; |
| FIXP_DBL *RESTRICT pImagDelayBuffer; |
| |
| C_ALLOC_SCRATCH_START(aaPowerSlot, FIXP_DBL, NO_MID_RES_BINS); |
| C_ALLOC_SCRATCH_START(aaTransRatioSlot, FIXP_DBL, NO_MID_RES_BINS); |
| |
| /*! |
| <pre> |
| parameter index qmf bands hybrid bands |
| ---------------------------------------------------------------------------- |
| 0 0 0,7 |
| 1 0 1,6 |
| 2 0 2 |
| 3 0 3 HYBRID BANDS |
| 4 1 9 |
| 5 1 8 |
| 6 2 10 |
| 7 2 11 |
| ---------------------------------------------------------------------------- |
| 8 3 |
| 9 4 |
| 10 5 |
| 11 6 |
| 12 7 |
| 13 8 |
| 14 9,10 (2 ) QMF BANDS |
| 15 11 - 13 (3 ) |
| 16 14 - 17 (4 ) |
| 17 18 - 22 (5 ) |
| 18 23 - 34 (12) |
| 19 35 - 63 (29) |
| ---------------------------------------------------------------------------- |
| </pre> |
| */ |
| |
| #define FLTR_SCALE 3 |
| |
| /* hybrid bands (parameter index 0 - 7) */ |
| aaLeftReal = mHybridRealLeft; |
| aaLeftImag = mHybridImagLeft; |
| |
| aaPowerSlot[0] = ( fMultAddDiv2( fMultDiv2(aaLeftReal[0], aaLeftReal[0]), aaLeftImag[0], aaLeftImag[0] ) >> FLTR_SCALE ) + |
| ( fMultAddDiv2( fMultDiv2(aaLeftReal[7], aaLeftReal[7]), aaLeftImag[7], aaLeftImag[7] ) >> FLTR_SCALE ); |
| |
| aaPowerSlot[1] = ( fMultAddDiv2( fMultDiv2(aaLeftReal[1], aaLeftReal[1]), aaLeftImag[1], aaLeftImag[1] ) >> FLTR_SCALE ) + |
| ( fMultAddDiv2( fMultDiv2(aaLeftReal[6], aaLeftReal[6]), aaLeftImag[6], aaLeftImag[6] ) >> FLTR_SCALE ); |
| |
| aaPowerSlot[2] = fMultAddDiv2( fMultDiv2(aaLeftReal[2], aaLeftReal[2]), aaLeftImag[2], aaLeftImag[2] ) >> FLTR_SCALE; |
| aaPowerSlot[3] = fMultAddDiv2( fMultDiv2(aaLeftReal[3], aaLeftReal[3]), aaLeftImag[3], aaLeftImag[3] ) >> FLTR_SCALE; |
| |
| aaPowerSlot[4] = fMultAddDiv2( fMultDiv2(aaLeftReal[9], aaLeftReal[9]), aaLeftImag[9], aaLeftImag[9] ) >> FLTR_SCALE; |
| aaPowerSlot[5] = fMultAddDiv2( fMultDiv2(aaLeftReal[8], aaLeftReal[8]), aaLeftImag[8], aaLeftImag[8] ) >> FLTR_SCALE; |
| |
| aaPowerSlot[6] = fMultAddDiv2( fMultDiv2(aaLeftReal[10], aaLeftReal[10]), aaLeftImag[10], aaLeftImag[10] ) >> FLTR_SCALE; |
| aaPowerSlot[7] = fMultAddDiv2( fMultDiv2(aaLeftReal[11], aaLeftReal[11]), aaLeftImag[11], aaLeftImag[11] ) >> FLTR_SCALE; |
| |
| /* qmf bands (parameter index 8 - 19) */ |
| for ( bin = 8; bin < NO_MID_RES_BINS; bin++ ) { |
| FIXP_DBL slotNrg = FL2FXCONST_DBL(0.f); |
| |
| for ( i = groupBorders20[bin+2]; i < groupBorders20[bin+3]; i++ ) { /* max loops: 29 */ |
| slotNrg += fMultAddDiv2 ( fMultDiv2(rIntBufferLeft[i], rIntBufferLeft[i]), iIntBufferLeft[i], iIntBufferLeft[i]) >> FLTR_SCALE; |
| } |
| aaPowerSlot[bin] = slotNrg; |
| |
| } |
| |
| |
| /* calculation of transient ratio */ |
| for (bin=0; bin < NO_MID_RES_BINS; bin++) { /* noBins = 20 ( BASELINE_PS ) */ |
| |
| h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] = fMult( h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin], PEAK_DECAY_FACTOR ); |
| |
| if (h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] < aaPowerSlot[bin]) { |
| h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] = aaPowerSlot[bin]; |
| } |
| |
| /* calculate PSmoothPeakDecayDiffNrg */ |
| peakDiff = fMultAdd ( (h_ps_d->specificTo.mpeg.aPrevPeakDiffBin[bin]>>1), |
| INT_FILTER_COEFF, h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] - aaPowerSlot[bin] - h_ps_d->specificTo.mpeg.aPrevPeakDiffBin[bin]); |
| |
| /* save peakDiff for the next frame */ |
| h_ps_d->specificTo.mpeg.aPrevPeakDiffBin[bin] = peakDiff; |
| |
| nrg = h_ps_d->specificTo.mpeg.aPrevNrgBin[bin] + fMult( INT_FILTER_COEFF, aaPowerSlot[bin] - h_ps_d->specificTo.mpeg.aPrevNrgBin[bin] ); |
| |
| /* Negative energies don't exist. But sometimes they appear due to rounding. */ |
| |
| nrg = fixMax(nrg,FL2FXCONST_DBL(0.f)); |
| |
| /* save nrg for the next frame */ |
| h_ps_d->specificTo.mpeg.aPrevNrgBin[bin] = nrg; |
| |
| nrg = fMult( nrg, TRANSIENT_IMPACT_FACTOR ); |
| |
| /* save transient impact factor */ |
| if ( peakDiff <= nrg || peakDiff == FL2FXCONST_DBL(0.0) ) { |
| aaTransRatioSlot[bin] = (FIXP_DBL)MAXVAL_DBL /* FL2FXCONST_DBL(1.0f)*/; |
| } |
| else if ( nrg <= FL2FXCONST_DBL(0.0f) ) { |
| aaTransRatioSlot[bin] = FL2FXCONST_DBL(0.f); |
| } |
| else { |
| /* scale to denominator */ |
| INT scale_left = fixMax(0, CntLeadingZeros(peakDiff) - 1); |
| aaTransRatioSlot[bin] = schur_div( nrg<<scale_left, peakDiff<<scale_left, 16); |
| } |
| } /* bin */ |
| |
| |
| |
| |
| #define DELAY_GROUP_OFFSET 20 |
| #define NR_OF_DELAY_GROUPS 2 |
| |
| FIXP_DBL rTmp, iTmp, rTmp0, iTmp0, rR0, iR0; |
| |
| INT TempDelay = h_ps_d->specificTo.mpeg.delayBufIndex; /* set delay indices */ |
| |
| pRealDelayBuffer = h_ps_d->specificTo.mpeg.aaRealDelayBufferSubQmf[TempDelay]; |
| pImagDelayBuffer = h_ps_d->specificTo.mpeg.aaImagDelayBufferSubQmf[TempDelay]; |
| |
| aaLeftReal = mHybridRealLeft; |
| aaLeftImag = mHybridImagLeft; |
| aaRightReal = mHybridRealRight; |
| aaRightImag = mHybridImagRight; |
| |
| /************************/ |
| /* ICC groups : 0 - 9 */ |
| /************************/ |
| |
| /* gr = ICC groups */ |
| for (gr=0; gr < SUBQMF_GROUPS; gr++) { |
| |
| transRatio = aaTransRatioSlot[bins2groupMap20[gr]]; |
| |
| /* sb = subQMF/QMF subband */ |
| sb = groupBorders20[gr]; |
| |
| /* Update delay buffers, sample delay allpass = 2 */ |
| rTmp0 = pRealDelayBuffer[sb]; |
| iTmp0 = pImagDelayBuffer[sb]; |
| |
| pRealDelayBuffer[sb] = aaLeftReal[sb]; |
| pImagDelayBuffer[sb] = aaLeftImag[sb]; |
| |
| /* delay by fraction */ |
| cplxMultDiv2(&rR0, &iR0, rTmp0, iTmp0, aaFractDelayPhaseFactorReSubQmf20[sb], aaFractDelayPhaseFactorImSubQmf20[sb]); |
| rR0<<=1; |
| iR0<<=1; |
| |
| FIXP_DBL *pAaaRealDelayRBufferSerSubQmf = h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[sb]; |
| FIXP_DBL *pAaaImagDelayRBufferSerSubQmf = h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[sb]; |
| |
| for (m=0; m<NO_SERIAL_ALLPASS_LINKS ; m++) { |
| |
| INT tmpDelayRSer = h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[m]; |
| |
| /* get delayed values from according buffer : m(0)=3; m(1)=4; m(2)=5; */ |
| rTmp0 = pAaaRealDelayRBufferSerSubQmf[tmpDelayRSer]; |
| iTmp0 = pAaaImagDelayRBufferSerSubQmf[tmpDelayRSer]; |
| |
| /* delay by fraction */ |
| cplxMultDiv2(&rTmp, &iTmp, rTmp0, iTmp0, aaFractDelayPhaseFactorSerReSubQmf20[sb][m], aaFractDelayPhaseFactorSerImSubQmf20[sb][m]); |
| |
| rTmp = (rTmp - fMultDiv2(aAllpassLinkDecaySer[m], rR0)) << 1; |
| iTmp = (iTmp - fMultDiv2(aAllpassLinkDecaySer[m], iR0)) << 1; |
| |
| pAaaRealDelayRBufferSerSubQmf[tmpDelayRSer] = rR0 + fMult(aAllpassLinkDecaySer[m], rTmp); |
| pAaaImagDelayRBufferSerSubQmf[tmpDelayRSer] = iR0 + fMult(aAllpassLinkDecaySer[m], iTmp); |
| |
| rR0 = rTmp; |
| iR0 = iTmp; |
| |
| pAaaRealDelayRBufferSerSubQmf += aAllpassLinkDelaySer[m]; |
| pAaaImagDelayRBufferSerSubQmf += aAllpassLinkDelaySer[m]; |
| |
| } /* m */ |
| |
| /* duck if a past transient is found */ |
| aaRightReal[sb] = fMult(transRatio, rR0); |
| aaRightImag[sb] = fMult(transRatio, iR0); |
| |
| } /* gr */ |
| |
| |
| scaleValues( mHybridRealLeft, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); |
| scaleValues( mHybridImagLeft, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); |
| scaleValues( mHybridRealRight, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); |
| scaleValues( mHybridImagRight, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); |
| |
| |
| /************************/ |
| |
| aaLeftReal = rIntBufferLeft; |
| aaLeftImag = iIntBufferLeft; |
| aaRightReal = rIntBufferRight; |
| aaRightImag = iIntBufferRight; |
| |
| pRealDelayBuffer = h_ps_d->specificTo.mpeg.aaRealDelayBufferQmf[TempDelay]; |
| pImagDelayBuffer = h_ps_d->specificTo.mpeg.aaImagDelayBufferQmf[TempDelay]; |
| |
| /************************/ |
| /* ICC groups : 10 - 19 */ |
| /************************/ |
| |
| |
| /* gr = ICC groups */ |
| for (gr=SUBQMF_GROUPS; gr < NO_IID_GROUPS - NR_OF_DELAY_GROUPS; gr++) { |
| |
| transRatio = aaTransRatioSlot[bins2groupMap20[gr]]; |
| |
| /* sb = subQMF/QMF subband */ |
| for (sb = groupBorders20[gr]; sb < groupBorders20[gr+1]; sb++) { |
| FIXP_DBL resR, resI; |
| |
| /* decayScaleFactor = 1.0f + decay_cutoff * DECAY_SLOPE - DECAY_SLOPE * sb; DECAY_SLOPE = 0.05 */ |
| FIXP_DBL decayScaleFactor = decayScaleFactTable[sb]; |
| |
| /* Update delay buffers, sample delay allpass = 2 */ |
| rTmp0 = pRealDelayBuffer[sb]; |
| iTmp0 = pImagDelayBuffer[sb]; |
| |
| pRealDelayBuffer[sb] = aaLeftReal[sb]; |
| pImagDelayBuffer[sb] = aaLeftImag[sb]; |
| |
| /* delay by fraction */ |
| cplxMultDiv2(&rR0, &iR0, rTmp0, iTmp0, aaFractDelayPhaseFactorReQmf[sb], aaFractDelayPhaseFactorImQmf[sb]); |
| rR0<<=1; |
| iR0<<=1; |
| |
| resR = fMult(decayScaleFactor, rR0); |
| resI = fMult(decayScaleFactor, iR0); |
| |
| FIXP_DBL *pAaaRealDelayRBufferSerQmf = h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[sb]; |
| FIXP_DBL *pAaaImagDelayRBufferSerQmf = h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[sb]; |
| |
| for (m=0; m<NO_SERIAL_ALLPASS_LINKS ; m++) { |
| |
| INT tmpDelayRSer = h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[m]; |
| |
| /* get delayed values from according buffer : m(0)=3; m(1)=4; m(2)=5; */ |
| rTmp0 = pAaaRealDelayRBufferSerQmf[tmpDelayRSer]; |
| iTmp0 = pAaaImagDelayRBufferSerQmf[tmpDelayRSer]; |
| |
| /* delay by fraction */ |
| cplxMultDiv2(&rTmp, &iTmp, rTmp0, iTmp0, aaFractDelayPhaseFactorSerReQmf[sb][m], aaFractDelayPhaseFactorSerImQmf[sb][m]); |
| |
| rTmp = (rTmp - fMultDiv2(aAllpassLinkDecaySer[m], resR))<<1; |
| iTmp = (iTmp - fMultDiv2(aAllpassLinkDecaySer[m], resI))<<1; |
| |
| resR = fMult(decayScaleFactor, rTmp); |
| resI = fMult(decayScaleFactor, iTmp); |
| |
| pAaaRealDelayRBufferSerQmf[tmpDelayRSer] = rR0 + fMult(aAllpassLinkDecaySer[m], resR); |
| pAaaImagDelayRBufferSerQmf[tmpDelayRSer] = iR0 + fMult(aAllpassLinkDecaySer[m], resI); |
| |
| rR0 = rTmp; |
| iR0 = iTmp; |
| |
| pAaaRealDelayRBufferSerQmf += aAllpassLinkDelaySer[m]; |
| pAaaImagDelayRBufferSerQmf += aAllpassLinkDelaySer[m]; |
| |
| } /* m */ |
| |
| /* duck if a past transient is found */ |
| aaRightReal[sb] = fMult(transRatio, rR0); |
| aaRightImag[sb] = fMult(transRatio, iR0); |
| |
| } /* sb */ |
| } /* gr */ |
| |
| /************************/ |
| /* ICC groups : 20, 21 */ |
| /************************/ |
| |
| |
| /* gr = ICC groups */ |
| for (gr=DELAY_GROUP_OFFSET; gr < NO_IID_GROUPS; gr++) { |
| |
| INT sbStart = groupBorders20[gr]; |
| INT sbStop = groupBorders20[gr+1]; |
| |
| UCHAR *pDelayBufIdx = &h_ps_d->specificTo.mpeg.aDelayBufIndexDelayQmf[sbStart-FIRST_DELAY_SB]; |
| |
| transRatio = aaTransRatioSlot[bins2groupMap20[gr]]; |
| |
| /* sb = subQMF/QMF subband */ |
| for (sb = sbStart; sb < sbStop; sb++) { |
| |
| /* Update delay buffers */ |
| rR0 = h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB]; |
| iR0 = h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB]; |
| |
| h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB] = aaLeftReal[sb]; |
| h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB] = aaLeftImag[sb]; |
| |
| /* duck if a past transient is found */ |
| aaRightReal[sb] = fMult(transRatio, rR0); |
| aaRightImag[sb] = fMult(transRatio, iR0); |
| |
| if (++(*pDelayBufIdx) >= delayIndexQmf[sb]) { |
| *pDelayBufIdx = 0; |
| } |
| pDelayBufIdx++; |
| |
| } /* sb */ |
| } /* gr */ |
| |
| |
| /* Update delay buffer index */ |
| if (++h_ps_d->specificTo.mpeg.delayBufIndex >= NO_SAMPLE_DELAY_ALLPASS) |
| h_ps_d->specificTo.mpeg.delayBufIndex = 0; |
| |
| for (m=0; m<NO_SERIAL_ALLPASS_LINKS ; m++) { |
| if (++h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[m] >= aAllpassLinkDelaySer[m]) |
| h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[m] = 0; |
| } |
| |
| |
| scaleValues( &rIntBufferLeft[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); |
| scaleValues( &iIntBufferLeft[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); |
| scaleValues( &rIntBufferRight[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); |
| scaleValues( &iIntBufferRight[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); |
| |
| /* free memory on scratch */ |
| C_ALLOC_SCRATCH_END(aaTransRatioSlot, FIXP_DBL, NO_MID_RES_BINS); |
| C_ALLOC_SCRATCH_END(aaPowerSlot, FIXP_DBL, NO_MID_RES_BINS); |
| } |
| |
| |
| void initSlotBasedRotation( HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */ |
| int env, |
| int usb |
| ) { |
| |
| INT group = 0; |
| INT bin = 0; |
| INT noIidSteps; |
| |
| /* const UCHAR *pQuantizedIIDs;*/ |
| |
| FIXP_SGL invL; |
| FIXP_DBL ScaleL, ScaleR; |
| FIXP_DBL Alpha, Beta; |
| FIXP_DBL h11r, h12r, h21r, h22r; |
| |
| const FIXP_DBL *PScaleFactors; |
| |
| /* Overwrite old values in delay buffers when upper subband is higher than in last frame */ |
| if (env == 0) { |
| |
| if ((usb > h_ps_d->specificTo.mpeg.lastUsb) && h_ps_d->specificTo.mpeg.lastUsb) { |
| |
| INT i,k,length; |
| |
| for (i=h_ps_d->specificTo.mpeg.lastUsb ; i < FIRST_DELAY_SB; i++) { |
| FDKmemclear(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); |
| FDKmemclear(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); |
| } |
| |
| for (k=0 ; k<NO_SAMPLE_DELAY_ALLPASS; k++) { |
| FDKmemclear(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[k], FIRST_DELAY_SB*sizeof(FIXP_DBL)); |
| } |
| length = (usb-FIRST_DELAY_SB)*sizeof(FIXP_DBL); |
| if(length>0) { |
| FDKmemclear(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[0], length); |
| FDKmemclear(h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[0], length); |
| } |
| length = (fixMin(NO_DELAY_BUFFER_BANDS,(INT)usb)-FIRST_DELAY_SB)*sizeof(FIXP_DBL); |
| if(length>0) { |
| for (k=1 ; k < h_ps_d->specificTo.mpeg.noSampleDelay; k++) { |
| FDKmemclear(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[k], length); |
| FDKmemclear(h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[k], length); |
| } |
| } |
| } |
| h_ps_d->specificTo.mpeg.lastUsb = usb; |
| } /* env == 0 */ |
| |
| if (h_ps_d->bsData[h_ps_d->processSlot].mpeg.bFineIidQ) |
| { |
| PScaleFactors = ScaleFactorsFine; /* values are shiftet right by one */ |
| noIidSteps = NO_IID_STEPS_FINE; |
| /*pQuantizedIIDs = quantizedIIDsFine;*/ |
| } |
| |
| else |
| { |
| PScaleFactors = ScaleFactors; /* values are shiftet right by one */ |
| noIidSteps = NO_IID_STEPS; |
| /*pQuantizedIIDs = quantizedIIDs;*/ |
| } |
| |
| |
| /* dequantize and decode */ |
| for ( group = 0; group < NO_IID_GROUPS; group++ ) { |
| |
| bin = bins2groupMap20[group]; |
| |
| /*! |
| <h3> type 'A' rotation </h3> |
| mixing procedure R_a, used in baseline version<br> |
| |
| Scale-factor vectors c1 and c2 are precalculated in initPsTables () and stored in |
| scaleFactors[] and scaleFactorsFine[] = pScaleFactors []. |
| From the linearized IID parameters (intensity differences), two scale factors are |
| calculated. They are used to obtain the coefficients h11... h22. |
| */ |
| |
| /* ScaleR and ScaleL are scaled by 1 shift right */ |
| |
| ScaleR = PScaleFactors[noIidSteps + h_ps_d->specificTo.mpeg.coef.aaIidIndexMapped[env][bin]]; |
| ScaleL = PScaleFactors[noIidSteps - h_ps_d->specificTo.mpeg.coef.aaIidIndexMapped[env][bin]]; |
| |
| Beta = fMult (fMult( Alphas[h_ps_d->specificTo.mpeg.coef.aaIccIndexMapped[env][bin]], ( ScaleR - ScaleL )), FIXP_SQRT05); |
| Alpha = Alphas[h_ps_d->specificTo.mpeg.coef.aaIccIndexMapped[env][bin]]>>1; |
| |
| /* Alpha and Beta are now both scaled by 2 shifts right */ |
| |
| /* calculate the coefficients h11... h22 from scale-factors and ICC parameters */ |
| |
| /* h values are scaled by 1 shift right */ |
| { |
| FIXP_DBL trigData[4]; |
| |
| inline_fixp_cos_sin(Beta + Alpha, Beta - Alpha, 2, trigData); |
| h11r = fMult( ScaleL, trigData[0]); |
| h12r = fMult( ScaleR, trigData[2]); |
| h21r = fMult( ScaleL, trigData[1]); |
| h22r = fMult( ScaleR, trigData[3]); |
| } |
| /*****************************************************************************************/ |
| /* Interpolation of the matrices H11... H22: */ |
| /* */ |
| /* H11(k,n) = H11(k,n[e]) + (n-n[e]) * (H11(k,n[e+1] - H11(k,n[e])) / (n[e+1] - n[e]) */ |
| /* ... */ |
| /*****************************************************************************************/ |
| |
| /* invL = 1/(length of envelope) */ |
| invL = FX_DBL2FX_SGL(GetInvInt(h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env + 1] - h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env])); |
| |
| h_ps_d->specificTo.mpeg.coef.H11r[group] = h_ps_d->specificTo.mpeg.h11rPrev[group]; |
| h_ps_d->specificTo.mpeg.coef.H12r[group] = h_ps_d->specificTo.mpeg.h12rPrev[group]; |
| h_ps_d->specificTo.mpeg.coef.H21r[group] = h_ps_d->specificTo.mpeg.h21rPrev[group]; |
| h_ps_d->specificTo.mpeg.coef.H22r[group] = h_ps_d->specificTo.mpeg.h22rPrev[group]; |
| |
| h_ps_d->specificTo.mpeg.coef.DeltaH11r[group] = fMult ( h11r - h_ps_d->specificTo.mpeg.coef.H11r[group], invL ); |
| h_ps_d->specificTo.mpeg.coef.DeltaH12r[group] = fMult ( h12r - h_ps_d->specificTo.mpeg.coef.H12r[group], invL ); |
| h_ps_d->specificTo.mpeg.coef.DeltaH21r[group] = fMult ( h21r - h_ps_d->specificTo.mpeg.coef.H21r[group], invL ); |
| h_ps_d->specificTo.mpeg.coef.DeltaH22r[group] = fMult ( h22r - h_ps_d->specificTo.mpeg.coef.H22r[group], invL ); |
| |
| /* update prev coefficients for interpolation in next envelope */ |
| |
| h_ps_d->specificTo.mpeg.h11rPrev[group] = h11r; |
| h_ps_d->specificTo.mpeg.h12rPrev[group] = h12r; |
| h_ps_d->specificTo.mpeg.h21rPrev[group] = h21r; |
| h_ps_d->specificTo.mpeg.h22rPrev[group] = h22r; |
| |
| } /* group loop */ |
| } |
| |
| |
| static void applySlotBasedRotation( HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */ |
| |
| FIXP_DBL *mHybridRealLeft, /*!< hybrid values real left */ |
| FIXP_DBL *mHybridImagLeft, /*!< hybrid values imag left */ |
| |
| FIXP_DBL *QmfLeftReal, /*!< real bands left qmf channel */ |
| FIXP_DBL *QmfLeftImag, /*!< imag bands left qmf channel */ |
| |
| FIXP_DBL *mHybridRealRight, /*!< hybrid values real right */ |
| FIXP_DBL *mHybridImagRight, /*!< hybrid values imag right */ |
| |
| FIXP_DBL *QmfRightReal, /*!< real bands right qmf channel */ |
| FIXP_DBL *QmfRightImag /*!< imag bands right qmf channel */ |
| ) |
| { |
| INT group; |
| INT subband; |
| |
| FIXP_DBL *RESTRICT HybrLeftReal; |
| FIXP_DBL *RESTRICT HybrLeftImag; |
| FIXP_DBL *RESTRICT HybrRightReal; |
| FIXP_DBL *RESTRICT HybrRightImag; |
| |
| FIXP_DBL tmpLeft, tmpRight; |
| |
| |
| /**********************************************************************************************/ |
| /*! |
| <h2> Mapping </h2> |
| |
| The number of stereo bands that is actually used depends on the number of availble |
| parameters for IID and ICC: |
| <pre> |
| nr. of IID para.| nr. of ICC para. | nr. of Stereo bands |
| ----------------|------------------|------------------- |
| 10,20 | 10,20 | 20 |
| 10,20 | 34 | 34 |
| 34 | 10,20 | 34 |
| 34 | 34 | 34 |
| </pre> |
| In the case the number of parameters for IIS and ICC differs from the number of stereo |
| bands, a mapping from the lower number to the higher number of parameters is applied. |
| Index mapping of IID and ICC parameters is already done in psbitdec.cpp. Further mapping is |
| not needed here in baseline version. |
| **********************************************************************************************/ |
| |
| /************************************************************************************************/ |
| /*! |
| <h2> Mixing </h2> |
| |
| To generate the QMF subband signals for the subband samples n = n[e]+1 ,,, n_[e+1] the |
| parameters at position n[e] and n[e+1] are required as well as the subband domain signals |
| s_k(n) and d_k(n) for n = n[e]+1... n_[e+1]. n[e] represents the start position for |
| envelope e. The border positions n[e] are handled in DecodePS(). |
| |
| The stereo sub subband signals are constructed as: |
| <pre> |
| l_k(n) = H11(k,n) s_k(n) + H21(k,n) d_k(n) |
| r_k(n) = H21(k,n) s_k(n) + H22(k,n) d_k(n) |
| </pre> |
| In order to obtain the matrices H11(k,n)... H22 (k,n), the vectors h11(b)... h22(b) need to |
| be calculated first (b: parameter index). Depending on ICC mode either mixing procedure R_a |
| or R_b is used for that. For both procedures, the parameters for parameter position n[e+1] |
| is used. |
| ************************************************************************************************/ |
| |
| |
| /************************************************************************************************/ |
| /*! |
| <h2>Phase parameters </h2> |
| With disabled phase parameters (which is the case in baseline version), the H-matrices are |
| just calculated by: |
| |
| <pre> |
| H11(k,n[e+1] = h11(b(k)) |
| (...) |
| b(k): parameter index according to mapping table |
| </pre> |
| |
| <h2>Processing of the samples in the sub subbands </h2> |
| this loop includes the interpolation of the coefficients Hxx |
| ************************************************************************************************/ |
| |
| |
| /* loop thru all groups ... */ |
| HybrLeftReal = mHybridRealLeft; |
| HybrLeftImag = mHybridImagLeft; |
| HybrRightReal = mHybridRealRight; |
| HybrRightImag = mHybridImagRight; |
| |
| /******************************************************/ |
| /* construct stereo sub subband signals according to: */ |
| /* */ |
| /* l_k(n) = H11(k,n) s_k(n) + H21(k,n) d_k(n) */ |
| /* r_k(n) = H12(k,n) s_k(n) + H22(k,n) d_k(n) */ |
| /******************************************************/ |
| for ( group = 0; group < SUBQMF_GROUPS; group++ ) { |
| |
| h_ps_d->specificTo.mpeg.coef.H11r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH11r[group]; |
| h_ps_d->specificTo.mpeg.coef.H12r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH12r[group]; |
| h_ps_d->specificTo.mpeg.coef.H21r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH21r[group]; |
| h_ps_d->specificTo.mpeg.coef.H22r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH22r[group]; |
| |
| subband = groupBorders20[group]; |
| |
| tmpLeft = fMultAddDiv2( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightReal[subband]); |
| tmpRight = fMultAddDiv2( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightReal[subband]); |
| HybrLeftReal [subband] = tmpLeft<<1; |
| HybrRightReal[subband] = tmpRight<<1; |
| |
| tmpLeft = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightImag[subband]); |
| tmpRight = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightImag[subband]); |
| HybrLeftImag [subband] = tmpLeft; |
| HybrRightImag[subband] = tmpRight; |
| } |
| |
| /* continue in the qmf buffers */ |
| HybrLeftReal = QmfLeftReal; |
| HybrLeftImag = QmfLeftImag; |
| HybrRightReal = QmfRightReal; |
| HybrRightImag = QmfRightImag; |
| |
| for (; group < NO_IID_GROUPS; group++ ) { |
| |
| h_ps_d->specificTo.mpeg.coef.H11r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH11r[group]; |
| h_ps_d->specificTo.mpeg.coef.H12r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH12r[group]; |
| h_ps_d->specificTo.mpeg.coef.H21r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH21r[group]; |
| h_ps_d->specificTo.mpeg.coef.H22r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH22r[group]; |
| |
| for ( subband = groupBorders20[group]; subband < groupBorders20[group + 1]; subband++ ) |
| { |
| tmpLeft = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightReal[subband]); |
| tmpRight = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightReal[subband]); |
| HybrLeftReal [subband] = tmpLeft; |
| HybrRightReal[subband] = tmpRight; |
| |
| tmpLeft = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightImag[subband]); |
| tmpRight = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightImag[subband]); |
| HybrLeftImag [subband] = tmpLeft; |
| HybrRightImag[subband] = tmpRight; |
| |
| } /* subband */ |
| } |
| } |
| |
| |
| /***************************************************************************/ |
| /*! |
| \brief Applies IID, ICC, IPD and OPD parameters to the current frame. |
| |
| \return none |
| |
| ****************************************************************************/ |
| void |
| ApplyPsSlot( HANDLE_PS_DEC h_ps_d, /*!< handle PS_DEC*/ |
| FIXP_DBL **rIntBufferLeft, /*!< real bands left qmf channel (38x64) */ |
| FIXP_DBL **iIntBufferLeft, /*!< imag bands left qmf channel (38x64) */ |
| FIXP_DBL *rIntBufferRight, /*!< real bands right qmf channel (38x64) */ |
| FIXP_DBL *iIntBufferRight /*!< imag bands right qmf channel (38x64) */ |
| ) |
| { |
| |
| /*! |
| The 64-band QMF representation of the monaural signal generated by the SBR tool |
| is used as input of the PS tool. After the PS processing, the outputs of the left |
| and right hybrid synthesis filterbanks are used to generate the stereo output |
| signal. |
| |
| <pre> |
| |
| ------------- ---------- ------------- |
| | Hybrid | M_n[k,m] | | L_n[k,m] | Hybrid | l[n] |
| m[n] --->| analysis |--------->| |--------->| synthesis |-----> |
| | filter bank | | | | filter bank | |
| ------------- | Stereo | ------------- |
| | | recon- | |
| | | stuction | |
| \|/ | | |
| ------------- | | |
| | De- | D_n[k,m] | | |
| | correlation |--------->| | |
| ------------- | | ------------- |
| | | R_n[k,m] | Hybrid | r[n] |
| | |--------->| synthesis |-----> |
| IID, ICC ------------------------>| | | filter bank | |
| (IPD, OPD) ---------- ------------- |
| |
| m[n]: QMF represantation of the mono input |
| M_n[k,m]: (sub-)sub-band domain signals of the mono input |
| D_n[k,m]: decorrelated (sub-)sub-band domain signals |
| L_n[k,m]: (sub-)sub-band domain signals of the left output |
| R_n[k,m]: (sub-)sub-band domain signals of the right output |
| l[n],r[n]: left/right output signals |
| |
| </pre> |
| */ |
| |
| /* get temporary hybrid qmf values of one timeslot */ |
| C_ALLOC_SCRATCH_START(hybridRealLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); |
| C_ALLOC_SCRATCH_START(hybridImagLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); |
| C_ALLOC_SCRATCH_START(hybridRealRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); |
| C_ALLOC_SCRATCH_START(hybridImagRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); |
| |
| SCHAR sf_IntBuffer = h_ps_d->sf_IntBuffer; |
| |
| /* clear workbuffer */ |
| FDKmemclear(hybridRealLeft, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); |
| FDKmemclear(hybridImagLeft, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); |
| FDKmemclear(hybridRealRight, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); |
| FDKmemclear(hybridImagRight, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); |
| |
| |
| /*! |
| Hybrid analysis filterbank: |
| The lower 3 (5) of the 64 QMF subbands are further split to provide better frequency resolution. |
| for PS processing. |
| For the 10 and 20 stereo bands configuration, the QMF band H_0(w) is split |
| up into 8 (sub-) sub-bands and the QMF bands H_1(w) and H_2(w) are spit into 2 (sub-) |
| 4th. (See figures 8.20 and 8.22 of ISO/IEC 14496-3:2001/FDAM 2:2004(E) ) |
| */ |
| |
| |
| if (h_ps_d->procFrameBased == 1) /* If we have switched from frame to slot based processing */ |
| { /* fill hybrid delay buffer. */ |
| h_ps_d->procFrameBased = 0; |
| |
| fillHybridDelayLine( rIntBufferLeft, |
| iIntBufferLeft, |
| hybridRealLeft, |
| hybridImagLeft, |
| hybridRealRight, |
| hybridImagRight, |
| &h_ps_d->specificTo.mpeg.hybrid ); |
| } |
| |
| slotBasedHybridAnalysis ( rIntBufferLeft[HYBRID_FILTER_DELAY], /* qmf filterbank values */ |
| iIntBufferLeft[HYBRID_FILTER_DELAY], /* qmf filterbank values */ |
| hybridRealLeft, /* hybrid filterbank values */ |
| hybridImagLeft, /* hybrid filterbank values */ |
| &h_ps_d->specificTo.mpeg.hybrid); /* hybrid filterbank handle */ |
| |
| |
| SCHAR hybridScal = h_ps_d->specificTo.mpeg.hybrid.sf_mQmfBuffer; |
| |
| |
| /*! |
| Decorrelation: |
| By means of all-pass filtering and delaying, the (sub-)sub-band samples s_k(n) are |
| converted into de-correlated (sub-)sub-band samples d_k(n). |
| - k: frequency in hybrid spectrum |
| - n: time index |
| */ |
| |
| deCorrelateSlotBased( h_ps_d, /* parametric stereo decoder handle */ |
| hybridRealLeft, /* left hybrid time slot */ |
| hybridImagLeft, |
| hybridScal, /* scale factor of left hybrid time slot */ |
| rIntBufferLeft[0], /* left qmf time slot */ |
| iIntBufferLeft[0], |
| sf_IntBuffer, /* scale factor of left and right qmf time slot */ |
| hybridRealRight, /* right hybrid time slot */ |
| hybridImagRight, |
| rIntBufferRight, /* right qmf time slot */ |
| iIntBufferRight ); |
| |
| |
| |
| /*! |
| Stereo Processing: |
| The sets of (sub-)sub-band samples s_k(n) and d_k(n) are processed according to |
| the stereo cues which are defined per stereo band. |
| */ |
| |
| |
| applySlotBasedRotation( h_ps_d, /* parametric stereo decoder handle */ |
| hybridRealLeft, /* left hybrid time slot */ |
| hybridImagLeft, |
| rIntBufferLeft[0], /* left qmf time slot */ |
| iIntBufferLeft[0], |
| hybridRealRight, /* right hybrid time slot */ |
| hybridImagRight, |
| rIntBufferRight, /* right qmf time slot */ |
| iIntBufferRight ); |
| |
| |
| |
| |
| /*! |
| Hybrid synthesis filterbank: |
| The stereo processed hybrid subband signals l_k(n) and r_k(n) are fed into the hybrid synthesis |
| filterbanks which are identical to the 64 complex synthesis filterbank of the SBR tool. The |
| input to the filterbank are slots of 64 QMF samples. For each slot the filterbank outputs one |
| block of 64 samples of one reconstructed stereo channel. The hybrid synthesis filterbank is |
| computed seperatly for the left and right channel. |
| */ |
| |
| |
| /* left channel */ |
| slotBasedHybridSynthesis ( hybridRealLeft, /* one timeslot of hybrid filterbank values */ |
| hybridImagLeft, |
| rIntBufferLeft[0], /* one timeslot of qmf filterbank values */ |
| iIntBufferLeft[0], |
| &h_ps_d->specificTo.mpeg.hybrid ); /* hybrid filterbank handle */ |
| |
| /* right channel */ |
| slotBasedHybridSynthesis ( hybridRealRight, /* one timeslot of hybrid filterbank values */ |
| hybridImagRight, |
| rIntBufferRight, /* one timeslot of qmf filterbank values */ |
| iIntBufferRight, |
| &h_ps_d->specificTo.mpeg.hybrid ); /* hybrid filterbank handle */ |
| |
| |
| |
| |
| |
| |
| |
| /* free temporary hybrid qmf values of one timeslot */ |
| C_ALLOC_SCRATCH_END(hybridImagRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); |
| C_ALLOC_SCRATCH_END(hybridRealRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); |
| C_ALLOC_SCRATCH_END(hybridImagLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); |
| C_ALLOC_SCRATCH_END(hybridRealLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); |
| |
| }/* END ApplyPsSlot */ |
| |
| |
| /***************************************************************************/ |
| /*! |
| |
| \brief assigns timeslots to an array |
| |
| \return |
| |
| ****************************************************************************/ |
| |
| static void assignTimeSlotsPS (FIXP_DBL *bufAdr, |
| FIXP_DBL **bufPtr, |
| const int numSlots, |
| const int numChan) |
| { |
| FIXP_DBL *ptr; |
| int slot; |
| ptr = bufAdr; |
| for(slot=0; slot < numSlots; slot++) { |
| bufPtr [slot] = ptr; |
| ptr += numChan; |
| } |
| } |
| |