| /* ----------------------------------------------------------------------------- | |
| Software License for The Fraunhofer FDK AAC Codec Library for Android | |
| © Copyright 1995 - 2018 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 | |
| ----------------------------------------------------------------------------- */ | |
| /**************************** SBR decoder library ****************************** | |
| Author(s): | |
| Description: | |
| *******************************************************************************/ | |
| /*! | |
| \file | |
| \brief parametric stereo decoder | |
| */ | |
| #include "psdec.h" | |
| #include "FDK_bitbuffer.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); | |
| /***** HELPERS *****/ | |
| /***************************************************************************/ | |
| /*! | |
| \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) { | |
| goto bail; | |
| } | |
| } else { | |
| /* Reset an open instance */ | |
| h_ps_d = *h_PS_DEC; | |
| } | |
| /* | |
| * Create Analysis Hybrid filterbank. | |
| */ | |
| FDKhybridAnalysisOpen(&h_ps_d->specificTo.mpeg.hybridAnalysis, | |
| h_ps_d->specificTo.mpeg.pHybridAnaStatesLFdmx, | |
| sizeof(h_ps_d->specificTo.mpeg.pHybridAnaStatesLFdmx), | |
| NULL, 0); | |
| /* 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; | |
| } | |
| { | |
| int error; | |
| error = FDKdecorrelateOpen(&(h_ps_d->specificTo.mpeg.apDecor), | |
| h_ps_d->specificTo.mpeg.decorrBufferCplx, | |
| (2 * ((825) + (373)))); | |
| if (error) goto bail; | |
| } | |
| 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; | |
| *h_PS_DEC = h_ps_d; | |
| return 0; | |
| bail: | |
| if (h_ps_d != NULL) { | |
| 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; | |
| } | |
| { | |
| HANDLE_PS_DEC h_ps_d = *h_PS_DEC; | |
| FDKdecorrelateClose(&(h_ps_d->specificTo.mpeg.apDecor)); | |
| } | |
| 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; | |
| /* explicitly init state variables to safe values (until first ps header | |
| * arrives) */ | |
| h_ps_d->specificTo.mpeg.lastUsb = 0; | |
| /* | |
| * Initialize Analysis Hybrid filterbank. | |
| */ | |
| FDKhybridAnalysisInit(&h_ps_d->specificTo.mpeg.hybridAnalysis, THREE_TO_TEN, | |
| NO_QMF_BANDS_HYBRID20, NO_QMF_BANDS_HYBRID20, 1); | |
| /* | |
| * Initialize Synthesis Hybrid filterbank. | |
| */ | |
| for (i = 0; i < 2; i++) { | |
| FDKhybridSynthesisInit(&h_ps_d->specificTo.mpeg.hybridSynthesis[i], | |
| THREE_TO_TEN, NO_QMF_CHANNELS, NO_QMF_CHANNELS); | |
| } | |
| { | |
| INT error; | |
| error = FDKdecorrelateInit(&h_ps_d->specificTo.mpeg.apDecor, 71, DECORR_PS, | |
| DUCKER_AUTOMATIC, 0, 0, 0, 0, 1, /* isLegacyPS */ | |
| 1); | |
| if (error) return SBRDEC_NOT_INITIALIZED; | |
| } | |
| 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 Feed delaylines when parametric stereo is switched on. | |
| \return | |
| ****************************************************************************/ | |
| void PreparePsProcessing(HANDLE_PS_DEC h_ps_d, | |
| const FIXP_DBL *const *const rIntBufferLeft, | |
| const FIXP_DBL *const *const iIntBufferLeft, | |
| const int scaleFactorLowBand) { | |
| if (h_ps_d->procFrameBased == | |
| 1) /* If we have switched from frame to slot based processing */ | |
| { /* fill hybrid delay buffer. */ | |
| int i, j; | |
| for (i = 0; i < HYBRID_FILTER_DELAY; i++) { | |
| FIXP_DBL qmfInputData[2][NO_QMF_BANDS_HYBRID20]; | |
| FIXP_DBL hybridOutputData[2][NO_SUB_QMF_CHANNELS]; | |
| for (j = 0; j < NO_QMF_BANDS_HYBRID20; j++) { | |
| qmfInputData[0][j] = | |
| scaleValue(rIntBufferLeft[i][j], scaleFactorLowBand); | |
| qmfInputData[1][j] = | |
| scaleValue(iIntBufferLeft[i][j], scaleFactorLowBand); | |
| } | |
| FDKhybridAnalysisApply(&h_ps_d->specificTo.mpeg.hybridAnalysis, | |
| qmfInputData[0], qmfInputData[1], | |
| hybridOutputData[0], hybridOutputData[1]); | |
| } | |
| h_ps_d->procFrameBased = 0; /* switch to slot based processing. */ | |
| } /* procFrameBased==1 */ | |
| } | |
| 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; | |
| FIXP_SGL invL; | |
| FIXP_DBL ScaleL, ScaleR; | |
| FIXP_DBL Alpha, Beta; | |
| FIXP_DBL h11r, h12r, h21r, h22r; | |
| const FIXP_DBL *PScaleFactors; | |
| if (h_ps_d->bsData[h_ps_d->processSlot].mpeg.bFineIidQ) { | |
| PScaleFactors = ScaleFactorsFine; /* values are shiftet right by one */ | |
| noIidSteps = NO_IID_STEPS_FINE; | |
| } else { | |
| PScaleFactors = ScaleFactors; /* values are shiftet right by one */ | |
| noIidSteps = NO_IID_STEPS; | |
| } | |
| /* 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.pCoef | |
| ->aaIidIndexMapped[env][bin]]; | |
| ScaleL = PScaleFactors[noIidSteps - h_ps_d->specificTo.mpeg.pCoef | |
| ->aaIidIndexMapped[env][bin]]; | |
| Beta = fMult( | |
| fMult(Alphas[h_ps_d->specificTo.mpeg.pCoef->aaIccIndexMapped[env][bin]], | |
| (ScaleR - ScaleL)), | |
| FIXP_SQRT05); | |
| Alpha = | |
| Alphas[h_ps_d->specificTo.mpeg.pCoef->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.pCoef->H11r[group] = | |
| h_ps_d->specificTo.mpeg.h11rPrev[group]; | |
| h_ps_d->specificTo.mpeg.pCoef->H12r[group] = | |
| h_ps_d->specificTo.mpeg.h12rPrev[group]; | |
| h_ps_d->specificTo.mpeg.pCoef->H21r[group] = | |
| h_ps_d->specificTo.mpeg.h21rPrev[group]; | |
| h_ps_d->specificTo.mpeg.pCoef->H22r[group] = | |
| h_ps_d->specificTo.mpeg.h22rPrev[group]; | |
| h_ps_d->specificTo.mpeg.pCoef->DeltaH11r[group] = | |
| fMult(h11r - h_ps_d->specificTo.mpeg.pCoef->H11r[group], invL); | |
| h_ps_d->specificTo.mpeg.pCoef->DeltaH12r[group] = | |
| fMult(h12r - h_ps_d->specificTo.mpeg.pCoef->H12r[group], invL); | |
| h_ps_d->specificTo.mpeg.pCoef->DeltaH21r[group] = | |
| fMult(h21r - h_ps_d->specificTo.mpeg.pCoef->H21r[group], invL); | |
| h_ps_d->specificTo.mpeg.pCoef->DeltaH22r[group] = | |
| fMult(h22r - h_ps_d->specificTo.mpeg.pCoef->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 const UCHAR groupTable[NO_IID_GROUPS + 1] = { | |
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, | |
| 12, 13, 14, 15, 16, 18, 21, 25, 30, 42, 71}; | |
| 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 *mHybridRealRight, /*!< hybrid values real right */ | |
| FIXP_DBL *mHybridImagRight /*!< hybrid values imag right */ | |
| ) { | |
| INT group; | |
| INT subband; | |
| /**********************************************************************************************/ | |
| /*! | |
| <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 | |
| ************************************************************************************************/ | |
| /******************************************************/ | |
| /* 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) */ | |
| /******************************************************/ | |
| PS_DEC_COEFFICIENTS *pCoef = h_ps_d->specificTo.mpeg.pCoef; | |
| for (group = 0; group < NO_IID_GROUPS; group++) { | |
| pCoef->H11r[group] += pCoef->DeltaH11r[group]; | |
| pCoef->H12r[group] += pCoef->DeltaH12r[group]; | |
| pCoef->H21r[group] += pCoef->DeltaH21r[group]; | |
| pCoef->H22r[group] += pCoef->DeltaH22r[group]; | |
| const int start = groupTable[group]; | |
| const int stop = groupTable[group + 1]; | |
| for (subband = start; subband < stop; subband++) { | |
| FIXP_DBL tmpLeft = | |
| fMultAdd(fMultDiv2(pCoef->H11r[group], mHybridRealLeft[subband]), | |
| pCoef->H21r[group], mHybridRealRight[subband]); | |
| FIXP_DBL tmpRight = | |
| fMultAdd(fMultDiv2(pCoef->H12r[group], mHybridRealLeft[subband]), | |
| pCoef->H22r[group], mHybridRealRight[subband]); | |
| mHybridRealLeft[subband] = tmpLeft; | |
| mHybridRealRight[subband] = tmpRight; | |
| tmpLeft = | |
| fMultAdd(fMultDiv2(pCoef->H11r[group], mHybridImagLeft[subband]), | |
| pCoef->H21r[group], mHybridImagRight[subband]); | |
| tmpRight = | |
| fMultAdd(fMultDiv2(pCoef->H12r[group], mHybridImagLeft[subband]), | |
| pCoef->H22r[group], mHybridImagRight[subband]); | |
| mHybridImagLeft[subband] = tmpLeft; | |
| mHybridImagRight[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) */ | |
| const int scaleFactorLowBand_no_ov, const int scaleFactorLowBand, | |
| const int scaleFactorHighBand, const int lsb, const int usb) { | |
| /*! | |
| 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 |-----> | |
| ------------- | 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> | |
| */ | |
| #define NO_HYBRID_DATA_BANDS (71) | |
| int i; | |
| FIXP_DBL qmfInputData[2][NO_QMF_BANDS_HYBRID20]; | |
| FIXP_DBL *hybridData[2][2]; | |
| C_ALLOC_SCRATCH_START(pHybridData, FIXP_DBL, 4 * NO_HYBRID_DATA_BANDS); | |
| hybridData[0][0] = | |
| pHybridData + 0 * NO_HYBRID_DATA_BANDS; /* left real hybrid data */ | |
| hybridData[0][1] = | |
| pHybridData + 1 * NO_HYBRID_DATA_BANDS; /* left imag hybrid data */ | |
| hybridData[1][0] = | |
| pHybridData + 2 * NO_HYBRID_DATA_BANDS; /* right real hybrid data */ | |
| hybridData[1][1] = | |
| pHybridData + 3 * NO_HYBRID_DATA_BANDS; /* right imag hybrid data */ | |
| /*! | |
| 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) ) | |
| */ | |
| /* | |
| * Hybrid analysis. | |
| */ | |
| /* Get qmf input data and apply descaling */ | |
| for (i = 0; i < NO_QMF_BANDS_HYBRID20; i++) { | |
| qmfInputData[0][i] = scaleValue(rIntBufferLeft[HYBRID_FILTER_DELAY][i], | |
| scaleFactorLowBand_no_ov); | |
| qmfInputData[1][i] = scaleValue(iIntBufferLeft[HYBRID_FILTER_DELAY][i], | |
| scaleFactorLowBand_no_ov); | |
| } | |
| /* LF - part */ | |
| FDKhybridAnalysisApply(&h_ps_d->specificTo.mpeg.hybridAnalysis, | |
| qmfInputData[0], qmfInputData[1], hybridData[0][0], | |
| hybridData[0][1]); | |
| /* HF - part */ | |
| /* bands up to lsb */ | |
| scaleValues(&hybridData[0][0][NO_SUB_QMF_CHANNELS - 2], | |
| &rIntBufferLeft[0][NO_QMF_BANDS_HYBRID20], | |
| lsb - NO_QMF_BANDS_HYBRID20, scaleFactorLowBand); | |
| scaleValues(&hybridData[0][1][NO_SUB_QMF_CHANNELS - 2], | |
| &iIntBufferLeft[0][NO_QMF_BANDS_HYBRID20], | |
| lsb - NO_QMF_BANDS_HYBRID20, scaleFactorLowBand); | |
| /* bands from lsb to usb */ | |
| scaleValues(&hybridData[0][0][lsb + (NO_SUB_QMF_CHANNELS - 2 - | |
| NO_QMF_BANDS_HYBRID20)], | |
| &rIntBufferLeft[0][lsb], usb - lsb, scaleFactorHighBand); | |
| scaleValues(&hybridData[0][1][lsb + (NO_SUB_QMF_CHANNELS - 2 - | |
| NO_QMF_BANDS_HYBRID20)], | |
| &iIntBufferLeft[0][lsb], usb - lsb, scaleFactorHighBand); | |
| /* bands from usb to NO_SUB_QMF_CHANNELS which should be zero for non-overlap | |
| slots but can be non-zero for overlap slots */ | |
| FDKmemcpy( | |
| &hybridData[0][0] | |
| [usb + (NO_SUB_QMF_CHANNELS - 2 - NO_QMF_BANDS_HYBRID20)], | |
| &rIntBufferLeft[0][usb], sizeof(FIXP_DBL) * (NO_QMF_CHANNELS - usb)); | |
| FDKmemcpy( | |
| &hybridData[0][1] | |
| [usb + (NO_SUB_QMF_CHANNELS - 2 - NO_QMF_BANDS_HYBRID20)], | |
| &iIntBufferLeft[0][usb], sizeof(FIXP_DBL) * (NO_QMF_CHANNELS - usb)); | |
| /*! | |
| 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 | |
| */ | |
| FDKdecorrelateApply(&h_ps_d->specificTo.mpeg.apDecor, | |
| &hybridData[0][0][0], /* left real hybrid data */ | |
| &hybridData[0][1][0], /* left imag hybrid data */ | |
| &hybridData[1][0][0], /* right real hybrid data */ | |
| &hybridData[1][1][0], /* right imag hybrid data */ | |
| 0 /* startHybBand */ | |
| ); | |
| /*! | |
| 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, | |
| &hybridData[0][0][0], /* left real hybrid data */ | |
| &hybridData[0][1][0], /* left imag hybrid data */ | |
| &hybridData[1][0][0], /* right real hybrid data */ | |
| &hybridData[1][1][0] /* right imag hybrid data */ | |
| ); | |
| /*! | |
| 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. | |
| */ | |
| /* | |
| * Hybrid synthesis. | |
| */ | |
| for (i = 0; i < 2; i++) { | |
| FDKhybridSynthesisApply( | |
| &h_ps_d->specificTo.mpeg.hybridSynthesis[i], | |
| hybridData[i][0], /* real hybrid data */ | |
| hybridData[i][1], /* imag hybrid data */ | |
| (i == 0) ? rIntBufferLeft[0] | |
| : rIntBufferRight, /* output real qmf buffer */ | |
| (i == 0) ? iIntBufferLeft[0] | |
| : iIntBufferRight /* output imag qmf buffer */ | |
| ); | |
| } | |
| /* free temporary hybrid qmf values of one timeslot */ | |
| C_ALLOC_SCRATCH_END(pHybridData, FIXP_DBL, 4 * NO_HYBRID_DATA_BANDS); | |
| } /* END ApplyPsSlot */ |