diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2012-07-11 10:15:24 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2012-07-11 10:15:24 -0700 |
commit | 2228e360595641dd906bf1773307f43d304f5b2e (patch) | |
tree | 57f3d390ebb0782cc0de0fb984c8ea7e45b4f386 /libSBRdec/src/sbr_dec.cpp | |
download | fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.tar.gz fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.tar.bz2 fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.zip |
Snapshot 2bda038c163298531d47394bc2c09e1409c5d0db
Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54
Diffstat (limited to 'libSBRdec/src/sbr_dec.cpp')
-rw-r--r-- | libSBRdec/src/sbr_dec.cpp | 1046 |
1 files changed, 1046 insertions, 0 deletions
diff --git a/libSBRdec/src/sbr_dec.cpp b/libSBRdec/src/sbr_dec.cpp new file mode 100644 index 0000000..208120c --- /dev/null +++ b/libSBRdec/src/sbr_dec.cpp @@ -0,0 +1,1046 @@ + +/* ----------------------------------------------------------------------------------------------------------- +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 Sbr decoder + This module provides the actual decoder implementation. The SBR data (side information) is already + decoded. Only three functions are provided: + + \li 1.) createSbrDec(): One time initialization + \li 2.) resetSbrDec(): Called by sbr_Apply() when the information contained in an SBR_HEADER_ELEMENT requires a reset + and recalculation of important SBR structures. + \li 3.) sbr_dec(): The actual decoder. Calls the different tools such as filterbanks, lppTransposer(), and calculateSbrEnvelope() + [the envelope adjuster]. + + \sa sbr_dec(), \ref documentationOverview +*/ + +#include "sbr_dec.h" + +#include "sbr_ram.h" +#include "env_extr.h" +#include "env_calc.h" +#include "scale.h" + +#include "genericStds.h" + +#include "sbrdec_drc.h" + + + +static void assignLcTimeSlots( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + FIXP_DBL **QmfBufferReal, + int noCols ) +{ + int slot, i; + FIXP_DBL *ptr; + + /* Number of QMF timeslots in the overlap buffer: */ + ptr = hSbrDec->pSbrOverlapBuffer; + for(slot=0; slot<hSbrDec->LppTrans.pSettings->overlap; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + } + + /* Assign timeslots to Workbuffer1 */ + ptr = hSbrDec->WorkBuffer1; + for(i=0; i<noCols; i++) { + QmfBufferReal[slot] = ptr; ptr += (64); + slot++; + } +} + + +static void assignHqTimeSlots( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + FIXP_DBL **QmfBufferReal, + FIXP_DBL **QmfBufferImag, + int noCols ) +{ + FIXP_DBL *ptr; + int slot; + + /* Number of QMF timeslots in one half of a frame (size of Workbuffer1 or 2): */ + int halflen = (noCols >> 1) + hSbrDec->LppTrans.pSettings->overlap; + int totCols = noCols + hSbrDec->LppTrans.pSettings->overlap; + + /* Number of QMF timeslots in the overlap buffer: */ + ptr = hSbrDec->pSbrOverlapBuffer; + for(slot=0; slot<hSbrDec->LppTrans.pSettings->overlap; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + QmfBufferImag[slot] = ptr; ptr += (64); + } + + /* Assign first half of timeslots to Workbuffer1 */ + ptr = hSbrDec->WorkBuffer1; + for(; slot<halflen; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + QmfBufferImag[slot] = ptr; ptr += (64); + } + + /* Assign second half of timeslots to Workbuffer2 */ + ptr = hSbrDec->WorkBuffer2; + for(; slot<totCols; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + QmfBufferImag[slot] = ptr; ptr += (64); + } +} + + +static void assignTimeSlots( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + int noCols, + int useLP ) +{ + /* assign qmf time slots */ + hSbrDec->useLP = useLP; + if (useLP) { + hSbrDec->SynthesisQMF.flags |= QMF_FLAG_LP; + hSbrDec->AnalysiscQMF.flags |= QMF_FLAG_LP; + } else { + hSbrDec->SynthesisQMF.flags &= ~QMF_FLAG_LP; + hSbrDec->AnalysiscQMF.flags &= ~QMF_FLAG_LP; + } + if (!useLP) + assignHqTimeSlots( hSbrDec, hSbrDec->QmfBufferReal, hSbrDec->QmfBufferImag, noCols ); + else + { + assignLcTimeSlots( hSbrDec, hSbrDec->QmfBufferReal, noCols ); + } +} + +static void changeQmfType( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + int useLdTimeAlign ) +{ + UINT synQmfFlags = hSbrDec->SynthesisQMF.flags; + UINT anaQmfFlags = hSbrDec->AnalysiscQMF.flags; + int resetSynQmf = 0; + int resetAnaQmf = 0; + + /* assign qmf type */ + if (useLdTimeAlign) { + if (synQmfFlags & QMF_FLAG_CLDFB) { + /* change the type to MPSLD */ + synQmfFlags &= ~QMF_FLAG_CLDFB; + synQmfFlags |= QMF_FLAG_MPSLDFB; + resetSynQmf = 1; + } + if (anaQmfFlags & QMF_FLAG_CLDFB) { + /* change the type to MPSLD */ + anaQmfFlags &= ~QMF_FLAG_CLDFB; + anaQmfFlags |= QMF_FLAG_MPSLDFB; + resetAnaQmf = 1; + } + } else { + if (synQmfFlags & QMF_FLAG_MPSLDFB) { + /* change the type to CLDFB */ + synQmfFlags &= ~QMF_FLAG_MPSLDFB; + synQmfFlags |= QMF_FLAG_CLDFB; + resetSynQmf = 1; + } + if (anaQmfFlags & QMF_FLAG_MPSLDFB) { + /* change the type to CLDFB */ + anaQmfFlags &= ~QMF_FLAG_MPSLDFB; + anaQmfFlags |= QMF_FLAG_CLDFB; + resetAnaQmf = 1; + } + } + + if (resetAnaQmf) { + int qmfErr = qmfInitAnalysisFilterBank ( + &hSbrDec->AnalysiscQMF, + hSbrDec->anaQmfStates, + hSbrDec->AnalysiscQMF.no_col, + hSbrDec->AnalysiscQMF.lsb, + hSbrDec->AnalysiscQMF.usb, + hSbrDec->AnalysiscQMF.no_channels, + anaQmfFlags | QMF_FLAG_KEEP_STATES + ); + if (qmfErr != 0) { + FDK_ASSERT(0); + } + } + + if (resetSynQmf) { + int qmfErr = qmfInitSynthesisFilterBank ( + &hSbrDec->SynthesisQMF, + hSbrDec->pSynQmfStates, + hSbrDec->SynthesisQMF.no_col, + hSbrDec->SynthesisQMF.lsb, + hSbrDec->SynthesisQMF.usb, + hSbrDec->SynthesisQMF.no_channels, + synQmfFlags | QMF_FLAG_KEEP_STATES + ); + + if (qmfErr != 0) { + FDK_ASSERT(0); + } + } +} + + +/*! + \brief SBR decoder core function for one channel + + \image html BufferMgmtDetailed-1632.png + + Besides the filter states of the QMF filter bank and the LPC-states of + the LPP-Transposer, processing is mainly based on four buffers: + #timeIn, #timeOut, #WorkBuffer2 and #OverlapBuffer. The #WorkBuffer2 + is reused for all channels and might be used by the core decoder, a + static overlap buffer is required for each channel. Du to in-place + processing, #timeIn and #timeOut point to identical locations. + + The spectral data is organized in so-called slots, each slot + containing 64 bands of complex data. The number of slots per frame is + dependend on the frame size. For mp3PRO, there are 18 slots per frame + and 6 slots per #OverlapBuffer. It is not necessary to have the slots + in located consecutive address ranges. + + To optimize memory usage and to minimize the number of memory + accesses, the memory management is organized as follows (Slot numbers + based on mp3PRO): + + 1.) Input time domain signal is located in #timeIn, the last slots + (0..5) of the spectral data of the previous frame are located in the + #OverlapBuffer. In addition, #frameData of the current frame resides + in the upper part of #timeIn. + + 2.) During the cplxAnalysisQmfFiltering(), 32 samples from #timeIn are transformed + into a slot of up to 32 complex spectral low band values at a + time. The first spectral slot -- nr. 6 -- is written at slot number + zero of #WorkBuffer2. #WorkBuffer2 will be completely filled with + spectral data. + + 3.) LPP-Transposition in lppTransposer() is processed on 24 slots. During the + transposition, the high band part of the spectral data is replicated + based on the low band data. + + Envelope Adjustment is processed on the high band part of the spectral + data only by calculateSbrEnvelope(). + + 4.) The cplxSynthesisQmfFiltering() creates 64 time domain samples out + of a slot of 64 complex spectral values at a time. The first 6 slots + in #timeOut are filled from the results of spectral slots 0..5 in the + #OverlapBuffer. The consecutive slots in timeOut are now filled with + the results of spectral slots 6..17. + + 5.) The preprocessed slots 18..23 have to be stored in the + #OverlapBuffer. + +*/ + +void +sbr_dec ( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + INT_PCM *timeIn, /*!< pointer to input time signal */ + INT_PCM *timeOut, /*!< pointer to output time signal */ + HANDLE_SBR_DEC hSbrDecRight, /*!< handle to Decoder channel right */ + INT_PCM *timeOutRight, /*!< pointer to output time signal */ + const int strideIn, /*!< Time data traversal strideIn */ + const int strideOut, /*!< Time data traversal strideOut */ + HANDLE_SBR_HEADER_DATA hHeaderData,/*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */ + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, /*!< Some control data of last frame */ + const int applyProcessing, /*!< Flag for SBR operation */ + HANDLE_PS_DEC h_ps_d, + const UINT flags + ) +{ + int i, slot, reserve; + int saveLbScale; + int ov_len; + int lastSlotOffs; + FIXP_DBL maxVal; + + /* 1+1/3 frames of spectral data: */ + FIXP_DBL **QmfBufferReal = hSbrDec->QmfBufferReal; + FIXP_DBL **QmfBufferImag = hSbrDec->QmfBufferImag; + + /* Number of QMF timeslots in the overlap buffer: */ + ov_len = hSbrDec->LppTrans.pSettings->overlap; + + /* Number of QMF slots per frame */ + int noCols = hHeaderData->numberTimeSlots * hHeaderData->timeStep; + + /* assign qmf time slots */ + if ( ((flags & SBRDEC_LOW_POWER ) ? 1 : 0) != ((hSbrDec->SynthesisQMF.flags & QMF_FLAG_LP) ? 1 : 0) ) { + assignTimeSlots( hSbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, flags & SBRDEC_LOW_POWER); + } + + if (flags & SBRDEC_ELD_GRID) { + /* Choose the right low delay filter bank */ + changeQmfType( hSbrDec, (flags & SBRDEC_LD_MPS_QMF) ? 1 : 0 ); + } + + /* + low band codec signal subband filtering + */ + + { + C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2*(64)); + + qmfAnalysisFiltering( &hSbrDec->AnalysiscQMF, + QmfBufferReal + ov_len, + QmfBufferImag + ov_len, + &hSbrDec->sbrScaleFactor, + timeIn, + strideIn, + qmfTemp + ); + + C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2*(64)); + } + + /* + Clear upper half of spectrum + */ + { + int nAnalysisBands = hHeaderData->numberOfAnalysisBands; + + if (! (flags & SBRDEC_LOW_POWER)) { + for (slot = ov_len; slot < noCols+ov_len; slot++) { + FDKmemclear(&QmfBufferReal[slot][nAnalysisBands],((64)-nAnalysisBands)*sizeof(FIXP_DBL)); + FDKmemclear(&QmfBufferImag[slot][nAnalysisBands],((64)-nAnalysisBands)*sizeof(FIXP_DBL)); + } + } else + for (slot = ov_len; slot < noCols+ov_len; slot++) { + FDKmemclear(&QmfBufferReal[slot][nAnalysisBands],((64)-nAnalysisBands)*sizeof(FIXP_DBL)); + } + } + + + + /* + Shift spectral data left to gain accuracy in transposer and adjustor + */ + maxVal = maxSubbandSample( QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + 0, + hSbrDec->AnalysiscQMF.lsb, + ov_len, + noCols+ov_len ); + + reserve = fixMax(0,CntLeadingZeros(maxVal)-1) ; + reserve = fixMin(reserve,DFRACT_BITS-1-hSbrDec->sbrScaleFactor.lb_scale); + + /* If all data is zero, lb_scale could become too large */ + rescaleSubbandSamples( QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + 0, + hSbrDec->AnalysiscQMF.lsb, + ov_len, + noCols+ov_len, + reserve); + + hSbrDec->sbrScaleFactor.lb_scale += reserve; + + /* + save low band scale, wavecoding or parametric stereo may modify it + */ + saveLbScale = hSbrDec->sbrScaleFactor.lb_scale; + + + if (applyProcessing) + { + UCHAR * borders = hFrameData->frameInfo.borders; + lastSlotOffs = borders[hFrameData->frameInfo.nEnvelopes] - hHeaderData->numberTimeSlots; + + FIXP_DBL degreeAlias[(64)]; + + /* The transposer will override most values in degreeAlias[]. + The array needs to be cleared at least from lowSubband to highSubband before. */ + if (flags & SBRDEC_LOW_POWER) + FDKmemclear(°reeAlias[hHeaderData->freqBandData.lowSubband], (hHeaderData->freqBandData.highSubband-hHeaderData->freqBandData.lowSubband)*sizeof(FIXP_DBL)); + + /* + Inverse filtering of lowband and transposition into the SBR-frequency range + */ + + lppTransposer ( &hSbrDec->LppTrans, + &hSbrDec->sbrScaleFactor, + QmfBufferReal, + degreeAlias, // only used if useLP = 1 + QmfBufferImag, + flags & SBRDEC_LOW_POWER, + hHeaderData->timeStep, + borders[0], + lastSlotOffs, + hHeaderData->freqBandData.nInvfBands, + hFrameData->sbr_invf_mode, + hPrevFrameData->sbr_invf_mode ); + + + + + + /* + Adjust envelope of current frame. + */ + + calculateSbrEnvelope (&hSbrDec->sbrScaleFactor, + &hSbrDec->SbrCalculateEnvelope, + hHeaderData, + hFrameData, + QmfBufferReal, + QmfBufferImag, + flags & SBRDEC_LOW_POWER, + + degreeAlias, + flags, + (hHeaderData->frameErrorFlag || hPrevFrameData->frameErrorFlag)); + + + /* + Update hPrevFrameData (to be used in the next frame) + */ + for (i=0; i<hHeaderData->freqBandData.nInvfBands; i++) { + hPrevFrameData->sbr_invf_mode[i] = hFrameData->sbr_invf_mode[i]; + } + hPrevFrameData->coupling = hFrameData->coupling; + hPrevFrameData->stopPos = borders[hFrameData->frameInfo.nEnvelopes]; + hPrevFrameData->ampRes = hFrameData->ampResolutionCurrentFrame; + } + else { + /* Reset hb_scale if no highband is present, because hb_scale is considered in the QMF-synthesis */ + hSbrDec->sbrScaleFactor.hb_scale = saveLbScale; + } + + + for (i=0; i<LPC_ORDER; i++){ + /* + Store the unmodified qmf Slots values (required for LPC filtering) + */ + if (! (flags & SBRDEC_LOW_POWER)) { + FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesReal[i], QmfBufferReal[noCols-LPC_ORDER+i], hSbrDec->AnalysiscQMF.lsb*sizeof(FIXP_DBL)); + FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesImag[i], QmfBufferImag[noCols-LPC_ORDER+i], hSbrDec->AnalysiscQMF.lsb*sizeof(FIXP_DBL)); + } else + FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesReal[i], QmfBufferReal[noCols-LPC_ORDER+i], hSbrDec->AnalysiscQMF.lsb*sizeof(FIXP_DBL)); + } + + /* + Synthesis subband filtering. + */ + + if ( ! (flags & SBRDEC_PS_DECODED) ) { + + { + int outScalefactor = 0; + + if (h_ps_d != NULL) { + h_ps_d->procFrameBased = 1; /* we here do frame based processing */ + } + + + sbrDecoder_drcApply(&hSbrDec->sbrDrcChannel, + QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + hSbrDec->SynthesisQMF.no_col, + &outScalefactor + ); + + + + qmfChangeOutScalefactor(&hSbrDec->SynthesisQMF, outScalefactor ); + + { + C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2*(64)); + + qmfSynthesisFiltering( &hSbrDec->SynthesisQMF, + QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + &hSbrDec->sbrScaleFactor, + hSbrDec->LppTrans.pSettings->overlap, + timeOut, + strideOut, + qmfTemp); + + C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2*(64)); + } + + } + + } else { /* (flags & SBRDEC_PS_DECODED) */ + INT i, sdiff, outScalefactor, scaleFactorLowBand, scaleFactorHighBand; + SCHAR scaleFactorLowBand_ov, scaleFactorLowBand_no_ov; + + HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->SynthesisQMF; + HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->SynthesisQMF; + + /* adapt scaling */ + sdiff = hSbrDec->sbrScaleFactor.lb_scale - reserve; /* Scaling difference */ + scaleFactorHighBand = sdiff - hSbrDec->sbrScaleFactor.hb_scale; /* Scale of current high band */ + scaleFactorLowBand_ov = sdiff - hSbrDec->sbrScaleFactor.ov_lb_scale; /* Scale of low band overlapping QMF data */ + scaleFactorLowBand_no_ov = sdiff - hSbrDec->sbrScaleFactor.lb_scale; /* Scale of low band current QMF data */ + outScalefactor = 0; /* Initial output scale */ + + if (h_ps_d->procFrameBased == 1) /* If we have switched from frame to slot based processing copy filter states */ + { /* procFrameBased will be unset later */ + /* copy filter states from left to right */ + FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates, ((640)-(64))*sizeof(FIXP_QSS)); + } + + /* scale ALL qmf vales ( real and imag ) of mono / left channel to the + same scale factor ( ov_lb_sf, lb_sf and hq_sf ) */ + scalFilterBankValues( h_ps_d, /* parametric stereo decoder handle */ + QmfBufferReal, /* qmf filterbank values */ + QmfBufferImag, /* qmf filterbank values */ + synQmf->lsb, /* sbr start subband */ + hSbrDec->sbrScaleFactor.ov_lb_scale, + hSbrDec->sbrScaleFactor.lb_scale, + &scaleFactorLowBand_ov, /* adapt scaling values */ + &scaleFactorLowBand_no_ov, /* adapt scaling values */ + hSbrDec->sbrScaleFactor.hb_scale, /* current frame ( highband ) */ + &scaleFactorHighBand, + synQmf->no_col); + + /* use the same synthese qmf values for left and right channel */ + synQmfRight->no_col = synQmf->no_col; + synQmfRight->lsb = synQmf->lsb; + synQmfRight->usb = synQmf->usb; + + int env=0; + + outScalefactor += (SCAL_HEADROOM+1); /* psDiffScale! */ + + { + C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 2*(64)); + + int maxShift = 0; + + if (hSbrDec->sbrDrcChannel.prevFact_exp > maxShift) { + maxShift = hSbrDec->sbrDrcChannel.prevFact_exp; + } + if (hSbrDec->sbrDrcChannel.currFact_exp > maxShift) { + maxShift = hSbrDec->sbrDrcChannel.currFact_exp; + } + if (hSbrDec->sbrDrcChannel.nextFact_exp > maxShift) { + maxShift = hSbrDec->sbrDrcChannel.nextFact_exp; + } + + /* copy DRC data to right channel (with PS both channels use the same DRC gains) */ + FDKmemcpy(&hSbrDecRight->sbrDrcChannel, &hSbrDec->sbrDrcChannel, sizeof(SBRDEC_DRC_CHANNEL)); + + for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */ + + INT outScalefactorR, outScalefactorL; + outScalefactorR = outScalefactorL = outScalefactor; + + /* qmf timeslot of right channel */ + FIXP_DBL* rQmfReal = pWorkBuffer; + FIXP_DBL* rQmfImag = pWorkBuffer + 64; + + + { + if ( i == h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env] ) { + initSlotBasedRotation( h_ps_d, env, hHeaderData->freqBandData.highSubband ); + env++; + } + + ApplyPsSlot( h_ps_d, /* parametric stereo decoder handle */ + (QmfBufferReal + i), /* one timeslot of left/mono channel */ + (QmfBufferImag + i), /* one timeslot of left/mono channel */ + rQmfReal, /* one timeslot or right channel */ + rQmfImag); /* one timeslot or right channel */ + } + + + scaleFactorLowBand = (i<(6)) ? scaleFactorLowBand_ov : scaleFactorLowBand_no_ov; + + + sbrDecoder_drcApplySlot ( /* right channel */ + &hSbrDecRight->sbrDrcChannel, + rQmfReal, + rQmfImag, + i, + synQmfRight->no_col, + maxShift + ); + + outScalefactorR += maxShift; + + sbrDecoder_drcApplySlot ( /* left channel */ + &hSbrDec->sbrDrcChannel, + *(QmfBufferReal + i), + *(QmfBufferImag + i), + i, + synQmf->no_col, + maxShift + ); + + outScalefactorL += maxShift; + + + /* scale filter states for left and right channel */ + qmfChangeOutScalefactor( synQmf, outScalefactorL ); + qmfChangeOutScalefactor( synQmfRight, outScalefactorR ); + + { + + qmfSynthesisFilteringSlot( synQmfRight, + rQmfReal, /* QMF real buffer */ + rQmfImag, /* QMF imag buffer */ + scaleFactorLowBand, + scaleFactorHighBand, + timeOutRight+(i*synQmf->no_channels*strideOut), + strideOut, + pWorkBuffer); + + qmfSynthesisFilteringSlot( synQmf, + *(QmfBufferReal + i), /* QMF real buffer */ + *(QmfBufferImag + i), /* QMF imag buffer */ + scaleFactorLowBand, + scaleFactorHighBand, + timeOut+(i*synQmf->no_channels*strideOut), + strideOut, + pWorkBuffer); + + } + } /* no_col loop i */ + + /* scale back (6) timeslots look ahead for hybrid filterbank to original value */ + rescalFilterBankValues( h_ps_d, + QmfBufferReal, + QmfBufferImag, + synQmf->lsb, + synQmf->no_col ); + + C_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2*(64)); + } + } + + sbrDecoder_drcUpdateChannel( &hSbrDec->sbrDrcChannel ); + + + /* + Update overlap buffer + Even bands above usb are copied to avoid outdated spectral data in case + the stop frequency raises. + */ + + if (hSbrDec->LppTrans.pSettings->overlap > 0) + { + if (! (flags & SBRDEC_LOW_POWER)) { + for ( i=0; i<hSbrDec->LppTrans.pSettings->overlap; i++ ) { + FDKmemcpy(QmfBufferReal[i], QmfBufferReal[i+noCols], (64)*sizeof(FIXP_DBL)); + FDKmemcpy(QmfBufferImag[i], QmfBufferImag[i+noCols], (64)*sizeof(FIXP_DBL)); + } + } else + for ( i=0; i<hSbrDec->LppTrans.pSettings->overlap; i++ ) { + FDKmemcpy(QmfBufferReal[i], QmfBufferReal[i+noCols], (64)*sizeof(FIXP_DBL)); + } + } + + hSbrDec->sbrScaleFactor.ov_lb_scale = saveLbScale; + + /* Save current frame status */ + hPrevFrameData->frameErrorFlag = hHeaderData->frameErrorFlag; + +} // sbr_dec() + + +/*! + \brief Creates sbr decoder structure + \return errorCode, 0 if successful +*/ +SBR_ERROR +createSbrDec (SBR_CHANNEL * hSbrChannel, + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + TRANSPOSER_SETTINGS *pSettings, + const int downsampleFac, /*!< Downsampling factor */ + const UINT qmfFlags, /*!< flags -> 1: HQ/LP selector, 2: CLDFB */ + const UINT flags, + const int overlap, + int chan) /*!< Channel for which to assign buffers etc. */ + +{ + SBR_ERROR err = SBRDEC_OK; + int timeSlots = hHeaderData->numberTimeSlots; /* Number of SBR slots per frame */ + int noCols = timeSlots * hHeaderData->timeStep; /* Number of QMF slots per frame */ + HANDLE_SBR_DEC hs = &(hSbrChannel->SbrDec); + + /* Initialize scale factors */ + hs->sbrScaleFactor.ov_lb_scale = 0; + hs->sbrScaleFactor.ov_hb_scale = 0; + hs->sbrScaleFactor.hb_scale = 0; + + + /* + create envelope calculator + */ + err = createSbrEnvelopeCalc (&hs->SbrCalculateEnvelope, + hHeaderData, + chan, + flags); + if (err != SBRDEC_OK) { + return err; + } + + /* + create QMF filter banks + */ + { + int qmfErr; + + qmfErr = qmfInitAnalysisFilterBank ( + &hs->AnalysiscQMF, + hs->anaQmfStates, + noCols, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.highSubband, + hHeaderData->numberOfAnalysisBands, + qmfFlags & (~QMF_FLAG_KEEP_STATES) + ); + if (qmfErr != 0) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + } + if (hs->pSynQmfStates == NULL) { + hs->pSynQmfStates = GetRam_sbr_QmfStatesSynthesis(chan); + if (hs->pSynQmfStates == NULL) + return SBRDEC_MEM_ALLOC_FAILED; + } + + { + int qmfErr; + + qmfErr = qmfInitSynthesisFilterBank ( + &hs->SynthesisQMF, + hs->pSynQmfStates, + noCols, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.highSubband, + (64) / downsampleFac, + qmfFlags & (~QMF_FLAG_KEEP_STATES) + ); + + if (qmfErr != 0) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + } + initSbrPrevFrameData (&hSbrChannel->prevFrameData, timeSlots); + + /* + create transposer + */ + err = createLppTransposer (&hs->LppTrans, + pSettings, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.v_k_master, + hHeaderData->freqBandData.numMaster, + hs->SynthesisQMF.usb, + timeSlots, + hs->AnalysiscQMF.no_col, + hHeaderData->freqBandData.freqBandTableNoise, + hHeaderData->freqBandData.nNfb, + hHeaderData->sbrProcSmplRate, + chan, + overlap ); + if (err != SBRDEC_OK) { + return err; + } + + /* The CLDFB does not have overlap */ + if ((qmfFlags & QMF_FLAG_CLDFB) == 0) { + if (hs->pSbrOverlapBuffer == NULL) { + hs->pSbrOverlapBuffer = GetRam_sbr_OverlapBuffer(chan); + if (hs->pSbrOverlapBuffer == NULL) { + return SBRDEC_MEM_ALLOC_FAILED; + } + } else { + /* Clear overlap buffer */ + FDKmemclear( hs->pSbrOverlapBuffer, + sizeof(FIXP_DBL) * 2 * (6) * (64) + ); + } + } + + /* assign qmf time slots */ + assignTimeSlots( &hSbrChannel->SbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, qmfFlags & QMF_FLAG_LP); + + return err; +} + +/*! + \brief Delete sbr decoder structure + \return errorCode, 0 if successful +*/ +int +deleteSbrDec (SBR_CHANNEL * hSbrChannel) +{ + HANDLE_SBR_DEC hs = &hSbrChannel->SbrDec; + + deleteSbrEnvelopeCalc (&hs->SbrCalculateEnvelope); + + /* delete QMF filter states */ + if (hs->pSynQmfStates != NULL) { + FreeRam_sbr_QmfStatesSynthesis(&hs->pSynQmfStates); + } + + + if (hs->pSbrOverlapBuffer != NULL) { + FreeRam_sbr_OverlapBuffer(&hs->pSbrOverlapBuffer); + } + + return 0; +} + + +/*! + \brief resets sbr decoder structure + \return errorCode, 0 if successful +*/ +SBR_ERROR +resetSbrDec (HANDLE_SBR_DEC hSbrDec, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, + const int useLP, + const int downsampleFac + ) +{ + SBR_ERROR sbrError = SBRDEC_OK; + + int old_lsb = hSbrDec->SynthesisQMF.lsb; + int new_lsb = hHeaderData->freqBandData.lowSubband; + int l, startBand, stopBand, startSlot, size; + + int source_scale, target_scale, delta_scale, target_lsb, target_usb, reserve; + FIXP_DBL maxVal; + + /* overlapBuffer point to first (6) slots */ + FIXP_DBL **OverlapBufferReal = hSbrDec->QmfBufferReal; + FIXP_DBL **OverlapBufferImag = hSbrDec->QmfBufferImag; + + /* assign qmf time slots */ + assignTimeSlots( hSbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, useLP); + + + + resetSbrEnvelopeCalc (&hSbrDec->SbrCalculateEnvelope); + + hSbrDec->SynthesisQMF.lsb = hHeaderData->freqBandData.lowSubband; + hSbrDec->SynthesisQMF.usb = fixMin((INT)hSbrDec->SynthesisQMF.no_channels, (INT)hHeaderData->freqBandData.highSubband); + + hSbrDec->AnalysiscQMF.lsb = hSbrDec->SynthesisQMF.lsb; + hSbrDec->AnalysiscQMF.usb = hSbrDec->SynthesisQMF.usb; + + + /* + The following initialization of spectral data in the overlap buffer + is required for dynamic x-over or a change of the start-freq for 2 reasons: + + 1. If the lowband gets _wider_, unadjusted data would remain + + 2. If the lowband becomes _smaller_, the highest bands of the old lowband + must be cleared because the whitening would be affected + */ + startBand = old_lsb; + stopBand = new_lsb; + startSlot = hHeaderData->timeStep * (hPrevFrameData->stopPos - hHeaderData->numberTimeSlots); + size = fixMax(0,stopBand-startBand); + + /* keep already adjusted data in the x-over-area */ + if (!useLP) { + for (l=startSlot; l<hSbrDec->LppTrans.pSettings->overlap; l++) { + FDKmemclear(&OverlapBufferReal[l][startBand], size*sizeof(FIXP_DBL)); + FDKmemclear(&OverlapBufferImag[l][startBand], size*sizeof(FIXP_DBL)); + } + } else + for (l=startSlot; l<hSbrDec->LppTrans.pSettings->overlap ; l++) { + FDKmemclear(&OverlapBufferReal[l][startBand], size*sizeof(FIXP_DBL)); + } + + + /* + reset LPC filter states + */ + startBand = fixMin(old_lsb,new_lsb); + stopBand = fixMax(old_lsb,new_lsb); + size = fixMax(0,stopBand-startBand); + + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesReal[0][startBand], size*sizeof(FIXP_DBL)); + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesReal[1][startBand], size*sizeof(FIXP_DBL)); + if (!useLP) { + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImag[0][startBand], size*sizeof(FIXP_DBL)); + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImag[1][startBand], size*sizeof(FIXP_DBL)); + } + + + /* + Rescale already processed spectral data between old and new x-over frequency. + This must be done because of the separate scalefactors for lowband and highband. + */ + startBand = fixMin(old_lsb,new_lsb); + stopBand = fixMax(old_lsb,new_lsb); + + if (new_lsb > old_lsb) { + /* The x-over-area was part of the highband before and will now belong to the lowband */ + source_scale = hSbrDec->sbrScaleFactor.ov_hb_scale; + target_scale = hSbrDec->sbrScaleFactor.ov_lb_scale; + target_lsb = 0; + target_usb = old_lsb; + } + else { + /* The x-over-area was part of the lowband before and will now belong to the highband */ + source_scale = hSbrDec->sbrScaleFactor.ov_lb_scale; + target_scale = hSbrDec->sbrScaleFactor.ov_hb_scale; + /* jdr: The values old_lsb and old_usb might be wrong because the previous frame might have been "upsamling". */ + target_lsb = hSbrDec->SynthesisQMF.lsb; + target_usb = hSbrDec->SynthesisQMF.usb; + } + + /* Shift left all samples of the x-over-area as much as possible + An unnecessary coarse scale could cause ov_lb_scale or ov_hb_scale to be + adapted and the accuracy in the next frame would seriously suffer! */ + + maxVal = maxSubbandSample( OverlapBufferReal, + (useLP) ? NULL : OverlapBufferImag, + startBand, + stopBand, + 0, + startSlot); + + reserve = CntLeadingZeros(maxVal)-1; + reserve = fixMin(reserve,DFRACT_BITS-1-source_scale); + + rescaleSubbandSamples( OverlapBufferReal, + (useLP) ? NULL : OverlapBufferImag, + startBand, + stopBand, + 0, + startSlot, + reserve); + source_scale += reserve; + + delta_scale = target_scale - source_scale; + + if (delta_scale > 0) { /* x-over-area is dominant */ + delta_scale = -delta_scale; + startBand = target_lsb; + stopBand = target_usb; + + if (new_lsb > old_lsb) { + /* The lowband has to be rescaled */ + hSbrDec->sbrScaleFactor.ov_lb_scale = source_scale; + } + else { + /* The highband has be be rescaled */ + hSbrDec->sbrScaleFactor.ov_hb_scale = source_scale; + } + } + + FDK_ASSERT(startBand <= stopBand); + + if (!useLP) { + for (l=0; l<startSlot; l++) { + scaleValues( OverlapBufferReal[l] + startBand, stopBand-startBand, delta_scale ); + scaleValues( OverlapBufferImag[l] + startBand, stopBand-startBand, delta_scale ); + } + } else + for (l=0; l<startSlot; l++) { + scaleValues( OverlapBufferReal[l] + startBand, stopBand-startBand, delta_scale ); + } + + + /* + Initialize transposer and limiter + */ + sbrError = resetLppTransposer (&hSbrDec->LppTrans, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.v_k_master, + hHeaderData->freqBandData.numMaster, + hHeaderData->freqBandData.freqBandTableNoise, + hHeaderData->freqBandData.nNfb, + hHeaderData->freqBandData.highSubband, + hHeaderData->sbrProcSmplRate); + if (sbrError != SBRDEC_OK) + return sbrError; + + sbrError = ResetLimiterBands ( hHeaderData->freqBandData.limiterBandTable, + &hHeaderData->freqBandData.noLimiterBands, + hHeaderData->freqBandData.freqBandTable[0], + hHeaderData->freqBandData.nSfb[0], + hSbrDec->LppTrans.pSettings->patchParam, + hSbrDec->LppTrans.pSettings->noOfPatches, + hHeaderData->bs_data.limiterBands); + + + return sbrError; +} |