| /* ----------------------------------------------------------------------------- |
| 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 */ |