diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2020-03-31 10:03:58 +0200 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2020-03-31 10:03:58 +0200 |
commit | a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d (patch) | |
tree | 2b4790eec8f47fb086e645717f07c53b30ace919 /fdk-aac/libSBRenc/src | |
parent | 2f84a54ec1d10b10293c7b1f4ab9fee31f3c6327 (diff) | |
parent | c6a73c219dbfdfe639372d9922f4eb512f06fa2f (diff) | |
download | ODR-AudioEnc-a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d.tar.gz ODR-AudioEnc-a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d.tar.bz2 ODR-AudioEnc-a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d.zip |
Merge GStreamer into next
Diffstat (limited to 'fdk-aac/libSBRenc/src')
41 files changed, 22125 insertions, 0 deletions
diff --git a/fdk-aac/libSBRenc/src/bit_sbr.cpp b/fdk-aac/libSBRenc/src/bit_sbr.cpp new file mode 100644 index 0000000..5a65e98 --- /dev/null +++ b/fdk-aac/libSBRenc/src/bit_sbr.cpp @@ -0,0 +1,1049 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief SBR bit writing routines $Revision: 93300 $ +*/ + +#include "bit_sbr.h" + +#include "code_env.h" +#include "cmondata.h" +#include "sbr.h" + +#include "ps_main.h" + +typedef enum { SBR_ID_SCE = 1, SBR_ID_CPE } SBR_ELEMENT_TYPE; + +static INT encodeSbrData(HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_COMMON_DATA cmonData, SBR_ELEMENT_TYPE sbrElem, + INT coupling, UINT sbrSyntaxFlags); + +static INT encodeSbrHeader(HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_COMMON_DATA cmonData); + +static INT encodeSbrHeaderData(HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_FDK_BITSTREAM hBitStream); + +static INT encodeSbrSingleChannelElement( + HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream, + HANDLE_PARAMETRIC_STEREO hParametricStereo, const UINT sbrSyntaxFlags); + +static INT encodeSbrChannelPairElement( + HANDLE_SBR_ENV_DATA sbrEnvDataLeft, HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, HANDLE_FDK_BITSTREAM hBitStream, + const INT coupling, const UINT sbrSyntaxFlags); + +static INT encodeSbrGrid(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream); + +static int encodeLowDelaySbrGrid(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + const int transmitFreqs, + const UINT sbrSyntaxFlags); + +static INT encodeSbrDtdf(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream); + +static INT writeNoiseLevelData(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, INT coupling); + +static INT writeEnvelopeData(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, INT coupling); + +static INT writeSyntheticCodingData(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream); + +static INT encodeExtendedData(HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream); + +static INT getSbrExtendedDataSize(HANDLE_PARAMETRIC_STEREO hParametricStereo); + +/***************************************************************************** + + functionname: FDKsbrEnc_WriteEnvSingleChannelElement + description: writes pure SBR single channel data element + returns: number of bits written + input: + output: + +*****************************************************************************/ +INT FDKsbrEnc_WriteEnvSingleChannelElement( + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_COMMON_DATA cmonData, UINT sbrSyntaxFlags) + +{ + INT payloadBits = 0; + + cmonData->sbrHdrBits = 0; + cmonData->sbrDataBits = 0; + + /* write pure sbr data */ + if (sbrEnvData != NULL) { + /* write header */ + payloadBits += encodeSbrHeader(sbrHeaderData, sbrBitstreamData, cmonData); + + /* write data */ + payloadBits += encodeSbrData(sbrEnvData, NULL, hParametricStereo, cmonData, + SBR_ID_SCE, 0, sbrSyntaxFlags); + } + return payloadBits; +} + +/***************************************************************************** + + functionname: FDKsbrEnc_WriteEnvChannelPairElement + description: writes pure SBR channel pair data element + returns: number of bits written + input: + output: + +*****************************************************************************/ +INT FDKsbrEnc_WriteEnvChannelPairElement( + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_SBR_ENV_DATA sbrEnvDataLeft, HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_COMMON_DATA cmonData, UINT sbrSyntaxFlags) + +{ + INT payloadBits = 0; + cmonData->sbrHdrBits = 0; + cmonData->sbrDataBits = 0; + + /* write pure sbr data */ + if ((sbrEnvDataLeft != NULL) && (sbrEnvDataRight != NULL)) { + /* write header */ + payloadBits += encodeSbrHeader(sbrHeaderData, sbrBitstreamData, cmonData); + + /* write data */ + payloadBits += encodeSbrData(sbrEnvDataLeft, sbrEnvDataRight, + hParametricStereo, cmonData, SBR_ID_CPE, + sbrHeaderData->coupling, sbrSyntaxFlags); + } + return payloadBits; +} + +INT FDKsbrEnc_CountSbrChannelPairElement( + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_SBR_ENV_DATA sbrEnvDataLeft, HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_COMMON_DATA cmonData, UINT sbrSyntaxFlags) { + INT payloadBits; + INT bitPos = FDKgetValidBits(&cmonData->sbrBitbuf); + + payloadBits = FDKsbrEnc_WriteEnvChannelPairElement( + sbrHeaderData, hParametricStereo, sbrBitstreamData, sbrEnvDataLeft, + sbrEnvDataRight, cmonData, sbrSyntaxFlags); + + FDKpushBack(&cmonData->sbrBitbuf, + (FDKgetValidBits(&cmonData->sbrBitbuf) - bitPos)); + + return payloadBits; +} + +void sbrEncoder_GetHeader(SBR_ENCODER *sbrEncoder, HANDLE_FDK_BITSTREAM hBs, + INT element_index, int fSendHeaders) { + encodeSbrHeaderData(&sbrEncoder->sbrElement[element_index]->sbrHeaderData, + hBs); + + if (fSendHeaders == 0) { + /* Prevent header being embedded into the SBR payload. */ + sbrEncoder->sbrElement[element_index]->sbrBitstreamData.NrSendHeaderData = + -1; + sbrEncoder->sbrElement[element_index]->sbrBitstreamData.HeaderActive = 0; + sbrEncoder->sbrElement[element_index] + ->sbrBitstreamData.CountSendHeaderData = -1; + } +} + +/***************************************************************************** + + functionname: encodeSbrHeader + description: encodes SBR Header information + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT encodeSbrHeader(HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_COMMON_DATA cmonData) { + INT payloadBits = 0; + + if (sbrBitstreamData->HeaderActive) { + payloadBits += FDKwriteBits(&cmonData->sbrBitbuf, 1, 1); + payloadBits += encodeSbrHeaderData(sbrHeaderData, &cmonData->sbrBitbuf); + } else { + payloadBits += FDKwriteBits(&cmonData->sbrBitbuf, 0, 1); + } + + cmonData->sbrHdrBits = payloadBits; + + return payloadBits; +} + +/***************************************************************************** + + functionname: encodeSbrHeaderData + description: writes sbr_header() + bs_protocol_version through bs_header_extra_2 + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT encodeSbrHeaderData(HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_FDK_BITSTREAM hBitStream) + +{ + INT payloadBits = 0; + if (sbrHeaderData != NULL) { + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->sbr_amp_res, + SI_SBR_AMP_RES_BITS); + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->sbr_start_frequency, + SI_SBR_START_FREQ_BITS); + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->sbr_stop_frequency, + SI_SBR_STOP_FREQ_BITS); + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->sbr_xover_band, + SI_SBR_XOVER_BAND_BITS); + + payloadBits += FDKwriteBits(hBitStream, 0, SI_SBR_RESERVED_BITS); + + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->header_extra_1, + SI_SBR_HEADER_EXTRA_1_BITS); + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->header_extra_2, + SI_SBR_HEADER_EXTRA_2_BITS); + + if (sbrHeaderData->header_extra_1) { + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->freqScale, + SI_SBR_FREQ_SCALE_BITS); + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->alterScale, + SI_SBR_ALTER_SCALE_BITS); + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->sbr_noise_bands, + SI_SBR_NOISE_BANDS_BITS); + } /* sbrHeaderData->header_extra_1 */ + + if (sbrHeaderData->header_extra_2) { + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->sbr_limiter_bands, + SI_SBR_LIMITER_BANDS_BITS); + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->sbr_limiter_gains, + SI_SBR_LIMITER_GAINS_BITS); + payloadBits += FDKwriteBits(hBitStream, sbrHeaderData->sbr_interpol_freq, + SI_SBR_INTERPOL_FREQ_BITS); + payloadBits += + FDKwriteBits(hBitStream, sbrHeaderData->sbr_smoothing_length, + SI_SBR_SMOOTHING_LENGTH_BITS); + + } /* sbrHeaderData->header_extra_2 */ + } /* sbrHeaderData != NULL */ + + return payloadBits; +} + +/***************************************************************************** + + functionname: encodeSbrData + description: encodes sbr Data information + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT encodeSbrData(HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_COMMON_DATA cmonData, SBR_ELEMENT_TYPE sbrElem, + INT coupling, UINT sbrSyntaxFlags) { + INT payloadBits = 0; + + switch (sbrElem) { + case SBR_ID_SCE: + payloadBits += + encodeSbrSingleChannelElement(sbrEnvDataLeft, &cmonData->sbrBitbuf, + hParametricStereo, sbrSyntaxFlags); + break; + case SBR_ID_CPE: + payloadBits += encodeSbrChannelPairElement( + sbrEnvDataLeft, sbrEnvDataRight, hParametricStereo, + &cmonData->sbrBitbuf, coupling, sbrSyntaxFlags); + break; + default: + /* we never should apply SBR to any other element type */ + FDK_ASSERT(0); + } + + cmonData->sbrDataBits = payloadBits; + + return payloadBits; +} + +#define MODE_FREQ_TANS 1 +#define MODE_NO_FREQ_TRAN 0 +#define LD_TRANSMISSION MODE_FREQ_TANS +static int encodeFreqs(int mode) { return ((mode & MODE_FREQ_TANS) ? 1 : 0); } + +/***************************************************************************** + + functionname: encodeSbrSingleChannelElement + description: encodes sbr SCE information + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT encodeSbrSingleChannelElement( + HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream, + HANDLE_PARAMETRIC_STEREO hParametricStereo, const UINT sbrSyntaxFlags) { + INT i, payloadBits = 0; + + payloadBits += FDKwriteBits(hBitStream, 0, + SI_SBR_DATA_EXTRA_BITS); /* no reserved bits */ + + if (sbrEnvData->ldGrid) { + if (sbrEnvData->hSbrBSGrid->frameClass != FIXFIXonly) { + /* encode normal SbrGrid */ + payloadBits += encodeSbrGrid(sbrEnvData, hBitStream); + } else { + /* use FIXFIXonly frame Grid */ + payloadBits += encodeLowDelaySbrGrid( + sbrEnvData, hBitStream, encodeFreqs(LD_TRANSMISSION), sbrSyntaxFlags); + } + } else { + if (sbrSyntaxFlags & SBR_SYNTAX_SCALABLE) { + payloadBits += FDKwriteBits(hBitStream, 1, SI_SBR_COUPLING_BITS); + } + payloadBits += encodeSbrGrid(sbrEnvData, hBitStream); + } + + payloadBits += encodeSbrDtdf(sbrEnvData, hBitStream); + + for (i = 0; i < sbrEnvData->noOfnoisebands; i++) { + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->sbr_invf_mode_vec[i], + SI_SBR_INVF_MODE_BITS); + } + + payloadBits += writeEnvelopeData(sbrEnvData, hBitStream, 0); + payloadBits += writeNoiseLevelData(sbrEnvData, hBitStream, 0); + + payloadBits += writeSyntheticCodingData(sbrEnvData, hBitStream); + + payloadBits += encodeExtendedData(hParametricStereo, hBitStream); + + return payloadBits; +} + +/***************************************************************************** + + functionname: encodeSbrChannelPairElement + description: encodes sbr CPE information + returns: + input: + output: + +*****************************************************************************/ +static INT encodeSbrChannelPairElement( + HANDLE_SBR_ENV_DATA sbrEnvDataLeft, HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, HANDLE_FDK_BITSTREAM hBitStream, + const INT coupling, const UINT sbrSyntaxFlags) { + INT payloadBits = 0; + INT i = 0; + + payloadBits += FDKwriteBits(hBitStream, 0, + SI_SBR_DATA_EXTRA_BITS); /* no reserved bits */ + + payloadBits += FDKwriteBits(hBitStream, coupling, SI_SBR_COUPLING_BITS); + + if (coupling) { + if (sbrEnvDataLeft->ldGrid) { + if (sbrEnvDataLeft->hSbrBSGrid->frameClass != FIXFIXonly) { + /* normal SbrGrid */ + payloadBits += encodeSbrGrid(sbrEnvDataLeft, hBitStream); + + } else { + /* FIXFIXonly frame Grid */ + payloadBits += + encodeLowDelaySbrGrid(sbrEnvDataLeft, hBitStream, + encodeFreqs(LD_TRANSMISSION), sbrSyntaxFlags); + } + } else + payloadBits += encodeSbrGrid(sbrEnvDataLeft, hBitStream); + + payloadBits += encodeSbrDtdf(sbrEnvDataLeft, hBitStream); + payloadBits += encodeSbrDtdf(sbrEnvDataRight, hBitStream); + + for (i = 0; i < sbrEnvDataLeft->noOfnoisebands; i++) { + payloadBits += + FDKwriteBits(hBitStream, sbrEnvDataLeft->sbr_invf_mode_vec[i], + SI_SBR_INVF_MODE_BITS); + } + + payloadBits += writeEnvelopeData(sbrEnvDataLeft, hBitStream, 1); + payloadBits += writeNoiseLevelData(sbrEnvDataLeft, hBitStream, 1); + payloadBits += writeEnvelopeData(sbrEnvDataRight, hBitStream, 1); + payloadBits += writeNoiseLevelData(sbrEnvDataRight, hBitStream, 1); + + payloadBits += writeSyntheticCodingData(sbrEnvDataLeft, hBitStream); + payloadBits += writeSyntheticCodingData(sbrEnvDataRight, hBitStream); + + } else { /* no coupling */ + FDK_ASSERT(sbrEnvDataLeft->ldGrid == sbrEnvDataRight->ldGrid); + + if (sbrEnvDataLeft->ldGrid || sbrEnvDataRight->ldGrid) { + /* sbrEnvDataLeft (left channel) */ + if (sbrEnvDataLeft->hSbrBSGrid->frameClass != FIXFIXonly) { + /* no FIXFIXonly Frame so we dont need encodeLowDelaySbrGrid */ + /* normal SbrGrid */ + payloadBits += encodeSbrGrid(sbrEnvDataLeft, hBitStream); + + } else { + /* FIXFIXonly frame Grid */ + payloadBits += + encodeLowDelaySbrGrid(sbrEnvDataLeft, hBitStream, + encodeFreqs(LD_TRANSMISSION), sbrSyntaxFlags); + } + + /* sbrEnvDataRight (right channel) */ + if (sbrEnvDataRight->hSbrBSGrid->frameClass != FIXFIXonly) { + /* no FIXFIXonly Frame so we dont need encodeLowDelaySbrGrid */ + /* normal SbrGrid */ + payloadBits += encodeSbrGrid(sbrEnvDataRight, hBitStream); + + } else { + /* FIXFIXonly frame Grid */ + payloadBits += + encodeLowDelaySbrGrid(sbrEnvDataRight, hBitStream, + encodeFreqs(LD_TRANSMISSION), sbrSyntaxFlags); + } + } else { + payloadBits += encodeSbrGrid(sbrEnvDataLeft, hBitStream); + payloadBits += encodeSbrGrid(sbrEnvDataRight, hBitStream); + } + payloadBits += encodeSbrDtdf(sbrEnvDataLeft, hBitStream); + payloadBits += encodeSbrDtdf(sbrEnvDataRight, hBitStream); + + for (i = 0; i < sbrEnvDataLeft->noOfnoisebands; i++) { + payloadBits += + FDKwriteBits(hBitStream, sbrEnvDataLeft->sbr_invf_mode_vec[i], + SI_SBR_INVF_MODE_BITS); + } + for (i = 0; i < sbrEnvDataRight->noOfnoisebands; i++) { + payloadBits += + FDKwriteBits(hBitStream, sbrEnvDataRight->sbr_invf_mode_vec[i], + SI_SBR_INVF_MODE_BITS); + } + + payloadBits += writeEnvelopeData(sbrEnvDataLeft, hBitStream, 0); + payloadBits += writeEnvelopeData(sbrEnvDataRight, hBitStream, 0); + payloadBits += writeNoiseLevelData(sbrEnvDataLeft, hBitStream, 0); + payloadBits += writeNoiseLevelData(sbrEnvDataRight, hBitStream, 0); + + payloadBits += writeSyntheticCodingData(sbrEnvDataLeft, hBitStream); + payloadBits += writeSyntheticCodingData(sbrEnvDataRight, hBitStream); + + } /* coupling */ + + payloadBits += encodeExtendedData(hParametricStereo, hBitStream); + + return payloadBits; +} + +static INT ceil_ln2(INT x) { + INT tmp = -1; + while ((1 << ++tmp) < x) + ; + return (tmp); +} + +/***************************************************************************** + + functionname: encodeSbrGrid + description: if hBitStream != NULL writes bits that describes the + time/frequency grouping of a frame; else counts them only + returns: number of bits written or counted + input: + output: + +*****************************************************************************/ +static INT encodeSbrGrid(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream) { + INT payloadBits = 0; + INT i, temp; + INT bufferFrameStart = sbrEnvData->hSbrBSGrid->bufferFrameStart; + INT numberTimeSlots = sbrEnvData->hSbrBSGrid->numberTimeSlots; + + if (sbrEnvData->ldGrid) + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->frameClass, + SBR_CLA_BITS_LD); + else + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->frameClass, + SBR_CLA_BITS); + + switch (sbrEnvData->hSbrBSGrid->frameClass) { + case FIXFIXonly: + FDK_ASSERT(0 /* Fatal error in encodeSbrGrid! */); + break; + case FIXFIX: + temp = ceil_ln2(sbrEnvData->hSbrBSGrid->bs_num_env); + payloadBits += FDKwriteBits(hBitStream, temp, SBR_ENV_BITS); + if ((sbrEnvData->ldGrid) && (sbrEnvData->hSbrBSGrid->bs_num_env == 1)) + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->currentAmpResFF, + SI_SBR_AMP_RES_BITS); + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->v_f[0], + SBR_RES_BITS); + + break; + + case FIXVAR: + case VARFIX: + if (sbrEnvData->hSbrBSGrid->frameClass == FIXVAR) + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord - + (bufferFrameStart + numberTimeSlots); + else + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord - bufferFrameStart; + + payloadBits += FDKwriteBits(hBitStream, temp, SBR_ABS_BITS); + payloadBits += + FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->n, SBR_NUM_BITS); + + for (i = 0; i < sbrEnvData->hSbrBSGrid->n; i++) { + temp = (sbrEnvData->hSbrBSGrid->bs_rel_bord[i] - 2) >> 1; + payloadBits += FDKwriteBits(hBitStream, temp, SBR_REL_BITS); + } + + temp = ceil_ln2(sbrEnvData->hSbrBSGrid->n + 2); + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->p, temp); + + for (i = 0; i < sbrEnvData->hSbrBSGrid->n + 1; i++) { + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->v_f[i], + SBR_RES_BITS); + } + break; + + case VARVAR: + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord_0 - bufferFrameStart; + payloadBits += FDKwriteBits(hBitStream, temp, SBR_ABS_BITS); + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord_1 - + (bufferFrameStart + numberTimeSlots); + payloadBits += FDKwriteBits(hBitStream, temp, SBR_ABS_BITS); + + payloadBits += FDKwriteBits( + hBitStream, sbrEnvData->hSbrBSGrid->bs_num_rel_0, SBR_NUM_BITS); + payloadBits += FDKwriteBits( + hBitStream, sbrEnvData->hSbrBSGrid->bs_num_rel_1, SBR_NUM_BITS); + + for (i = 0; i < sbrEnvData->hSbrBSGrid->bs_num_rel_0; i++) { + temp = (sbrEnvData->hSbrBSGrid->bs_rel_bord_0[i] - 2) >> 1; + payloadBits += FDKwriteBits(hBitStream, temp, SBR_REL_BITS); + } + + for (i = 0; i < sbrEnvData->hSbrBSGrid->bs_num_rel_1; i++) { + temp = (sbrEnvData->hSbrBSGrid->bs_rel_bord_1[i] - 2) >> 1; + payloadBits += FDKwriteBits(hBitStream, temp, SBR_REL_BITS); + } + + temp = ceil_ln2(sbrEnvData->hSbrBSGrid->bs_num_rel_0 + + sbrEnvData->hSbrBSGrid->bs_num_rel_1 + 2); + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->p, temp); + + temp = sbrEnvData->hSbrBSGrid->bs_num_rel_0 + + sbrEnvData->hSbrBSGrid->bs_num_rel_1 + 1; + + for (i = 0; i < temp; i++) { + payloadBits += FDKwriteBits( + hBitStream, sbrEnvData->hSbrBSGrid->v_fLR[i], SBR_RES_BITS); + } + break; + } + + return payloadBits; +} + +#define SBR_CLA_BITS_LD 1 +/***************************************************************************** + + functionname: encodeLowDelaySbrGrid + description: if hBitStream != NULL writes bits that describes the + time/frequency grouping of a frame; + else counts them only + (this function only write the FIXFIXonly Bitstream data) + returns: number of bits written or counted + input: + output: + +*****************************************************************************/ +static int encodeLowDelaySbrGrid(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + const int transmitFreqs, + const UINT sbrSyntaxFlags) { + int payloadBits = 0; + int i; + + /* write FIXFIXonly Grid */ + /* write frameClass [1 bit] for FIXFIXonly Grid */ + payloadBits += FDKwriteBits(hBitStream, 1, SBR_CLA_BITS_LD); + + /* absolute Borders are fix: 0,X,X,X,nTimeSlots; so we dont have to transmit + * them */ + /* only transmit the transient position! */ + /* with this info (b1) we can reconstruct the Frame on Decoder side : */ + /* border[0] = 0; border[1] = b1; border[2]=b1+2; border[3] = nrTimeSlots */ + + /* use 3 or 4bits for transient border (border) */ + if (sbrEnvData->hSbrBSGrid->numberTimeSlots == 8) + payloadBits += + FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->bs_abs_bord, 3); + else + payloadBits += + FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->bs_abs_bord, 4); + + if (transmitFreqs) { + /* write FreqRes grid */ + for (i = 0; i < sbrEnvData->hSbrBSGrid->bs_num_env; i++) { + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->hSbrBSGrid->v_f[i], + SBR_RES_BITS); + } + } + + return payloadBits; +} + +/***************************************************************************** + + functionname: encodeSbrDtdf + description: writes bits that describes the direction of the envelopes of a +frame returns: number of bits written input: output: + +*****************************************************************************/ +static INT encodeSbrDtdf(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream) { + INT i, payloadBits = 0, noOfNoiseEnvelopes; + + noOfNoiseEnvelopes = sbrEnvData->noOfEnvelopes > 1 ? 2 : 1; + + for (i = 0; i < sbrEnvData->noOfEnvelopes; ++i) { + payloadBits += + FDKwriteBits(hBitStream, sbrEnvData->domain_vec[i], SBR_DIR_BITS); + } + for (i = 0; i < noOfNoiseEnvelopes; ++i) { + payloadBits += + FDKwriteBits(hBitStream, sbrEnvData->domain_vec_noise[i], SBR_DIR_BITS); + } + + return payloadBits; +} + +/***************************************************************************** + + functionname: writeNoiseLevelData + description: writes bits corresponding to the noise-floor-level + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT writeNoiseLevelData(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, INT coupling) { + INT j, i, payloadBits = 0; + INT nNoiseEnvelopes = sbrEnvData->noOfEnvelopes > 1 ? 2 : 1; + + for (i = 0; i < nNoiseEnvelopes; i++) { + switch (sbrEnvData->domain_vec_noise[i]) { + case FREQ: + if (coupling && sbrEnvData->balance) { + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData->sbr_noise_levels[i * sbrEnvData->noOfnoisebands], + sbrEnvData->si_sbr_start_noise_bits_balance); + } else { + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData->sbr_noise_levels[i * sbrEnvData->noOfnoisebands], + sbrEnvData->si_sbr_start_noise_bits); + } + + for (j = 1 + i * sbrEnvData->noOfnoisebands; + j < (sbrEnvData->noOfnoisebands * (1 + i)); j++) { + if (coupling) { + if (sbrEnvData->balance) { + /* coupling && balance */ + payloadBits += FDKwriteBits(hBitStream, + sbrEnvData->hufftableNoiseBalanceFreqC + [sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11], + sbrEnvData->hufftableNoiseBalanceFreqL + [sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11]); + } else { + /* coupling && !balance */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData->hufftableNoiseLevelFreqC + [sbrEnvData->sbr_noise_levels[j] + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseLevelFreqL + [sbrEnvData->sbr_noise_levels[j] + CODE_BOOK_SCF_LAV11]); + } + } else { + /* !coupling */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData + ->hufftableNoiseFreqC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData + ->hufftableNoiseFreqL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } + break; + + case TIME: + for (j = i * sbrEnvData->noOfnoisebands; + j < (sbrEnvData->noOfnoisebands * (1 + i)); j++) { + if (coupling) { + if (sbrEnvData->balance) { + /* coupling && balance */ + payloadBits += FDKwriteBits(hBitStream, + sbrEnvData->hufftableNoiseBalanceTimeC + [sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11], + sbrEnvData->hufftableNoiseBalanceTimeL + [sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11]); + } else { + /* coupling && !balance */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData->hufftableNoiseLevelTimeC + [sbrEnvData->sbr_noise_levels[j] + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseLevelTimeL + [sbrEnvData->sbr_noise_levels[j] + CODE_BOOK_SCF_LAV11]); + } + } else { + /* !coupling */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData + ->hufftableNoiseLevelTimeC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData + ->hufftableNoiseLevelTimeL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } + break; + } + } + return payloadBits; +} + +/***************************************************************************** + + functionname: writeEnvelopeData + description: writes bits corresponding to the envelope + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT writeEnvelopeData(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, INT coupling) { + INT payloadBits = 0, j, i, delta; + + for (j = 0; j < sbrEnvData->noOfEnvelopes; + j++) { /* loop over all envelopes */ + if (sbrEnvData->domain_vec[j] == FREQ) { + if (coupling && sbrEnvData->balance) { + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->ienvelope[j][0], + sbrEnvData->si_sbr_start_env_bits_balance); + } else { + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->ienvelope[j][0], + sbrEnvData->si_sbr_start_env_bits); + } + } + + for (i = 1 - sbrEnvData->domain_vec[j]; i < sbrEnvData->noScfBands[j]; + i++) { + delta = sbrEnvData->ienvelope[j][i]; + if (coupling && sbrEnvData->balance) { + FDK_ASSERT(fixp_abs(delta) <= sbrEnvData->codeBookScfLavBalance); + } else { + FDK_ASSERT(fixp_abs(delta) <= sbrEnvData->codeBookScfLav); + } + if (coupling) { + if (sbrEnvData->balance) { + if (sbrEnvData->domain_vec[j]) { + /* coupling && balance && TIME */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData + ->hufftableBalanceTimeC[delta + + sbrEnvData->codeBookScfLavBalance], + sbrEnvData + ->hufftableBalanceTimeL[delta + + sbrEnvData->codeBookScfLavBalance]); + } else { + /* coupling && balance && FREQ */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData + ->hufftableBalanceFreqC[delta + + sbrEnvData->codeBookScfLavBalance], + sbrEnvData + ->hufftableBalanceFreqL[delta + + sbrEnvData->codeBookScfLavBalance]); + } + } else { + if (sbrEnvData->domain_vec[j]) { + /* coupling && !balance && TIME */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData + ->hufftableLevelTimeC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData + ->hufftableLevelTimeL[delta + sbrEnvData->codeBookScfLav]); + } else { + /* coupling && !balance && FREQ */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData + ->hufftableLevelFreqC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData + ->hufftableLevelFreqL[delta + sbrEnvData->codeBookScfLav]); + } + } + } else { + if (sbrEnvData->domain_vec[j]) { + /* !coupling && TIME */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData->hufftableTimeC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableTimeL[delta + sbrEnvData->codeBookScfLav]); + } else { + /* !coupling && FREQ */ + payloadBits += FDKwriteBits( + hBitStream, + sbrEnvData->hufftableFreqC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableFreqL[delta + sbrEnvData->codeBookScfLav]); + } + } + } + } + return payloadBits; +} + +/***************************************************************************** + + functionname: encodeExtendedData + description: writes bits corresponding to the extended data + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT encodeExtendedData(HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream) { + INT extDataSize; + INT payloadBits = 0; + + extDataSize = getSbrExtendedDataSize(hParametricStereo); + + if (extDataSize != 0) { + INT maxExtSize = (1 << SI_SBR_EXTENSION_SIZE_BITS) - 1; + INT writtenNoBits = 0; /* needed to byte align the extended data */ + + payloadBits += FDKwriteBits(hBitStream, 1, SI_SBR_EXTENDED_DATA_BITS); + FDK_ASSERT(extDataSize <= SBR_EXTENDED_DATA_MAX_CNT); + + if (extDataSize < maxExtSize) { + payloadBits += + FDKwriteBits(hBitStream, extDataSize, SI_SBR_EXTENSION_SIZE_BITS); + } else { + payloadBits += + FDKwriteBits(hBitStream, maxExtSize, SI_SBR_EXTENSION_SIZE_BITS); + payloadBits += FDKwriteBits(hBitStream, extDataSize - maxExtSize, + SI_SBR_EXTENSION_ESC_COUNT_BITS); + } + + /* parametric coding signalled here? */ + if (hParametricStereo) { + writtenNoBits += FDKwriteBits(hBitStream, EXTENSION_ID_PS_CODING, + SI_SBR_EXTENSION_ID_BITS); + writtenNoBits += + FDKsbrEnc_PSEnc_WritePSData(hParametricStereo, hBitStream); + } + + payloadBits += writtenNoBits; + + /* byte alignment */ + writtenNoBits = writtenNoBits % 8; + if (writtenNoBits) + payloadBits += FDKwriteBits(hBitStream, 0, (8 - writtenNoBits)); + } else { + payloadBits += FDKwriteBits(hBitStream, 0, SI_SBR_EXTENDED_DATA_BITS); + } + + return payloadBits; +} + +/***************************************************************************** + + functionname: writeSyntheticCodingData + description: writes bits corresponding to the "synthetic-coding"-extension + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT writeSyntheticCodingData(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream) + +{ + INT i; + INT payloadBits = 0; + + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->addHarmonicFlag, 1); + + if (sbrEnvData->addHarmonicFlag) { + for (i = 0; i < sbrEnvData->noHarmonics; i++) { + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->addHarmonic[i], 1); + } + } + + return payloadBits; +} + +/***************************************************************************** + + functionname: getSbrExtendedDataSize + description: counts the number of bits needed for encoding the + extended data (including extension id) + + returns: number of bits needed for the extended data + input: + output: + +*****************************************************************************/ +static INT getSbrExtendedDataSize(HANDLE_PARAMETRIC_STEREO hParametricStereo) { + INT extDataBits = 0; + + /* add your new extended data counting methods here */ + + /* + no extended data + */ + + if (hParametricStereo) { + /* PS extended data */ + extDataBits += SI_SBR_EXTENSION_ID_BITS; + extDataBits += FDKsbrEnc_PSEnc_WritePSData(hParametricStereo, NULL); + } + + return (extDataBits + 7) >> 3; +} diff --git a/fdk-aac/libSBRenc/src/bit_sbr.h b/fdk-aac/libSBRenc/src/bit_sbr.h new file mode 100644 index 0000000..e90f52c --- /dev/null +++ b/fdk-aac/libSBRenc/src/bit_sbr.h @@ -0,0 +1,267 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief SBR bit writing $Revision: 92790 $ +*/ +#ifndef BIT_SBR_H +#define BIT_SBR_H + +#include "sbr_def.h" +#include "cmondata.h" +#include "fram_gen.h" + +struct SBR_ENV_DATA; + +struct SBR_BITSTREAM_DATA { + INT TotalBits; + INT PayloadBits; + INT FillBits; + INT HeaderActive; + INT HeaderActiveDelay; /**< sbr payload and its header is delayed depending on + encoder configuration*/ + INT NrSendHeaderData; /**< input from commandline */ + INT CountSendHeaderData; /**< modulo count. If < 0 then no counting is done + (no SBR headers) */ + INT rightBorderFIX; /**< force VARFIX or FIXFIX frames */ +}; + +typedef struct SBR_BITSTREAM_DATA *HANDLE_SBR_BITSTREAM_DATA; + +struct SBR_HEADER_DATA { + AMP_RES sbr_amp_res; + INT sbr_start_frequency; + INT sbr_stop_frequency; + INT sbr_xover_band; + INT sbr_noise_bands; + INT sbr_data_extra; + INT header_extra_1; + INT header_extra_2; + INT sbr_lc_stereo_mode; + INT sbr_limiter_bands; + INT sbr_limiter_gains; + INT sbr_interpol_freq; + INT sbr_smoothing_length; + INT alterScale; + INT freqScale; + + /* + element of channelpairelement + */ + INT coupling; + INT prev_coupling; + + /* + element of singlechannelelement + */ +}; +typedef struct SBR_HEADER_DATA *HANDLE_SBR_HEADER_DATA; + +struct SBR_ENV_DATA { + INT sbr_xpos_ctrl; + FREQ_RES freq_res_fixfix[2]; + UCHAR fResTransIsLow; + + INVF_MODE sbr_invf_mode; + INVF_MODE sbr_invf_mode_vec[MAX_NUM_NOISE_VALUES]; + + XPOS_MODE sbr_xpos_mode; + + INT ienvelope[MAX_ENVELOPES][MAX_FREQ_COEFFS]; + + INT codeBookScfLavBalance; + INT codeBookScfLav; + const INT *hufftableTimeC; + const INT *hufftableFreqC; + const UCHAR *hufftableTimeL; + const UCHAR *hufftableFreqL; + + const INT *hufftableLevelTimeC; + const INT *hufftableBalanceTimeC; + const INT *hufftableLevelFreqC; + const INT *hufftableBalanceFreqC; + const UCHAR *hufftableLevelTimeL; + const UCHAR *hufftableBalanceTimeL; + const UCHAR *hufftableLevelFreqL; + const UCHAR *hufftableBalanceFreqL; + + const UCHAR *hufftableNoiseTimeL; + const INT *hufftableNoiseTimeC; + const UCHAR *hufftableNoiseFreqL; + const INT *hufftableNoiseFreqC; + + const UCHAR *hufftableNoiseLevelTimeL; + const INT *hufftableNoiseLevelTimeC; + const UCHAR *hufftableNoiseBalanceTimeL; + const INT *hufftableNoiseBalanceTimeC; + const UCHAR *hufftableNoiseLevelFreqL; + const INT *hufftableNoiseLevelFreqC; + const UCHAR *hufftableNoiseBalanceFreqL; + const INT *hufftableNoiseBalanceFreqC; + + HANDLE_SBR_GRID hSbrBSGrid; + + INT noHarmonics; + INT addHarmonicFlag; + UCHAR addHarmonic[MAX_FREQ_COEFFS]; + + /* calculated helper vars */ + INT si_sbr_start_env_bits_balance; + INT si_sbr_start_env_bits; + INT si_sbr_start_noise_bits_balance; + INT si_sbr_start_noise_bits; + + INT noOfEnvelopes; + INT noScfBands[MAX_ENVELOPES]; + INT domain_vec[MAX_ENVELOPES]; + INT domain_vec_noise[MAX_ENVELOPES]; + SCHAR sbr_noise_levels[MAX_FREQ_COEFFS]; + INT noOfnoisebands; + + INT balance; + AMP_RES init_sbr_amp_res; + AMP_RES currentAmpResFF; + FIXP_DBL + ton_HF[SBR_GLOBAL_TONALITY_VALUES]; /* tonality is scaled by + 2^19/0.524288f (fract part of + RELAXATION) */ + FIXP_DBL global_tonality; + + /* extended data */ + INT extended_data; + INT extension_size; + INT extension_id; + UCHAR extended_data_buffer[SBR_EXTENDED_DATA_MAX_CNT]; + + UCHAR ldGrid; +}; +typedef struct SBR_ENV_DATA *HANDLE_SBR_ENV_DATA; + +INT FDKsbrEnc_WriteEnvSingleChannelElement( + struct SBR_HEADER_DATA *sbrHeaderData, + struct T_PARAMETRIC_STEREO *hParametricStereo, + struct SBR_BITSTREAM_DATA *sbrBitstreamData, + struct SBR_ENV_DATA *sbrEnvData, struct COMMON_DATA *cmonData, + UINT sbrSyntaxFlags); + +INT FDKsbrEnc_WriteEnvChannelPairElement( + struct SBR_HEADER_DATA *sbrHeaderData, + struct T_PARAMETRIC_STEREO *hParametricStereo, + struct SBR_BITSTREAM_DATA *sbrBitstreamData, + struct SBR_ENV_DATA *sbrEnvDataLeft, struct SBR_ENV_DATA *sbrEnvDataRight, + struct COMMON_DATA *cmonData, UINT sbrSyntaxFlags); + +INT FDKsbrEnc_CountSbrChannelPairElement( + struct SBR_HEADER_DATA *sbrHeaderData, + struct T_PARAMETRIC_STEREO *hParametricStereo, + struct SBR_BITSTREAM_DATA *sbrBitstreamData, + struct SBR_ENV_DATA *sbrEnvDataLeft, struct SBR_ENV_DATA *sbrEnvDataRight, + struct COMMON_DATA *cmonData, UINT sbrSyntaxFlags); + +/* debugging and tuning functions */ + +/*#define SBR_ENV_STATISTICS */ + +/*#define SBR_PAYLOAD_MONITOR*/ + +#endif diff --git a/fdk-aac/libSBRenc/src/cmondata.h b/fdk-aac/libSBRenc/src/cmondata.h new file mode 100644 index 0000000..0779b4d --- /dev/null +++ b/fdk-aac/libSBRenc/src/cmondata.h @@ -0,0 +1,127 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Core Coder's and SBR's shared data structure definition $Revision: + 92790 $ +*/ +#ifndef CMONDATA_H +#define CMONDATA_H + +#include "FDK_bitstream.h" + +struct COMMON_DATA { + INT sbrHdrBits; /**< number of SBR header bits */ + INT sbrDataBits; /**< number of SBR data bits */ + INT sbrFillBits; /**< number of SBR fill bits */ + FDK_BITSTREAM sbrBitbuf; /**< the SBR data bitbuffer */ + FDK_BITSTREAM tmpWriteBitbuf; /**< helper var for writing header*/ + INT xOverFreq; /**< the SBR crossover frequency */ + INT dynBwEnabled; /**< indicates if dynamic bandwidth is enabled */ + INT sbrNumChannels; /**< number of channels (meaning mono or stereo) */ + INT dynXOverFreqEnc; /**< encoder dynamic crossover frequency */ +}; + +typedef struct COMMON_DATA *HANDLE_COMMON_DATA; + +#endif diff --git a/fdk-aac/libSBRenc/src/code_env.cpp b/fdk-aac/libSBRenc/src/code_env.cpp new file mode 100644 index 0000000..fb0f6a4 --- /dev/null +++ b/fdk-aac/libSBRenc/src/code_env.cpp @@ -0,0 +1,602 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "code_env.h" +#include "sbrenc_rom.h" + +/***************************************************************************** + + functionname: FDKsbrEnc_InitSbrHuffmanTables + description: initializes Huffman Tables dependent on chosen amp_res + returns: error handle + input: + output: + +*****************************************************************************/ +INT FDKsbrEnc_InitSbrHuffmanTables(HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_SBR_CODE_ENVELOPE henv, + HANDLE_SBR_CODE_ENVELOPE hnoise, + AMP_RES amp_res) { + if ((!henv) || (!hnoise) || (!sbrEnvData)) return (1); /* not init. */ + + sbrEnvData->init_sbr_amp_res = amp_res; + + switch (amp_res) { + case SBR_AMP_RES_3_0: + /*envelope data*/ + + /*Level/Pan - coding */ + sbrEnvData->hufftableLevelTimeC = v_Huff_envelopeLevelC11T; + sbrEnvData->hufftableLevelTimeL = v_Huff_envelopeLevelL11T; + sbrEnvData->hufftableBalanceTimeC = bookSbrEnvBalanceC11T; + sbrEnvData->hufftableBalanceTimeL = bookSbrEnvBalanceL11T; + + sbrEnvData->hufftableLevelFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableLevelFreqL = v_Huff_envelopeLevelL11F; + sbrEnvData->hufftableBalanceFreqC = bookSbrEnvBalanceC11F; + sbrEnvData->hufftableBalanceFreqL = bookSbrEnvBalanceL11F; + + /*Right/Left - coding */ + sbrEnvData->hufftableTimeC = v_Huff_envelopeLevelC11T; + sbrEnvData->hufftableTimeL = v_Huff_envelopeLevelL11T; + sbrEnvData->hufftableFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableFreqL = v_Huff_envelopeLevelL11F; + + sbrEnvData->codeBookScfLavBalance = CODE_BOOK_SCF_LAV_BALANCE11; + sbrEnvData->codeBookScfLav = CODE_BOOK_SCF_LAV11; + + sbrEnvData->si_sbr_start_env_bits = SI_SBR_START_ENV_BITS_AMP_RES_3_0; + sbrEnvData->si_sbr_start_env_bits_balance = + SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_3_0; + break; + + case SBR_AMP_RES_1_5: + /*envelope data*/ + + /*Level/Pan - coding */ + sbrEnvData->hufftableLevelTimeC = v_Huff_envelopeLevelC10T; + sbrEnvData->hufftableLevelTimeL = v_Huff_envelopeLevelL10T; + sbrEnvData->hufftableBalanceTimeC = bookSbrEnvBalanceC10T; + sbrEnvData->hufftableBalanceTimeL = bookSbrEnvBalanceL10T; + + sbrEnvData->hufftableLevelFreqC = v_Huff_envelopeLevelC10F; + sbrEnvData->hufftableLevelFreqL = v_Huff_envelopeLevelL10F; + sbrEnvData->hufftableBalanceFreqC = bookSbrEnvBalanceC10F; + sbrEnvData->hufftableBalanceFreqL = bookSbrEnvBalanceL10F; + + /*Right/Left - coding */ + sbrEnvData->hufftableTimeC = v_Huff_envelopeLevelC10T; + sbrEnvData->hufftableTimeL = v_Huff_envelopeLevelL10T; + sbrEnvData->hufftableFreqC = v_Huff_envelopeLevelC10F; + sbrEnvData->hufftableFreqL = v_Huff_envelopeLevelL10F; + + sbrEnvData->codeBookScfLavBalance = CODE_BOOK_SCF_LAV_BALANCE10; + sbrEnvData->codeBookScfLav = CODE_BOOK_SCF_LAV10; + + sbrEnvData->si_sbr_start_env_bits = SI_SBR_START_ENV_BITS_AMP_RES_1_5; + sbrEnvData->si_sbr_start_env_bits_balance = + SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_1_5; + break; + + default: + return (1); /* undefined amp_res mode */ + } + + /* these are common to both amp_res values */ + /*Noise data*/ + + /*Level/Pan - coding */ + sbrEnvData->hufftableNoiseLevelTimeC = v_Huff_NoiseLevelC11T; + sbrEnvData->hufftableNoiseLevelTimeL = v_Huff_NoiseLevelL11T; + sbrEnvData->hufftableNoiseBalanceTimeC = bookSbrNoiseBalanceC11T; + sbrEnvData->hufftableNoiseBalanceTimeL = bookSbrNoiseBalanceL11T; + + sbrEnvData->hufftableNoiseLevelFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableNoiseLevelFreqL = v_Huff_envelopeLevelL11F; + sbrEnvData->hufftableNoiseBalanceFreqC = bookSbrEnvBalanceC11F; + sbrEnvData->hufftableNoiseBalanceFreqL = bookSbrEnvBalanceL11F; + + /*Right/Left - coding */ + sbrEnvData->hufftableNoiseTimeC = v_Huff_NoiseLevelC11T; + sbrEnvData->hufftableNoiseTimeL = v_Huff_NoiseLevelL11T; + sbrEnvData->hufftableNoiseFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableNoiseFreqL = v_Huff_envelopeLevelL11F; + + sbrEnvData->si_sbr_start_noise_bits = SI_SBR_START_NOISE_BITS_AMP_RES_3_0; + sbrEnvData->si_sbr_start_noise_bits_balance = + SI_SBR_START_NOISE_BITS_BALANCE_AMP_RES_3_0; + + /* init envelope tables and codebooks */ + henv->codeBookScfLavBalanceTime = sbrEnvData->codeBookScfLavBalance; + henv->codeBookScfLavBalanceFreq = sbrEnvData->codeBookScfLavBalance; + henv->codeBookScfLavLevelTime = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavLevelFreq = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavTime = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavFreq = sbrEnvData->codeBookScfLav; + + henv->hufftableLevelTimeL = sbrEnvData->hufftableLevelTimeL; + henv->hufftableBalanceTimeL = sbrEnvData->hufftableBalanceTimeL; + henv->hufftableTimeL = sbrEnvData->hufftableTimeL; + henv->hufftableLevelFreqL = sbrEnvData->hufftableLevelFreqL; + henv->hufftableBalanceFreqL = sbrEnvData->hufftableBalanceFreqL; + henv->hufftableFreqL = sbrEnvData->hufftableFreqL; + + henv->codeBookScfLavFreq = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavTime = sbrEnvData->codeBookScfLav; + + henv->start_bits = sbrEnvData->si_sbr_start_env_bits; + henv->start_bits_balance = sbrEnvData->si_sbr_start_env_bits_balance; + + /* init noise tables and codebooks */ + + hnoise->codeBookScfLavBalanceTime = CODE_BOOK_SCF_LAV_BALANCE11; + hnoise->codeBookScfLavBalanceFreq = CODE_BOOK_SCF_LAV_BALANCE11; + hnoise->codeBookScfLavLevelTime = CODE_BOOK_SCF_LAV11; + hnoise->codeBookScfLavLevelFreq = CODE_BOOK_SCF_LAV11; + hnoise->codeBookScfLavTime = CODE_BOOK_SCF_LAV11; + hnoise->codeBookScfLavFreq = CODE_BOOK_SCF_LAV11; + + hnoise->hufftableLevelTimeL = sbrEnvData->hufftableNoiseLevelTimeL; + hnoise->hufftableBalanceTimeL = sbrEnvData->hufftableNoiseBalanceTimeL; + hnoise->hufftableTimeL = sbrEnvData->hufftableNoiseTimeL; + hnoise->hufftableLevelFreqL = sbrEnvData->hufftableNoiseLevelFreqL; + hnoise->hufftableBalanceFreqL = sbrEnvData->hufftableNoiseBalanceFreqL; + hnoise->hufftableFreqL = sbrEnvData->hufftableNoiseFreqL; + + hnoise->start_bits = sbrEnvData->si_sbr_start_noise_bits; + hnoise->start_bits_balance = sbrEnvData->si_sbr_start_noise_bits_balance; + + /* No delta coding in time from the previous frame due to 1.5dB FIx-FIX rule + */ + henv->upDate = 0; + hnoise->upDate = 0; + return (0); +} + +/******************************************************************************* + Functionname: indexLow2High + ******************************************************************************* + + Description: Nice small patch-functions in order to cope with non-factor-2 + ratios between high-res and low-res + + Arguments: INT offset, INT index, FREQ_RES res + + Return: INT + +*******************************************************************************/ +static INT indexLow2High(INT offset, INT index, FREQ_RES res) { + if (res == FREQ_RES_LOW) { + if (offset >= 0) { + if (index < offset) + return (index); + else + return (2 * index - offset); + } else { + offset = -offset; + if (index < offset) + return (2 * index + index); + else + return (2 * index + offset); + } + } else + return (index); +} + +/******************************************************************************* + Functionname: mapLowResEnergyVal + ******************************************************************************* + + Description: + + Arguments: INT currVal,INT* prevData, INT offset, INT index, FREQ_RES res + + Return: none + +*******************************************************************************/ +static void mapLowResEnergyVal(SCHAR currVal, SCHAR *prevData, INT offset, + INT index, FREQ_RES res) { + if (res == FREQ_RES_LOW) { + if (offset >= 0) { + if (index < offset) + prevData[index] = currVal; + else { + prevData[2 * index - offset] = currVal; + prevData[2 * index + 1 - offset] = currVal; + } + } else { + offset = -offset; + if (index < offset) { + prevData[3 * index] = currVal; + prevData[3 * index + 1] = currVal; + prevData[3 * index + 2] = currVal; + } else { + prevData[2 * index + offset] = currVal; + prevData[2 * index + 1 + offset] = currVal; + } + } + } else + prevData[index] = currVal; +} + +/******************************************************************************* + Functionname: computeBits + ******************************************************************************* + + Description: + + Arguments: INT delta, + INT codeBookScfLavLevel, + INT codeBookScfLavBalance, + const UCHAR * hufftableLevel, + const UCHAR * hufftableBalance, INT coupling, INT channel) + + Return: INT + +*******************************************************************************/ +static INT computeBits(SCHAR *delta, INT codeBookScfLavLevel, + INT codeBookScfLavBalance, const UCHAR *hufftableLevel, + const UCHAR *hufftableBalance, INT coupling, + INT channel) { + INT index; + INT delta_bits = 0; + + if (coupling) { + if (channel == 1) { + if (*delta < 0) + index = fixMax(*delta, -codeBookScfLavBalance); + else + index = fixMin(*delta, codeBookScfLavBalance); + + if (index != *delta) { + *delta = index; + return (10000); + } + + delta_bits = hufftableBalance[index + codeBookScfLavBalance]; + } else { + if (*delta < 0) + index = fixMax(*delta, -codeBookScfLavLevel); + else + index = fixMin(*delta, codeBookScfLavLevel); + + if (index != *delta) { + *delta = index; + return (10000); + } + delta_bits = hufftableLevel[index + codeBookScfLavLevel]; + } + } else { + if (*delta < 0) + index = fixMax(*delta, -codeBookScfLavLevel); + else + index = fixMin(*delta, codeBookScfLavLevel); + + if (index != *delta) { + *delta = index; + return (10000); + } + delta_bits = hufftableLevel[index + codeBookScfLavLevel]; + } + + return (delta_bits); +} + +/******************************************************************************* + Functionname: FDKsbrEnc_codeEnvelope + ******************************************************************************* + + Description: + + Arguments: INT *sfb_nrg, + const FREQ_RES *freq_res, + SBR_CODE_ENVELOPE * h_sbrCodeEnvelope, + INT *directionVec, INT scalable, INT nEnvelopes, INT channel, + INT headerActive) + + Return: none + h_sbrCodeEnvelope->sfb_nrg_prev is modified ! + sfb_nrg is modified + h_sbrCodeEnvelope->update is modfied ! + *directionVec is modified + +*******************************************************************************/ +void FDKsbrEnc_codeEnvelope(SCHAR *sfb_nrg, const FREQ_RES *freq_res, + SBR_CODE_ENVELOPE *h_sbrCodeEnvelope, + INT *directionVec, INT coupling, INT nEnvelopes, + INT channel, INT headerActive) { + INT i, no_of_bands, band; + FIXP_DBL tmp1, tmp2, tmp3, dF_edge_1stEnv; + SCHAR *ptr_nrg; + + INT codeBookScfLavLevelTime; + INT codeBookScfLavLevelFreq; + INT codeBookScfLavBalanceTime; + INT codeBookScfLavBalanceFreq; + const UCHAR *hufftableLevelTimeL; + const UCHAR *hufftableBalanceTimeL; + const UCHAR *hufftableLevelFreqL; + const UCHAR *hufftableBalanceFreqL; + + INT offset = h_sbrCodeEnvelope->offset; + INT envDataTableCompFactor; + + INT delta_F_bits = 0, delta_T_bits = 0; + INT use_dT; + + SCHAR delta_F[MAX_FREQ_COEFFS]; + SCHAR delta_T[MAX_FREQ_COEFFS]; + SCHAR last_nrg, curr_nrg; + + tmp1 = FL2FXCONST_DBL(0.5f) >> (DFRACT_BITS - 16 - 1); + tmp2 = h_sbrCodeEnvelope->dF_edge_1stEnv >> (DFRACT_BITS - 16); + tmp3 = (FIXP_DBL)fMult(h_sbrCodeEnvelope->dF_edge_incr, + ((FIXP_DBL)h_sbrCodeEnvelope->dF_edge_incr_fac) << 15); + + dF_edge_1stEnv = tmp1 + tmp2 + tmp3; + + if (coupling) { + codeBookScfLavLevelTime = h_sbrCodeEnvelope->codeBookScfLavLevelTime; + codeBookScfLavLevelFreq = h_sbrCodeEnvelope->codeBookScfLavLevelFreq; + codeBookScfLavBalanceTime = h_sbrCodeEnvelope->codeBookScfLavBalanceTime; + codeBookScfLavBalanceFreq = h_sbrCodeEnvelope->codeBookScfLavBalanceFreq; + hufftableLevelTimeL = h_sbrCodeEnvelope->hufftableLevelTimeL; + hufftableBalanceTimeL = h_sbrCodeEnvelope->hufftableBalanceTimeL; + hufftableLevelFreqL = h_sbrCodeEnvelope->hufftableLevelFreqL; + hufftableBalanceFreqL = h_sbrCodeEnvelope->hufftableBalanceFreqL; + } else { + codeBookScfLavLevelTime = h_sbrCodeEnvelope->codeBookScfLavTime; + codeBookScfLavLevelFreq = h_sbrCodeEnvelope->codeBookScfLavFreq; + codeBookScfLavBalanceTime = h_sbrCodeEnvelope->codeBookScfLavTime; + codeBookScfLavBalanceFreq = h_sbrCodeEnvelope->codeBookScfLavFreq; + hufftableLevelTimeL = h_sbrCodeEnvelope->hufftableTimeL; + hufftableBalanceTimeL = h_sbrCodeEnvelope->hufftableTimeL; + hufftableLevelFreqL = h_sbrCodeEnvelope->hufftableFreqL; + hufftableBalanceFreqL = h_sbrCodeEnvelope->hufftableFreqL; + } + + if (coupling == 1 && channel == 1) + envDataTableCompFactor = + 1; /*should be one when the new huffman-tables are ready*/ + else + envDataTableCompFactor = 0; + + if (h_sbrCodeEnvelope->deltaTAcrossFrames == 0) h_sbrCodeEnvelope->upDate = 0; + + /* no delta coding in time in case of a header */ + if (headerActive) h_sbrCodeEnvelope->upDate = 0; + + for (i = 0; i < nEnvelopes; i++) { + if (freq_res[i] == FREQ_RES_HIGH) + no_of_bands = h_sbrCodeEnvelope->nSfb[FREQ_RES_HIGH]; + else + no_of_bands = h_sbrCodeEnvelope->nSfb[FREQ_RES_LOW]; + + ptr_nrg = sfb_nrg; + curr_nrg = *ptr_nrg; + + delta_F[0] = curr_nrg >> envDataTableCompFactor; + + if (coupling && channel == 1) + delta_F_bits = h_sbrCodeEnvelope->start_bits_balance; + else + delta_F_bits = h_sbrCodeEnvelope->start_bits; + + if (h_sbrCodeEnvelope->upDate != 0) { + delta_T[0] = (curr_nrg - h_sbrCodeEnvelope->sfb_nrg_prev[0]) >> + envDataTableCompFactor; + + delta_T_bits = computeBits(&delta_T[0], codeBookScfLavLevelTime, + codeBookScfLavBalanceTime, hufftableLevelTimeL, + hufftableBalanceTimeL, coupling, channel); + } + + mapLowResEnergyVal(curr_nrg, h_sbrCodeEnvelope->sfb_nrg_prev, offset, 0, + freq_res[i]); + + /* ensure that nrg difference is not higher than codeBookScfLavXXXFreq */ + if (coupling && channel == 1) { + for (band = no_of_bands - 1; band > 0; band--) { + if (ptr_nrg[band] - ptr_nrg[band - 1] > codeBookScfLavBalanceFreq) { + ptr_nrg[band - 1] = ptr_nrg[band] - codeBookScfLavBalanceFreq; + } + } + for (band = 1; band < no_of_bands; band++) { + if (ptr_nrg[band - 1] - ptr_nrg[band] > codeBookScfLavBalanceFreq) { + ptr_nrg[band] = ptr_nrg[band - 1] - codeBookScfLavBalanceFreq; + } + } + } else { + for (band = no_of_bands - 1; band > 0; band--) { + if (ptr_nrg[band] - ptr_nrg[band - 1] > codeBookScfLavLevelFreq) { + ptr_nrg[band - 1] = ptr_nrg[band] - codeBookScfLavLevelFreq; + } + } + for (band = 1; band < no_of_bands; band++) { + if (ptr_nrg[band - 1] - ptr_nrg[band] > codeBookScfLavLevelFreq) { + ptr_nrg[band] = ptr_nrg[band - 1] - codeBookScfLavLevelFreq; + } + } + } + + /* Coding loop*/ + for (band = 1; band < no_of_bands; band++) { + last_nrg = (*ptr_nrg); + ptr_nrg++; + curr_nrg = (*ptr_nrg); + + delta_F[band] = (curr_nrg - last_nrg) >> envDataTableCompFactor; + + delta_F_bits += computeBits( + &delta_F[band], codeBookScfLavLevelFreq, codeBookScfLavBalanceFreq, + hufftableLevelFreqL, hufftableBalanceFreqL, coupling, channel); + + if (h_sbrCodeEnvelope->upDate != 0) { + delta_T[band] = + curr_nrg - + h_sbrCodeEnvelope + ->sfb_nrg_prev[indexLow2High(offset, band, freq_res[i])]; + delta_T[band] = delta_T[band] >> envDataTableCompFactor; + } + + mapLowResEnergyVal(curr_nrg, h_sbrCodeEnvelope->sfb_nrg_prev, offset, + band, freq_res[i]); + + if (h_sbrCodeEnvelope->upDate != 0) { + delta_T_bits += computeBits( + &delta_T[band], codeBookScfLavLevelTime, codeBookScfLavBalanceTime, + hufftableLevelTimeL, hufftableBalanceTimeL, coupling, channel); + } + } + + /* Replace sfb_nrg with deltacoded samples and set flag */ + if (i == 0) { + INT tmp_bits; + tmp_bits = (((delta_T_bits * dF_edge_1stEnv) >> (DFRACT_BITS - 18)) + + (FIXP_DBL)1) >> + 1; + use_dT = (h_sbrCodeEnvelope->upDate != 0 && (delta_F_bits > tmp_bits)); + } else + use_dT = (delta_T_bits < delta_F_bits && h_sbrCodeEnvelope->upDate != 0); + + if (use_dT) { + directionVec[i] = TIME; + FDKmemcpy(sfb_nrg, delta_T, no_of_bands * sizeof(SCHAR)); + } else { + h_sbrCodeEnvelope->upDate = 0; + directionVec[i] = FREQ; + FDKmemcpy(sfb_nrg, delta_F, no_of_bands * sizeof(SCHAR)); + } + sfb_nrg += no_of_bands; + h_sbrCodeEnvelope->upDate = 1; + } +} + +/******************************************************************************* + Functionname: FDKsbrEnc_InitSbrCodeEnvelope + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +INT FDKsbrEnc_InitSbrCodeEnvelope(HANDLE_SBR_CODE_ENVELOPE h_sbrCodeEnvelope, + INT *nSfb, INT deltaTAcrossFrames, + FIXP_DBL dF_edge_1stEnv, + FIXP_DBL dF_edge_incr) { + FDKmemclear(h_sbrCodeEnvelope, sizeof(SBR_CODE_ENVELOPE)); + + h_sbrCodeEnvelope->deltaTAcrossFrames = deltaTAcrossFrames; + h_sbrCodeEnvelope->dF_edge_1stEnv = dF_edge_1stEnv; + h_sbrCodeEnvelope->dF_edge_incr = dF_edge_incr; + h_sbrCodeEnvelope->dF_edge_incr_fac = 0; + h_sbrCodeEnvelope->upDate = 0; + h_sbrCodeEnvelope->nSfb[FREQ_RES_LOW] = nSfb[FREQ_RES_LOW]; + h_sbrCodeEnvelope->nSfb[FREQ_RES_HIGH] = nSfb[FREQ_RES_HIGH]; + h_sbrCodeEnvelope->offset = 2 * h_sbrCodeEnvelope->nSfb[FREQ_RES_LOW] - + h_sbrCodeEnvelope->nSfb[FREQ_RES_HIGH]; + + return (0); +} diff --git a/fdk-aac/libSBRenc/src/code_env.h b/fdk-aac/libSBRenc/src/code_env.h new file mode 100644 index 0000000..673a783 --- /dev/null +++ b/fdk-aac/libSBRenc/src/code_env.h @@ -0,0 +1,161 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief DPCM Envelope coding $Revision: 92790 $ +*/ + +#ifndef CODE_ENV_H +#define CODE_ENV_H + +#include "sbr_def.h" +#include "bit_sbr.h" +#include "fram_gen.h" + +typedef struct { + INT offset; + INT upDate; + INT nSfb[2]; + SCHAR sfb_nrg_prev[MAX_FREQ_COEFFS]; + INT deltaTAcrossFrames; + FIXP_DBL dF_edge_1stEnv; + FIXP_DBL dF_edge_incr; + INT dF_edge_incr_fac; + + INT codeBookScfLavTime; + INT codeBookScfLavFreq; + + INT codeBookScfLavLevelTime; + INT codeBookScfLavLevelFreq; + INT codeBookScfLavBalanceTime; + INT codeBookScfLavBalanceFreq; + + INT start_bits; + INT start_bits_balance; + + const UCHAR *hufftableTimeL; + const UCHAR *hufftableFreqL; + + const UCHAR *hufftableLevelTimeL; + const UCHAR *hufftableBalanceTimeL; + const UCHAR *hufftableLevelFreqL; + const UCHAR *hufftableBalanceFreqL; +} SBR_CODE_ENVELOPE; +typedef SBR_CODE_ENVELOPE *HANDLE_SBR_CODE_ENVELOPE; + +void FDKsbrEnc_codeEnvelope(SCHAR *sfb_nrg, const FREQ_RES *freq_res, + SBR_CODE_ENVELOPE *h_sbrCodeEnvelope, + INT *directionVec, INT coupling, INT nEnvelopes, + INT channel, INT headerActive); + +INT FDKsbrEnc_InitSbrCodeEnvelope(HANDLE_SBR_CODE_ENVELOPE h_sbrCodeEnvelope, + INT *nSfb, INT deltaTAcrossFrames, + FIXP_DBL dF_edge_1stEnv, + FIXP_DBL dF_edge_incr); + +INT FDKsbrEnc_InitSbrHuffmanTables(struct SBR_ENV_DATA *sbrEnvData, + HANDLE_SBR_CODE_ENVELOPE henv, + HANDLE_SBR_CODE_ENVELOPE hnoise, + AMP_RES amp_res); + +#endif diff --git a/fdk-aac/libSBRenc/src/env_bit.cpp b/fdk-aac/libSBRenc/src/env_bit.cpp new file mode 100644 index 0000000..41812ac --- /dev/null +++ b/fdk-aac/libSBRenc/src/env_bit.cpp @@ -0,0 +1,257 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Remaining SBR Bit Writing Routines +*/ + +#include "env_bit.h" +#include "cmondata.h" + +#ifndef min +#define min(a, b) (a < b ? a : b) +#endif + +#ifndef max +#define max(a, b) (a > b ? a : b) +#endif + +/* ***************************** crcAdvance **********************************/ +/** + * @fn + * @brief updates crc data register + * @return none + * + * This function updates the crc register + * + */ +static void crcAdvance(USHORT crcPoly, USHORT crcMask, USHORT *crc, + ULONG bValue, INT bBits) { + INT i; + USHORT flag; + + for (i = bBits - 1; i >= 0; i--) { + flag = ((*crc) & crcMask) ? (1) : (0); + flag ^= (bValue & (1 << i)) ? (1) : (0); + + (*crc) <<= 1; + if (flag) (*crc) ^= crcPoly; + } +} + +/* ***************************** FDKsbrEnc_InitSbrBitstream + * **********************************/ +/** + * @fn + * @brief Inittialisation of sbr bitstream, write of dummy header and CRC + * @return none + * + * + * + */ + +INT FDKsbrEnc_InitSbrBitstream( + HANDLE_COMMON_DATA hCmonData, + UCHAR *memoryBase, /*!< Pointer to bitstream buffer */ + INT memorySize, /*!< Length of bitstream buffer in bytes */ + HANDLE_FDK_CRCINFO hCrcInfo, UINT sbrSyntaxFlags) /*!< SBR syntax flags */ +{ + INT crcRegion = 0; + + /* reset bit buffer */ + FDKresetBitbuffer(&hCmonData->sbrBitbuf, BS_WRITER); + + FDKinitBitStream(&hCmonData->tmpWriteBitbuf, memoryBase, memorySize, 0, + BS_WRITER); + + if (sbrSyntaxFlags & SBR_SYNTAX_CRC) { + if (sbrSyntaxFlags & SBR_SYNTAX_DRM_CRC) { /* Init and start CRC region */ + FDKwriteBits(&hCmonData->sbrBitbuf, 0x0, SI_SBR_DRM_CRC_BITS); + FDKcrcInit(hCrcInfo, 0x001d, 0xFFFF, SI_SBR_DRM_CRC_BITS); + crcRegion = FDKcrcStartReg(hCrcInfo, &hCmonData->sbrBitbuf, 0); + } else { + FDKwriteBits(&hCmonData->sbrBitbuf, 0x0, SI_SBR_CRC_BITS); + } + } + + return (crcRegion); +} + +/* ************************** FDKsbrEnc_AssembleSbrBitstream + * *******************************/ +/** + * @fn + * @brief Formats the SBR payload + * @return nothing + * + * Also the CRC will be calculated here. + * + */ + +void FDKsbrEnc_AssembleSbrBitstream(HANDLE_COMMON_DATA hCmonData, + HANDLE_FDK_CRCINFO hCrcInfo, INT crcRegion, + UINT sbrSyntaxFlags) { + USHORT crcReg = SBR_CRCINIT; + INT numCrcBits, i; + + /* check if SBR is present */ + if (hCmonData == NULL) return; + + hCmonData->sbrFillBits = 0; /* Fill bits are written only for GA streams */ + + if (sbrSyntaxFlags & SBR_SYNTAX_DRM_CRC) { + /* + * Calculate and write DRM CRC + */ + FDKcrcEndReg(hCrcInfo, &hCmonData->sbrBitbuf, crcRegion); + FDKwriteBits(&hCmonData->tmpWriteBitbuf, FDKcrcGetCRC(hCrcInfo) ^ 0xFF, + SI_SBR_DRM_CRC_BITS); + } else { + if (!(sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY)) { + /* Do alignment here, because its defined as part of the + * sbr_extension_data */ + int sbrLoad = hCmonData->sbrHdrBits + hCmonData->sbrDataBits; + + if (sbrSyntaxFlags & SBR_SYNTAX_CRC) { + sbrLoad += SI_SBR_CRC_BITS; + } + + sbrLoad += 4; /* Do byte Align with 4 bit offset. ISO/IEC 14496-3:2005(E) + page 39. */ + + hCmonData->sbrFillBits = (8 - (sbrLoad % 8)) % 8; + + /* + append fill bits + */ + FDKwriteBits(&hCmonData->sbrBitbuf, 0, hCmonData->sbrFillBits); + + FDK_ASSERT(FDKgetValidBits(&hCmonData->sbrBitbuf) % 8 == 4); + } + + /* + calculate crc + */ + if (sbrSyntaxFlags & SBR_SYNTAX_CRC) { + FDK_BITSTREAM tmpCRCBuf = hCmonData->sbrBitbuf; + FDKresetBitbuffer(&tmpCRCBuf, BS_READER); + + numCrcBits = hCmonData->sbrHdrBits + hCmonData->sbrDataBits + + hCmonData->sbrFillBits; + + for (i = 0; i < numCrcBits; i++) { + INT bit; + bit = FDKreadBits(&tmpCRCBuf, 1); + crcAdvance(SBR_CRC_POLY, SBR_CRC_MASK, &crcReg, bit, 1); + } + crcReg &= (SBR_CRC_RANGE); + + /* + * Write CRC data. + */ + FDKwriteBits(&hCmonData->tmpWriteBitbuf, crcReg, SI_SBR_CRC_BITS); + } + } + + FDKsyncCache(&hCmonData->tmpWriteBitbuf); +} diff --git a/fdk-aac/libSBRenc/src/env_bit.h b/fdk-aac/libSBRenc/src/env_bit.h new file mode 100644 index 0000000..b91802c --- /dev/null +++ b/fdk-aac/libSBRenc/src/env_bit.h @@ -0,0 +1,135 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Remaining SBR Bit Writing Routines +*/ + +#ifndef ENV_BIT_H +#define ENV_BIT_H + +#include "sbr_encoder.h" +#include "FDK_crc.h" + +/* G(x) = x^10 + x^9 + x^5 + x^4 + x + 1 */ +#define SBR_CRC_POLY (0x0233) +#define SBR_CRC_MASK (0x0200) +#define SBR_CRC_RANGE (0x03FF) +#define SBR_CRC_MAXREGS 1 +#define SBR_CRCINIT (0x0) + +#define SI_SBR_CRC_ENABLE_BITS 0 +#define SI_SBR_CRC_BITS 10 +#define SI_SBR_DRM_CRC_BITS 8 + +struct COMMON_DATA; + +INT FDKsbrEnc_InitSbrBitstream(struct COMMON_DATA *hCmonData, UCHAR *memoryBase, + INT memorySize, HANDLE_FDK_CRCINFO hCrcInfo, + UINT sbrSyntaxFlags); + +void FDKsbrEnc_AssembleSbrBitstream(struct COMMON_DATA *hCmonData, + HANDLE_FDK_CRCINFO hCrcInfo, INT crcRegion, + UINT sbrSyntaxFlags); + +#endif /* #ifndef ENV_BIT_H */ diff --git a/fdk-aac/libSBRenc/src/env_est.cpp b/fdk-aac/libSBRenc/src/env_est.cpp new file mode 100644 index 0000000..4af561b --- /dev/null +++ b/fdk-aac/libSBRenc/src/env_est.cpp @@ -0,0 +1,1986 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "env_est.h" +#include "tran_det.h" + +#include "qmf.h" + +#include "fram_gen.h" +#include "bit_sbr.h" +#include "cmondata.h" +#include "sbrenc_ram.h" + +#include "genericStds.h" + +#define QUANT_ERROR_THRES 200 +#define Y_NRG_SCALE 5 /* noCols = 32 -> shift(5) */ +#define MAX_NRG_SLOTS_LD 16 + +static const UCHAR panTable[2][10] = {{0, 2, 4, 6, 8, 12, 16, 20, 24}, + {0, 2, 4, 8, 12, 0, 0, 0, 0}}; +static const UCHAR maxIndex[2] = {9, 5}; + +/****************************************************************************** + Functionname: FDKsbrEnc_GetTonality +******************************************************************************/ +/***************************************************************************/ +/*! + + \brief Calculates complete energy per band from the energy values + of the QMF subsamples. + + \brief quotaMatrix - calculated in FDKsbrEnc_CalculateTonalityQuotas() + \brief noEstPerFrame - number of estimations per frame + \brief startIndex - start index for the quota matrix + \brief Energies - energy matrix + \brief startBand - start band + \brief stopBand - number of QMF bands + \brief numberCols - number of QMF subsamples + + \return mean tonality of the 5 bands with the highest energy + scaled by 2^(RELAXATION_SHIFT+2)*RELAXATION_FRACT + +****************************************************************************/ +static FIXP_DBL FDKsbrEnc_GetTonality(const FIXP_DBL *const *quotaMatrix, + const INT noEstPerFrame, + const INT startIndex, + const FIXP_DBL *const *Energies, + const UCHAR startBand, const INT stopBand, + const INT numberCols) { + UCHAR b, e, k; + INT no_enMaxBand[SBR_MAX_ENERGY_VALUES] = {-1, -1, -1, -1, -1}; + FIXP_DBL energyMax[SBR_MAX_ENERGY_VALUES] = { + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f)}; + FIXP_DBL energyMaxMin = MAXVAL_DBL; /* min. energy in energyMax array */ + UCHAR posEnergyMaxMin = 0; /* min. energy in energyMax array position */ + FIXP_DBL tonalityBand[SBR_MAX_ENERGY_VALUES] = { + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f)}; + FIXP_DBL globalTonality = FL2FXCONST_DBL(0.0f); + FIXP_DBL energyBand[64]; + INT maxNEnergyValues; /* max. number of max. energy values */ + + /*** Sum up energies for each band ***/ + FDK_ASSERT(numberCols == 15 || numberCols == 16); + /* numberCols is always 15 or 16 for ELD. In case of 16 bands, the + energyBands are initialized with the [15]th column. + The rest of the column energies are added in the next step. */ + if (numberCols == 15) { + for (b = startBand; b < stopBand; b++) { + energyBand[b] = FL2FXCONST_DBL(0.0f); + } + } else { + for (b = startBand; b < stopBand; b++) { + energyBand[b] = Energies[15][b] >> 4; + } + } + + for (k = 0; k < 15; k++) { + for (b = startBand; b < stopBand; b++) { + energyBand[b] += Energies[k][b] >> 4; + } + } + + /*** Determine 5 highest band-energies ***/ + maxNEnergyValues = fMin(SBR_MAX_ENERGY_VALUES, stopBand - startBand); + + /* Get min. value in energyMax array */ + energyMaxMin = energyMax[0] = energyBand[startBand]; + no_enMaxBand[0] = startBand; + posEnergyMaxMin = 0; + for (k = 1; k < maxNEnergyValues; k++) { + energyMax[k] = energyBand[startBand + k]; + no_enMaxBand[k] = startBand + k; + if (energyMaxMin > energyMax[k]) { + energyMaxMin = energyMax[k]; + posEnergyMaxMin = k; + } + } + + for (b = startBand + maxNEnergyValues; b < stopBand; b++) { + if (energyBand[b] > energyMaxMin) { + energyMax[posEnergyMaxMin] = energyBand[b]; + no_enMaxBand[posEnergyMaxMin] = b; + + /* Again, get min. value in energyMax array */ + energyMaxMin = energyMax[0]; + posEnergyMaxMin = 0; + for (k = 1; k < maxNEnergyValues; k++) { + if (energyMaxMin > energyMax[k]) { + energyMaxMin = energyMax[k]; + posEnergyMaxMin = k; + } + } + } + } + /*** End determine 5 highest band-energies ***/ + + /* Get tonality values for 5 highest energies */ + for (e = 0; e < maxNEnergyValues; e++) { + tonalityBand[e] = FL2FXCONST_DBL(0.0f); + for (k = 0; k < noEstPerFrame; k++) { + tonalityBand[e] += quotaMatrix[startIndex + k][no_enMaxBand[e]] >> 1; + } + globalTonality += + tonalityBand[e] >> 2; /* headroom of 2+1 (max. 5 additions) */ + } + + return globalTonality; +} + +/***************************************************************************/ +/*! + + \brief Calculates energy form real and imaginary part of + the QMF subsamples + + \return none + +****************************************************************************/ +LNK_SECTION_CODE_L1 +static void FDKsbrEnc_getEnergyFromCplxQmfData( + FIXP_DBL **RESTRICT energyValues, /*!< the result of the operation */ + FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */ + FIXP_DBL **RESTRICT + imagValues, /*!< the imaginary part of the QMF subsamples */ + INT numberBands, /*!< number of QMF bands */ + INT numberCols, /*!< number of QMF subsamples */ + INT *qmfScale, /*!< sclefactor of QMF subsamples */ + INT *energyScale) /*!< scalefactor of energies */ +{ + int j, k; + int scale; + FIXP_DBL max_val = FL2FXCONST_DBL(0.0f); + + /* Get Scratch buffer */ + C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, 32 * 64 / 2) + + /* Get max possible scaling of QMF data */ + scale = DFRACT_BITS; + for (k = 0; k < numberCols; k++) { + scale = fixMin(scale, fixMin(getScalefactor(realValues[k], numberBands), + getScalefactor(imagValues[k], numberBands))); + } + + /* Tweak scaling stability for zero signal to non-zero signal transitions */ + if (scale >= DFRACT_BITS - 1) { + scale = (FRACT_BITS - 1 - *qmfScale); + } + /* prevent scaling of QMF values to -1.f */ + scale = fixMax(0, scale - 1); + + /* Update QMF scale */ + *qmfScale += scale; + + /* + Calculate energy of each time slot pair, max energy + and shift QMF values as far as possible to the left. + */ + { + FIXP_DBL *nrgValues = tmpNrg; + for (k = 0; k < numberCols; k += 2) { + /* Load band vector addresses of 2 consecutive timeslots */ + FIXP_DBL *RESTRICT r0 = realValues[k]; + FIXP_DBL *RESTRICT i0 = imagValues[k]; + FIXP_DBL *RESTRICT r1 = realValues[k + 1]; + FIXP_DBL *RESTRICT i1 = imagValues[k + 1]; + for (j = 0; j < numberBands; j++) { + FIXP_DBL energy; + FIXP_DBL tr0, tr1, ti0, ti1; + + /* Read QMF values of 2 timeslots */ + tr0 = r0[j]; + tr1 = r1[j]; + ti0 = i0[j]; + ti1 = i1[j]; + + /* Scale QMF Values and Calc Energy average of both timeslots */ + tr0 <<= scale; + ti0 <<= scale; + energy = fPow2AddDiv2(fPow2Div2(tr0), ti0) >> 1; + + tr1 <<= scale; + ti1 <<= scale; + energy += fPow2AddDiv2(fPow2Div2(tr1), ti1) >> 1; + + /* Write timeslot pair energy to scratch */ + *nrgValues++ = energy; + max_val = fixMax(max_val, energy); + + /* Write back scaled QMF values */ + r0[j] = tr0; + r1[j] = tr1; + i0[j] = ti0; + i1[j] = ti1; + } + } + } + /* energyScale: scalefactor energies of current frame */ + *energyScale = + 2 * (*qmfScale) - + 1; /* if qmfScale > 0: nr of right shifts otherwise nr of left shifts */ + + /* Scale timeslot pair energies and write to output buffer */ + scale = CountLeadingBits(max_val); + { + FIXP_DBL *nrgValues = tmpNrg; + for (k = 0; k<numberCols>> 1; k++) { + scaleValues(energyValues[k], nrgValues, numberBands, scale); + nrgValues += numberBands; + } + *energyScale += scale; + } + + /* Free Scratch buffer */ + C_ALLOC_SCRATCH_END(tmpNrg, FIXP_DBL, 32 * 64 / 2) +} + +LNK_SECTION_CODE_L1 +static void FDKsbrEnc_getEnergyFromCplxQmfDataFull( + FIXP_DBL **RESTRICT energyValues, /*!< the result of the operation */ + FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */ + FIXP_DBL **RESTRICT + imagValues, /*!< the imaginary part of the QMF subsamples */ + int numberBands, /*!< number of QMF bands */ + int numberCols, /*!< number of QMF subsamples */ + int *qmfScale, /*!< scalefactor of QMF subsamples */ + int *energyScale) /*!< scalefactor of energies */ +{ + int j, k; + int scale; + FIXP_DBL max_val = FL2FXCONST_DBL(0.0f); + + /* Get Scratch buffer */ + C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, MAX_NRG_SLOTS_LD * 64) + + FDK_ASSERT(numberCols <= MAX_NRG_SLOTS_LD); + FDK_ASSERT(numberBands <= 64); + + /* Get max possible scaling of QMF data */ + scale = DFRACT_BITS; + for (k = 0; k < numberCols; k++) { + scale = fixMin(scale, fixMin(getScalefactor(realValues[k], numberBands), + getScalefactor(imagValues[k], numberBands))); + } + + /* Tweak scaling stability for zero signal to non-zero signal transitions */ + if (scale >= DFRACT_BITS - 1) { + scale = (FRACT_BITS - 1 - *qmfScale); + } + /* prevent scaling of QFM values to -1.f */ + scale = fixMax(0, scale - 1); + + /* Update QMF scale */ + *qmfScale += scale; + + /* + Calculate energy of each time slot pair, max energy + and shift QMF values as far as possible to the left. + */ + { + FIXP_DBL *nrgValues = tmpNrg; + for (k = 0; k < numberCols; k++) { + /* Load band vector addresses of 1 timeslot */ + FIXP_DBL *RESTRICT r0 = realValues[k]; + FIXP_DBL *RESTRICT i0 = imagValues[k]; + for (j = 0; j < numberBands; j++) { + FIXP_DBL energy; + FIXP_DBL tr0, ti0; + + /* Read QMF values of 1 timeslot */ + tr0 = r0[j]; + ti0 = i0[j]; + + /* Scale QMF Values and Calc Energy */ + tr0 <<= scale; + ti0 <<= scale; + energy = fPow2AddDiv2(fPow2Div2(tr0), ti0); + *nrgValues++ = energy; + + max_val = fixMax(max_val, energy); + + /* Write back scaled QMF values */ + r0[j] = tr0; + i0[j] = ti0; + } + } + } + /* energyScale: scalefactor energies of current frame */ + *energyScale = + 2 * (*qmfScale) - + 1; /* if qmfScale > 0: nr of right shifts otherwise nr of left shifts */ + + /* Scale timeslot pair energies and write to output buffer */ + scale = CountLeadingBits(max_val); + { + FIXP_DBL *nrgValues = tmpNrg; + for (k = 0; k < numberCols; k++) { + scaleValues(energyValues[k], nrgValues, numberBands, scale); + nrgValues += numberBands; + } + *energyScale += scale; + } + + /* Free Scratch buffer */ + C_ALLOC_SCRATCH_END(tmpNrg, FIXP_DBL, MAX_NRG_SLOTS_LD * 64) +} + +/***************************************************************************/ +/*! + + \brief Quantisation of the panorama value (balance) + + \return the quantized pan value + +****************************************************************************/ +static INT mapPanorama(INT nrgVal, /*! integer value of the energy */ + INT ampRes, /*! amplitude resolution [1.5/3dB] */ + INT *quantError /*! quantization error of energy val*/ +) { + int i; + INT min_val, val; + UCHAR panIndex; + INT sign; + + sign = nrgVal > 0 ? 1 : -1; + + nrgVal *= sign; + + min_val = FDK_INT_MAX; + panIndex = 0; + for (i = 0; i < maxIndex[ampRes]; i++) { + val = fixp_abs((nrgVal - (INT)panTable[ampRes][i])); + + if (val < min_val) { + min_val = val; + panIndex = i; + } + } + + *quantError = min_val; + + return panTable[ampRes][maxIndex[ampRes] - 1] + + sign * panTable[ampRes][panIndex]; +} + +/***************************************************************************/ +/*! + + \brief Quantisation of the noise floor levels + + \return void + +****************************************************************************/ +static void sbrNoiseFloorLevelsQuantisation( + SCHAR *RESTRICT iNoiseLevels, /*! quantized noise levels */ + FIXP_DBL *RESTRICT + NoiseLevels, /*! the noise levels. Exponent = LD_DATA_SHIFT */ + INT coupling /*! the coupling flag */ +) { + INT i; + INT tmp, dummy; + + /* Quantisation, similar to sfb quant... */ + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + /* tmp = NoiseLevels[i] > (PFLOAT)30.0f ? 30: (INT) (NoiseLevels[i] + + * (PFLOAT)0.5); */ + /* 30>>LD_DATA_SHIFT = 0.46875 */ + if ((FIXP_DBL)NoiseLevels[i] > FL2FXCONST_DBL(0.46875f)) { + tmp = 30; + } else { + /* tmp = (INT)((FIXP_DBL)NoiseLevels[i] + (FL2FXCONST_DBL(0.5f)>>(*/ + /* FRACT_BITS+ */ /* 6-1)));*/ + /* tmp = tmp >> (DFRACT_BITS-1-LD_DATA_SHIFT); */ /* conversion to integer + happens here */ + /* rounding is done by shifting one bit less than necessary to the right, + * adding '1' and then shifting the final bit */ + tmp = ((((INT)NoiseLevels[i]) >> + (DFRACT_BITS - 1 - LD_DATA_SHIFT))); /* conversion to integer */ + if (tmp != 0) tmp += 1; + } + + if (coupling) { + tmp = tmp < -30 ? -30 : tmp; + tmp = mapPanorama(tmp, 1, &dummy); + } + iNoiseLevels[i] = tmp; + } +} + +/***************************************************************************/ +/*! + + \brief Calculation of noise floor for coupling + + \return void + +****************************************************************************/ +static void coupleNoiseFloor( + FIXP_DBL *RESTRICT noise_level_left, /*! noise level left (modified)*/ + FIXP_DBL *RESTRICT noise_level_right /*! noise level right (modified)*/ +) { + FIXP_DBL cmpValLeft, cmpValRight; + INT i; + FIXP_DBL temp1, temp2; + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + /* Calculation of the power function using ld64: + z = x^y; + z' = CalcLd64(z) = y*CalcLd64(x)/64; + z = CalcInvLd64(z'); + */ + cmpValLeft = NOISE_FLOOR_OFFSET_64 - noise_level_left[i]; + cmpValRight = NOISE_FLOOR_OFFSET_64 - noise_level_right[i]; + + if (cmpValRight < FL2FXCONST_DBL(0.0f)) { + temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]); + } else { + temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]); + temp1 = temp1 << (DFRACT_BITS - 1 - LD_DATA_SHIFT - + 1); /* INT to fract conversion of result, if input of + CalcInvLdData is positiv */ + } + + if (cmpValLeft < FL2FXCONST_DBL(0.0f)) { + temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]); + } else { + temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]); + temp2 = temp2 << (DFRACT_BITS - 1 - LD_DATA_SHIFT - + 1); /* INT to fract conversion of result, if input of + CalcInvLdData is positiv */ + } + + if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && + (cmpValRight < FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = + NOISE_FLOOR_OFFSET_64 - + (CalcLdData( + ((temp1 >> 1) + + (temp2 >> 1)))); /* no scaling needed! both values are dfract */ + noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1); + } + + if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && + (cmpValRight >= FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - + (CalcLdData(((temp1 >> 1) + (temp2 >> 1))) + + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1); + } + + if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && + (cmpValRight < FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - + (CalcLdData(((temp1 >> (7 + 1)) + (temp2 >> 1))) + + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = + (CalcLdData(temp2) + FL2FXCONST_DBL(0.109375f)) - CalcLdData(temp1); + } + + if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && + (cmpValRight >= FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - + (CalcLdData(((temp1 >> 1) + (temp2 >> (7 + 1)))) + + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = CalcLdData(temp2) - + (CalcLdData(temp1) + + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + } + } +} + +/***************************************************************************/ +/*! + + \brief Calculation of energy starting in lower band (li) up to upper band +(ui) over slots (start_pos) to (stop_pos) + + \return void + +****************************************************************************/ + +static FIXP_DBL getEnvSfbEnergy( + INT li, /*! lower band */ + INT ui, /*! upper band */ + INT start_pos, /*! start slot */ + INT stop_pos, /*! stop slot */ + INT border_pos, /*! slots scaling border */ + FIXP_DBL **YBuffer, /*! sfb energy buffer */ + INT YBufferSzShift, /*! Energy buffer index scale */ + INT scaleNrg0, /*! scaling of lower slots */ + INT scaleNrg1) /*! scaling of upper slots */ +{ + /* use dynamic scaling for outer energy loop; + energies are critical and every bit is important */ + int sc0, sc1, k, l; + + FIXP_DBL nrgSum, nrg1, nrg2, accu1, accu2; + INT dynScale, dynScale1, dynScale2; + if (ui - li == 0) + dynScale = DFRACT_BITS - 1; + else + dynScale = CalcLdInt(ui - li) >> (DFRACT_BITS - 1 - LD_DATA_SHIFT); + + sc0 = fixMin(scaleNrg0, Y_NRG_SCALE); + sc1 = fixMin(scaleNrg1, Y_NRG_SCALE); + /* dynScale{1,2} is set such that the right shift below is positive */ + dynScale1 = fixMin((scaleNrg0 - sc0), dynScale); + dynScale2 = fixMin((scaleNrg1 - sc1), dynScale); + nrgSum = accu1 = accu2 = (FIXP_DBL)0; + + for (k = li; k < ui; k++) { + nrg1 = nrg2 = (FIXP_DBL)0; + for (l = start_pos; l < border_pos; l++) { + nrg1 += YBuffer[l >> YBufferSzShift][k] >> sc0; + } + for (; l < stop_pos; l++) { + nrg2 += YBuffer[l >> YBufferSzShift][k] >> sc1; + } + accu1 += (nrg1 >> dynScale1); + accu2 += (nrg2 >> dynScale2); + } + /* This shift factor is always positive. See comment above. */ + nrgSum += + (accu1 >> fixMin((scaleNrg0 - sc0 - dynScale1), (DFRACT_BITS - 1))) + + (accu2 >> fixMin((scaleNrg1 - sc1 - dynScale2), (DFRACT_BITS - 1))); + + return nrgSum; +} + +/***************************************************************************/ +/*! + + \brief Energy compensation in missing harmonic mode + + \return void + +****************************************************************************/ +static FIXP_DBL mhLoweringEnergy(FIXP_DBL nrg, INT M) { + /* + Compensating for the fact that we in the decoder map the "average energy to + every QMF band, and use this when we calculate the boost-factor. Since the + mapped energy isn't the average energy but the maximum energy in case of + missing harmonic creation, we will in the boost function calculate that too + much limiting has been applied and hence we will boost the signal although + it isn't called for. Hence we need to compensate for this by lowering the + transmitted energy values for the sines so they will get the correct level + after the boost is applied. + */ + if (M > 2) { + INT tmpScale; + tmpScale = CountLeadingBits(nrg); + nrg <<= tmpScale; + nrg = fMult(nrg, FL2FXCONST_DBL(0.398107267f)); /* The maximum boost + is 1.584893, so the + maximum attenuation + should be + square(1/1.584893) = + 0.398107267 */ + nrg >>= tmpScale; + } else { + if (M > 1) { + nrg >>= 1; + } + } + + return nrg; +} + +/***************************************************************************/ +/*! + + \brief Energy compensation in none missing harmonic mode + + \return void + +****************************************************************************/ +static FIXP_DBL nmhLoweringEnergy(FIXP_DBL nrg, const FIXP_DBL nrgSum, + const INT nrgSum_scale, const INT M) { + if (nrg > FL2FXCONST_DBL(0)) { + int sc = 0; + /* gain = nrgSum / (nrg*(M+1)) */ + FIXP_DBL gain = fMult(fDivNorm(nrgSum, nrg, &sc), GetInvInt(M + 1)); + sc += nrgSum_scale; + + /* reduce nrg if gain smaller 1.f */ + if (!((sc >= 0) && (gain > ((FIXP_DBL)MAXVAL_DBL >> sc)))) { + nrg = fMult(scaleValue(gain, sc), nrg); + } + } + return nrg; +} + +/***************************************************************************/ +/*! + + \brief calculates the envelope values from the energies, depending on + framing and stereo mode + + \return void + +****************************************************************************/ +static void calculateSbrEnvelope( + FIXP_DBL **RESTRICT YBufferLeft, /*! energy buffer left */ + FIXP_DBL **RESTRICT YBufferRight, /*! energy buffer right */ + int *RESTRICT YBufferScaleLeft, /*! scale energy buffer left */ + int *RESTRICT YBufferScaleRight, /*! scale energy buffer right */ + const SBR_FRAME_INFO *frame_info, /*! frame info vector */ + SCHAR *RESTRICT sfb_nrgLeft, /*! sfb energy buffer left */ + SCHAR *RESTRICT sfb_nrgRight, /*! sfb energy buffer right */ + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_ENV_CHANNEL h_sbr, /*! envelope channel handle */ + SBR_STEREO_MODE stereoMode, /*! stereo coding mode */ + INT *maxQuantError, /*! maximum quantization error, for panorama. */ + int YBufferSzShift) /*! Energy buffer index scale */ + +{ + int env, j, m = 0; + INT no_of_bands, start_pos, stop_pos, li, ui; + FREQ_RES freq_res; + + INT ca = 2 - h_sbr->encEnvData.init_sbr_amp_res; + INT oneBitLess = 0; + if (ca == 2) + oneBitLess = + 1; /* LD_DATA_SHIFT => ld64 scaling; one bit less for rounding */ + + INT quantError; + INT nEnvelopes = frame_info->nEnvelopes; + INT short_env = frame_info->shortEnv - 1; + INT timeStep = h_sbr->sbrExtractEnvelope.time_step; + INT commonScale, scaleLeft0, scaleLeft1; + INT scaleRight0 = 0, scaleRight1 = 0; + + commonScale = fixMin(YBufferScaleLeft[0], YBufferScaleLeft[1]); + + if (stereoMode == SBR_COUPLING) { + commonScale = fixMin(commonScale, YBufferScaleRight[0]); + commonScale = fixMin(commonScale, YBufferScaleRight[1]); + } + + commonScale = commonScale - 7; + + scaleLeft0 = YBufferScaleLeft[0] - commonScale; + scaleLeft1 = YBufferScaleLeft[1] - commonScale; + FDK_ASSERT((scaleLeft0 >= 0) && (scaleLeft1 >= 0)); + + if (stereoMode == SBR_COUPLING) { + scaleRight0 = YBufferScaleRight[0] - commonScale; + scaleRight1 = YBufferScaleRight[1] - commonScale; + FDK_ASSERT((scaleRight0 >= 0) && (scaleRight1 >= 0)); + *maxQuantError = 0; + } + + for (env = 0; env < nEnvelopes; env++) { + FIXP_DBL pNrgLeft[32]; + FIXP_DBL pNrgRight[32]; + int envNrg_scale; + FIXP_DBL envNrgLeft = FL2FXCONST_DBL(0.0f); + FIXP_DBL envNrgRight = FL2FXCONST_DBL(0.0f); + int missingHarmonic[32]; + int count[32]; + + start_pos = timeStep * frame_info->borders[env]; + stop_pos = timeStep * frame_info->borders[env + 1]; + freq_res = frame_info->freqRes[env]; + no_of_bands = h_con->nSfb[freq_res]; + envNrg_scale = DFRACT_BITS - fNormz((FIXP_DBL)no_of_bands); + if (env == short_env) { + j = fMax(2, timeStep); /* consider at least 2 QMF slots less for short + envelopes (envelopes just before transients) */ + if ((stop_pos - start_pos - j) > 0) { + stop_pos = stop_pos - j; + } + } + for (j = 0; j < no_of_bands; j++) { + FIXP_DBL nrgLeft = FL2FXCONST_DBL(0.0f); + FIXP_DBL nrgRight = FL2FXCONST_DBL(0.0f); + + li = h_con->freqBandTable[freq_res][j]; + ui = h_con->freqBandTable[freq_res][j + 1]; + + if (freq_res == FREQ_RES_HIGH) { + if (j == 0 && ui - li > 1) { + li++; + } + } else { + if (j == 0 && ui - li > 2) { + li++; + } + } + + /* + Find out whether a sine will be missing in the scale-factor + band that we're currently processing. + */ + missingHarmonic[j] = 0; + + if (h_sbr->encEnvData.addHarmonicFlag) { + if (freq_res == FREQ_RES_HIGH) { + if (h_sbr->encEnvData + .addHarmonic[j]) { /*A missing sine in the current band*/ + missingHarmonic[j] = 1; + } + } else { + INT i; + INT startBandHigh = 0; + INT stopBandHigh = 0; + + while (h_con->freqBandTable[FREQ_RES_HIGH][startBandHigh] < + h_con->freqBandTable[FREQ_RES_LOW][j]) + startBandHigh++; + while (h_con->freqBandTable[FREQ_RES_HIGH][stopBandHigh] < + h_con->freqBandTable[FREQ_RES_LOW][j + 1]) + stopBandHigh++; + + for (i = startBandHigh; i < stopBandHigh; i++) { + if (h_sbr->encEnvData.addHarmonic[i]) { + missingHarmonic[j] = 1; + } + } + } + } + + /* + If a sine is missing in a scalefactorband, with more than one qmf + channel use the nrg from the channel with the largest nrg rather than + the mean. Compensate for the boost calculation in the decdoder. + */ + int border_pos = + fixMin(stop_pos, h_sbr->sbrExtractEnvelope.YBufferWriteOffset + << YBufferSzShift); + + if (missingHarmonic[j]) { + int k; + count[j] = stop_pos - start_pos; + nrgLeft = FL2FXCONST_DBL(0.0f); + + for (k = li; k < ui; k++) { + FIXP_DBL tmpNrg; + tmpNrg = getEnvSfbEnergy(k, k + 1, start_pos, stop_pos, border_pos, + YBufferLeft, YBufferSzShift, scaleLeft0, + scaleLeft1); + + nrgLeft = fixMax(nrgLeft, tmpNrg); + } + + /* Energy lowering compensation */ + nrgLeft = mhLoweringEnergy(nrgLeft, ui - li); + + if (stereoMode == SBR_COUPLING) { + nrgRight = FL2FXCONST_DBL(0.0f); + + for (k = li; k < ui; k++) { + FIXP_DBL tmpNrg; + tmpNrg = getEnvSfbEnergy(k, k + 1, start_pos, stop_pos, border_pos, + YBufferRight, YBufferSzShift, scaleRight0, + scaleRight1); + + nrgRight = fixMax(nrgRight, tmpNrg); + } + + /* Energy lowering compensation */ + nrgRight = mhLoweringEnergy(nrgRight, ui - li); + } + } /* end missingHarmonic */ + else { + count[j] = (stop_pos - start_pos) * (ui - li); + + nrgLeft = getEnvSfbEnergy(li, ui, start_pos, stop_pos, border_pos, + YBufferLeft, YBufferSzShift, scaleLeft0, + scaleLeft1); + + if (stereoMode == SBR_COUPLING) { + nrgRight = getEnvSfbEnergy(li, ui, start_pos, stop_pos, border_pos, + YBufferRight, YBufferSzShift, scaleRight0, + scaleRight1); + } + } /* !missingHarmonic */ + + /* save energies */ + pNrgLeft[j] = nrgLeft; + pNrgRight[j] = nrgRight; + envNrgLeft += (nrgLeft >> envNrg_scale); + envNrgRight += (nrgRight >> envNrg_scale); + } /* j */ + + for (j = 0; j < no_of_bands; j++) { + FIXP_DBL nrgLeft2 = FL2FXCONST_DBL(0.0f); + FIXP_DBL nrgLeft = pNrgLeft[j]; + FIXP_DBL nrgRight = pNrgRight[j]; + + /* None missing harmonic Energy lowering compensation */ + if (!missingHarmonic[j] && h_sbr->fLevelProtect) { + /* in case of missing energy in base band, + reduce reference energy to prevent overflows in decoder output */ + nrgLeft = + nmhLoweringEnergy(nrgLeft, envNrgLeft, envNrg_scale, no_of_bands); + if (stereoMode == SBR_COUPLING) { + nrgRight = nmhLoweringEnergy(nrgRight, envNrgRight, envNrg_scale, + no_of_bands); + } + } + + if (stereoMode == SBR_COUPLING) { + /* calc operation later with log */ + nrgLeft2 = nrgLeft; + nrgLeft = (nrgRight + nrgLeft) >> 1; + } + + /* nrgLeft = f20_log2(nrgLeft / (PFLOAT)(count * 64))+(PFLOAT)44; */ + /* If nrgLeft == 0 then the Log calculations below do fail. */ + if (nrgLeft > FL2FXCONST_DBL(0.0f)) { + FIXP_DBL tmp0, tmp1, tmp2, tmp3; + INT tmpScale; + + tmpScale = CountLeadingBits(nrgLeft); + nrgLeft = nrgLeft << tmpScale; + + tmp0 = CalcLdData(nrgLeft); /* scaled by 1/64 */ + tmp1 = ((FIXP_DBL)(commonScale + tmpScale)) + << (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1); /* scaled by 1/64 */ + tmp2 = ((FIXP_DBL)(count[j] * 64)) << (DFRACT_BITS - 1 - 14 - 1); + tmp2 = CalcLdData(tmp2); /* scaled by 1/64 */ + tmp3 = FL2FXCONST_DBL(0.6875f - 0.21875f - 0.015625f) >> + 1; /* scaled by 1/64 */ + + nrgLeft = ((tmp0 - tmp2) >> 1) + (tmp3 - tmp1); + } else { + nrgLeft = FL2FXCONST_DBL(-1.0f); + } + + /* ld64 to integer conversion */ + nrgLeft = fixMin(fixMax(nrgLeft, FL2FXCONST_DBL(0.0f)), + (FL2FXCONST_DBL(0.5f) >> oneBitLess)); + nrgLeft = (FIXP_DBL)(LONG)nrgLeft >> + (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1 - oneBitLess - 1); + sfb_nrgLeft[m] = ((INT)nrgLeft + 1) >> 1; /* rounding */ + + if (stereoMode == SBR_COUPLING) { + FIXP_DBL scaleFract; + int sc0, sc1; + + nrgLeft2 = fixMax((FIXP_DBL)0x1, nrgLeft2); + nrgRight = fixMax((FIXP_DBL)0x1, nrgRight); + + sc0 = CountLeadingBits(nrgLeft2); + sc1 = CountLeadingBits(nrgRight); + + scaleFract = + ((FIXP_DBL)(sc0 - sc1)) + << (DFRACT_BITS - 1 - + LD_DATA_SHIFT); /* scale value in ld64 representation */ + nrgRight = CalcLdData(nrgLeft2 << sc0) - CalcLdData(nrgRight << sc1) - + scaleFract; + + /* ld64 to integer conversion */ + nrgRight = (FIXP_DBL)(LONG)(nrgRight) >> + (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1 - oneBitLess); + nrgRight = (nrgRight + (FIXP_DBL)1) >> 1; /* rounding */ + + sfb_nrgRight[m] = mapPanorama( + nrgRight, h_sbr->encEnvData.init_sbr_amp_res, &quantError); + + *maxQuantError = fixMax(quantError, *maxQuantError); + } + + m++; + } /* j */ + + /* Do energy compensation for sines that are present in two + QMF-bands in the original, but will only occur in one band in + the decoder due to the synthetic sine coding.*/ + if (h_con->useParametricCoding) { + m -= no_of_bands; + for (j = 0; j < no_of_bands; j++) { + if (freq_res == FREQ_RES_HIGH && + h_sbr->sbrExtractEnvelope.envelopeCompensation[j]) { + sfb_nrgLeft[m] -= + (ca * + fixp_abs( + (INT)h_sbr->sbrExtractEnvelope.envelopeCompensation[j])); + } + sfb_nrgLeft[m] = fixMax(0, sfb_nrgLeft[m]); + m++; + } + } /* useParametricCoding */ + + } /* env loop */ +} + +/***************************************************************************/ +/*! + + \brief calculates the noise floor and the envelope values from the + energies, depending on framing and stereo mode + + FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the + envelope and the noise floor. The function includes the following processes: + + -Analysis subband filtering. + -Encoding SA and pan parameters (if enabled). + -Transient detection. + +****************************************************************************/ + +LNK_SECTION_CODE_L1 +void FDKsbrEnc_extractSbrEnvelope1( + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, HANDLE_ENV_CHANNEL hEnvChan, + HANDLE_COMMON_DATA hCmonData, SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData) { + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope; + + if (sbrExtrEnv->YBufferSzShift == 0) + FDKsbrEnc_getEnergyFromCplxQmfDataFull( + &sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset], + sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset, + sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset, h_con->noQmfBands, + sbrExtrEnv->no_cols, &hEnvChan->qmfScale, &sbrExtrEnv->YBufferScale[1]); + else + FDKsbrEnc_getEnergyFromCplxQmfData( + &sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset], + sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset, + sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset, h_con->noQmfBands, + sbrExtrEnv->no_cols, &hEnvChan->qmfScale, &sbrExtrEnv->YBufferScale[1]); + + /* Energie values = + * sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset][x].floatVal * + * (1<<2*7-sbrExtrEnv->YBufferScale[1]) */ + + /* + Precalculation of Tonality Quotas COEFF Transform OK + */ + FDKsbrEnc_CalculateTonalityQuotas( + &hEnvChan->TonCorr, sbrExtrEnv->rBuffer, sbrExtrEnv->iBuffer, + h_con->freqBandTable[HI][h_con->nSfb[HI]], hEnvChan->qmfScale); + + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + FIXP_DBL tonality = FDKsbrEnc_GetTonality( + hEnvChan->TonCorr.quotaMatrix, + hEnvChan->TonCorr.numberOfEstimatesPerFrame, + hEnvChan->TonCorr.startIndexMatrix, + sbrExtrEnv->YBuffer + sbrExtrEnv->YBufferWriteOffset, + h_con->freqBandTable[HI][0] + 1, h_con->noQmfBands, + sbrExtrEnv->no_cols); + + hEnvChan->encEnvData.ton_HF[1] = hEnvChan->encEnvData.ton_HF[0]; + hEnvChan->encEnvData.ton_HF[0] = tonality; + + /* tonality is scaled by 2^19/0.524288f (fract part of RELAXATION) */ + hEnvChan->encEnvData.global_tonality = + (hEnvChan->encEnvData.ton_HF[0] >> 1) + + (hEnvChan->encEnvData.ton_HF[1] >> 1); + } + + /* + Transient detection COEFF Transform OK + */ + + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + FDKsbrEnc_fastTransientDetect(&hEnvChan->sbrFastTransientDetector, + sbrExtrEnv->YBuffer, sbrExtrEnv->YBufferScale, + sbrExtrEnv->YBufferWriteOffset, + eData->transient_info); + + } else { + FDKsbrEnc_transientDetect( + &hEnvChan->sbrTransientDetector, sbrExtrEnv->YBuffer, + sbrExtrEnv->YBufferScale, eData->transient_info, + sbrExtrEnv->YBufferWriteOffset, sbrExtrEnv->YBufferSzShift, + sbrExtrEnv->time_step, hEnvChan->SbrEnvFrame.frameMiddleSlot); + } + + /* + Generate flags for 2 env in a FIXFIX-frame. + Remove this function to get always 1 env per FIXFIX-frame. + */ + + /* + frame Splitter COEFF Transform OK + */ + FDKsbrEnc_frameSplitter( + sbrExtrEnv->YBuffer, sbrExtrEnv->YBufferScale, + &hEnvChan->sbrTransientDetector, h_con->freqBandTable[1], + eData->transient_info, sbrExtrEnv->YBufferWriteOffset, + sbrExtrEnv->YBufferSzShift, h_con->nSfb[1], sbrExtrEnv->time_step, + sbrExtrEnv->no_cols, &hEnvChan->encEnvData.global_tonality); +} + +/***************************************************************************/ +/*! + + \brief calculates the noise floor and the envelope values from the + energies, depending on framing and stereo mode + + FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the + envelope and the noise floor. The function includes the following processes: + + -Determine time/frequency division of current granule. + -Sending transient info to bitstream. + -Set amp_res to 1.5 dB if the current frame contains only one envelope. + -Lock dynamic bandwidth frequency change if the next envelope not starts on a + frame boundary. + -MDCT transposer (needed to detect where harmonics will be missing). + -Spectrum Estimation (used for pulse train and missing harmonics detection). + -Pulse train detection. + -Inverse Filtering detection. + -Waveform Coding. + -Missing Harmonics detection. + -Extract envelope of current frame. + -Noise floor estimation. + -Noise floor quantisation and coding. + -Encode envelope of current frame. + -Send the encoded data to the bitstream. + -Write to bitstream. + +****************************************************************************/ + +LNK_SECTION_CODE_L1 +void FDKsbrEnc_extractSbrEnvelope2( + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, HANDLE_ENV_CHANNEL h_envChan0, + HANDLE_ENV_CHANNEL h_envChan1, HANDLE_COMMON_DATA hCmonData, + SBR_ENV_TEMP_DATA *eData, SBR_FRAME_TEMP_DATA *fData, int clearOutput) { + HANDLE_ENV_CHANNEL h_envChan[MAX_NUM_CHANNELS] = {h_envChan0, h_envChan1}; + int ch, i, j, c, YSzShift = h_envChan[0]->sbrExtractEnvelope.YBufferSzShift; + + SBR_STEREO_MODE stereoMode = h_con->stereoMode; + int nChannels = h_con->nChannels; + FDK_ASSERT(nChannels <= MAX_NUM_CHANNELS); + const int *v_tuning; + static const int v_tuningHEAAC[6] = {0, 2, 4, 0, 0, 0}; + + static const int v_tuningELD[6] = {0, 2, 3, 0, 0, 0}; + + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) + v_tuning = v_tuningELD; + else + v_tuning = v_tuningHEAAC; + + /* + Select stereo mode. + */ + if (stereoMode == SBR_COUPLING) { + if (eData[0].transient_info[1] && eData[1].transient_info[1]) { + eData[0].transient_info[0] = + fixMin(eData[1].transient_info[0], eData[0].transient_info[0]); + eData[1].transient_info[0] = eData[0].transient_info[0]; + } else { + if (eData[0].transient_info[1] && !eData[1].transient_info[1]) { + eData[1].transient_info[0] = eData[0].transient_info[0]; + } else { + if (!eData[0].transient_info[1] && eData[1].transient_info[1]) + eData[0].transient_info[0] = eData[1].transient_info[0]; + else { + eData[0].transient_info[0] = + fixMax(eData[1].transient_info[0], eData[0].transient_info[0]); + eData[1].transient_info[0] = eData[0].transient_info[0]; + } + } + } + } + + /* + Determine time/frequency division of current granule + */ + eData[0].frame_info = FDKsbrEnc_frameInfoGenerator( + &h_envChan[0]->SbrEnvFrame, eData[0].transient_info, + sbrBitstreamData->rightBorderFIX, + h_envChan[0]->sbrExtractEnvelope.pre_transient_info, + h_envChan[0]->encEnvData.ldGrid, v_tuning); + + h_envChan[0]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid; + + /* AAC LD patch for transient prediction */ + if (h_envChan[0]->encEnvData.ldGrid && eData[0].transient_info[2]) { + /* if next frame will start with transient, set shortEnv to + * numEnvelopes(shortend Envelope = shortEnv-1)*/ + h_envChan[0]->SbrEnvFrame.SbrFrameInfo.shortEnv = + h_envChan[0]->SbrEnvFrame.SbrFrameInfo.nEnvelopes; + } + + switch (stereoMode) { + case SBR_LEFT_RIGHT: + case SBR_SWITCH_LRC: + eData[1].frame_info = FDKsbrEnc_frameInfoGenerator( + &h_envChan[1]->SbrEnvFrame, eData[1].transient_info, + sbrBitstreamData->rightBorderFIX, + h_envChan[1]->sbrExtractEnvelope.pre_transient_info, + h_envChan[1]->encEnvData.ldGrid, v_tuning); + + h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[1]->SbrEnvFrame.SbrGrid; + + if (h_envChan[1]->encEnvData.ldGrid && eData[1].transient_info[2]) { + /* if next frame will start with transient, set shortEnv to + * numEnvelopes(shortend Envelope = shortEnv-1)*/ + h_envChan[1]->SbrEnvFrame.SbrFrameInfo.shortEnv = + h_envChan[1]->SbrEnvFrame.SbrFrameInfo.nEnvelopes; + } + + /* compare left and right frame_infos */ + if (eData[0].frame_info->nEnvelopes != eData[1].frame_info->nEnvelopes) { + stereoMode = SBR_LEFT_RIGHT; + } else { + for (i = 0; i < eData[0].frame_info->nEnvelopes + 1; i++) { + if (eData[0].frame_info->borders[i] != + eData[1].frame_info->borders[i]) { + stereoMode = SBR_LEFT_RIGHT; + break; + } + } + for (i = 0; i < eData[0].frame_info->nEnvelopes; i++) { + if (eData[0].frame_info->freqRes[i] != + eData[1].frame_info->freqRes[i]) { + stereoMode = SBR_LEFT_RIGHT; + break; + } + } + if (eData[0].frame_info->shortEnv != eData[1].frame_info->shortEnv) { + stereoMode = SBR_LEFT_RIGHT; + } + } + break; + case SBR_COUPLING: + eData[1].frame_info = eData[0].frame_info; + h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid; + break; + case SBR_MONO: + /* nothing to do */ + break; + default: + FDK_ASSERT(0); + } + + for (ch = 0; ch < nChannels; ch++) { + HANDLE_ENV_CHANNEL hEnvChan = h_envChan[ch]; + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope; + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + + /* + Send transient info to bitstream and store for next call + */ + sbrExtrEnv->pre_transient_info[0] = ed->transient_info[0]; /* tran_pos */ + sbrExtrEnv->pre_transient_info[1] = ed->transient_info[1]; /* tran_flag */ + hEnvChan->encEnvData.noOfEnvelopes = ed->nEnvelopes = + ed->frame_info->nEnvelopes; /* number of envelopes of current frame */ + + /* + Check if the current frame is divided into one envelope only. If so, set + the amplitude resolution to 1.5 dB, otherwise may set back to chosen value + */ + if ((hEnvChan->encEnvData.hSbrBSGrid->frameClass == FIXFIX) && + (ed->nEnvelopes == 1)) { + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + /* Note: global_tonaliy_float_value == + ((float)hEnvChan->encEnvData.global_tonality/((INT64)(1)<<(31-(19+2)))/0.524288*(2.0/3.0))); + threshold_float_value == + ((float)h_con->thresholdAmpResFF_m/((INT64)(1)<<(31-(h_con->thresholdAmpResFF_e)))/0.524288*(2.0/3.0))); + */ + /* decision of SBR_AMP_RES */ + if (fIsLessThan(/* global_tonality > threshold ? */ + h_con->thresholdAmpResFF_m, h_con->thresholdAmpResFF_e, + hEnvChan->encEnvData.global_tonality, + RELAXATION_SHIFT + 2)) { + hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5; + } else { + hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_3_0; + } + } else + hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5; + + if (hEnvChan->encEnvData.currentAmpResFF != + hEnvChan->encEnvData.init_sbr_amp_res) { + FDKsbrEnc_InitSbrHuffmanTables( + &hEnvChan->encEnvData, &hEnvChan->sbrCodeEnvelope, + &hEnvChan->sbrCodeNoiseFloor, hEnvChan->encEnvData.currentAmpResFF); + } + } else { + if (sbrHeaderData->sbr_amp_res != hEnvChan->encEnvData.init_sbr_amp_res) { + FDKsbrEnc_InitSbrHuffmanTables( + &hEnvChan->encEnvData, &hEnvChan->sbrCodeEnvelope, + &hEnvChan->sbrCodeNoiseFloor, sbrHeaderData->sbr_amp_res); + } + } + + if (!clearOutput) { + /* + Tonality correction parameter extraction (inverse filtering level, noise + floor additional sines). + */ + FDKsbrEnc_TonCorrParamExtr( + &hEnvChan->TonCorr, hEnvChan->encEnvData.sbr_invf_mode_vec, + ed->noiseFloor, &hEnvChan->encEnvData.addHarmonicFlag, + hEnvChan->encEnvData.addHarmonic, sbrExtrEnv->envelopeCompensation, + ed->frame_info, ed->transient_info, h_con->freqBandTable[HI], + h_con->nSfb[HI], hEnvChan->encEnvData.sbr_xpos_mode, + h_con->sbrSyntaxFlags); + } + + /* Low energy in low band fix */ + if (hEnvChan->sbrTransientDetector.prevLowBandEnergy < + hEnvChan->sbrTransientDetector.prevHighBandEnergy && + hEnvChan->sbrTransientDetector.prevHighBandEnergy > FL2FX_DBL(0.03) + /* The fix needs the non-fast transient detector running. + It sets prevLowBandEnergy and prevHighBandEnergy. */ + && !(h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY)) { + hEnvChan->fLevelProtect = 1; + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + hEnvChan->encEnvData.sbr_invf_mode_vec[i] = INVF_HIGH_LEVEL; + } else { + hEnvChan->fLevelProtect = 0; + } + + hEnvChan->encEnvData.sbr_invf_mode = + hEnvChan->encEnvData.sbr_invf_mode_vec[0]; + + hEnvChan->encEnvData.noOfnoisebands = + hEnvChan->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + } /* ch */ + + /* + Save number of scf bands per envelope + */ + for (ch = 0; ch < nChannels; ch++) { + for (i = 0; i < eData[ch].nEnvelopes; i++) { + h_envChan[ch]->encEnvData.noScfBands[i] = + (eData[ch].frame_info->freqRes[i] == FREQ_RES_HIGH + ? h_con->nSfb[FREQ_RES_HIGH] + : h_con->nSfb[FREQ_RES_LOW]); + } + } + + /* + Extract envelope of current frame. + */ + switch (stereoMode) { + case SBR_MONO: + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, h_con, + h_envChan[0], SBR_MONO, NULL, YSzShift); + break; + case SBR_LEFT_RIGHT: + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, h_con, + h_envChan[0], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope(h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL, + eData[1].frame_info, eData[1].sfb_nrg, NULL, h_con, + h_envChan[1], SBR_MONO, NULL, YSzShift); + break; + case SBR_COUPLING: + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, + h_envChan[1]->sbrExtractEnvelope.YBuffer, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, + eData[0].frame_info, eData[0].sfb_nrg, + eData[1].sfb_nrg, h_con, h_envChan[0], SBR_COUPLING, + &fData->maxQuantError, YSzShift); + break; + case SBR_SWITCH_LRC: + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, h_con, + h_envChan[0], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope(h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL, + eData[1].frame_info, eData[1].sfb_nrg, NULL, h_con, + h_envChan[1], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, + h_envChan[1]->sbrExtractEnvelope.YBuffer, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, + eData[0].frame_info, eData[0].sfb_nrg_coupling, + eData[1].sfb_nrg_coupling, h_con, h_envChan[0], + SBR_COUPLING, &fData->maxQuantError, YSzShift); + break; + } + + /* + Noise floor quantisation and coding. + */ + + switch (stereoMode) { + case SBR_MONO: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, + 0); + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + break; + case SBR_LEFT_RIGHT: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, + 0); + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level, eData[1].noiseFloor, + 0); + + FDKsbrEnc_codeEnvelope(eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 0, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + break; + + case SBR_COUPLING: + coupleNoiseFloor(eData[0].noiseFloor, eData[1].noiseFloor); + + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, + 0); + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 1, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level, eData[1].noiseFloor, + 1); + + FDKsbrEnc_codeEnvelope(eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 1, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1, + sbrBitstreamData->HeaderActive); + + break; + case SBR_SWITCH_LRC: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, + 0); + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level, eData[1].noiseFloor, + 0); + coupleNoiseFloor(eData[0].noiseFloor, eData[1].noiseFloor); + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level_coupling, + eData[0].noiseFloor, 0); + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level_coupling, + eData[1].noiseFloor, 1); + break; + } + + /* + Encode envelope of current frame. + */ + switch (stereoMode) { + case SBR_MONO: + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + FDKsbrEnc_codeEnvelope( + eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + break; + case SBR_LEFT_RIGHT: + sbrHeaderData->coupling = 0; + + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + + FDKsbrEnc_codeEnvelope( + eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope( + eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, h_envChan[1]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[1].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + break; + case SBR_COUPLING: + sbrHeaderData->coupling = 1; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + + FDKsbrEnc_codeEnvelope( + eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope( + eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, h_envChan[1]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[1].frame_info->nEnvelopes, 1, + sbrBitstreamData->HeaderActive); + break; + case SBR_SWITCH_LRC: { + INT payloadbitsLR; + INT payloadbitsCOUPLING; + + SCHAR sfbNrgPrevTemp[MAX_NUM_CHANNELS][MAX_FREQ_COEFFS]; + SCHAR noisePrevTemp[MAX_NUM_CHANNELS][MAX_NUM_NOISE_COEFFS]; + INT upDateNrgTemp[MAX_NUM_CHANNELS]; + INT upDateNoiseTemp[MAX_NUM_CHANNELS]; + INT domainVecTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES]; + INT domainVecNoiseTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES]; + + INT tempFlagRight = 0; + INT tempFlagLeft = 0; + + /* + Store previous values, in order to be able to "undo" what is being + done. + */ + + for (ch = 0; ch < nChannels; ch++) { + FDKmemcpy(sfbNrgPrevTemp[ch], + h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev, + MAX_FREQ_COEFFS * sizeof(SCHAR)); + + FDKmemcpy(noisePrevTemp[ch], + h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev, + MAX_NUM_NOISE_COEFFS * sizeof(SCHAR)); + + upDateNrgTemp[ch] = h_envChan[ch]->sbrCodeEnvelope.upDate; + upDateNoiseTemp[ch] = h_envChan[ch]->sbrCodeNoiseFloor.upDate; + + /* + forbid time coding in the first envelope in case of a different + previous stereomode + */ + if (sbrHeaderData->prev_coupling) { + h_envChan[ch]->sbrCodeEnvelope.upDate = 0; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0; + } + } /* ch */ + + /* + Code ordinary Left/Right stereo + */ + FDKsbrEnc_codeEnvelope(eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, 0, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope(eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, 0, + eData[1].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + + c = 0; + for (i = 0; i < eData[0].nEnvelopes; i++) { + for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++) { + h_envChan[0]->encEnvData.ienvelope[i][j] = eData[0].sfb_nrg[c]; + h_envChan[1]->encEnvData.ienvelope[i][j] = eData[1].sfb_nrg[c]; + c++; + } + } + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[0]->encEnvData.sbr_noise_levels[i] = eData[0].noise_level[i]; + + FDKsbrEnc_codeEnvelope(eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 0, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[1]->encEnvData.sbr_noise_levels[i] = eData[1].noise_level[i]; + + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + + payloadbitsLR = FDKsbrEnc_CountSbrChannelPairElement( + sbrHeaderData, hParametricStereo, sbrBitstreamData, + &h_envChan[0]->encEnvData, &h_envChan[1]->encEnvData, hCmonData, + h_con->sbrSyntaxFlags); + + /* + swap saved stored with current values + */ + for (ch = 0; ch < nChannels; ch++) { + INT itmp; + for (i = 0; i < MAX_FREQ_COEFFS; i++) { + /* + swap sfb energies + */ + itmp = h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev[i]; + h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev[i] = + sfbNrgPrevTemp[ch][i]; + sfbNrgPrevTemp[ch][i] = itmp; + } + for (i = 0; i < MAX_NUM_NOISE_COEFFS; i++) { + /* + swap noise energies + */ + itmp = h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev[i]; + h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev[i] = + noisePrevTemp[ch][i]; + noisePrevTemp[ch][i] = itmp; + } + /* swap update flags */ + itmp = h_envChan[ch]->sbrCodeEnvelope.upDate; + h_envChan[ch]->sbrCodeEnvelope.upDate = upDateNrgTemp[ch]; + upDateNrgTemp[ch] = itmp; + + itmp = h_envChan[ch]->sbrCodeNoiseFloor.upDate; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = upDateNoiseTemp[ch]; + upDateNoiseTemp[ch] = itmp; + + /* + save domain vecs + */ + FDKmemcpy(domainVecTemp[ch], h_envChan[ch]->encEnvData.domain_vec, + sizeof(INT) * MAX_ENVELOPES); + FDKmemcpy(domainVecNoiseTemp[ch], + h_envChan[ch]->encEnvData.domain_vec_noise, + sizeof(INT) * MAX_ENVELOPES); + + /* + forbid time coding in the first envelope in case of a different + previous stereomode + */ + + if (!sbrHeaderData->prev_coupling) { + h_envChan[ch]->sbrCodeEnvelope.upDate = 0; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0; + } + } /* ch */ + + /* + Coupling + */ + + FDKsbrEnc_codeEnvelope( + eData[0].sfb_nrg_coupling, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, h_envChan[0]->encEnvData.domain_vec, + 1, eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + + FDKsbrEnc_codeEnvelope( + eData[1].sfb_nrg_coupling, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, h_envChan[1]->encEnvData.domain_vec, + 1, eData[1].frame_info->nEnvelopes, 1, + sbrBitstreamData->HeaderActive); + + c = 0; + for (i = 0; i < eData[0].nEnvelopes; i++) { + for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++) { + h_envChan[0]->encEnvData.ienvelope[i][j] = + eData[0].sfb_nrg_coupling[c]; + h_envChan[1]->encEnvData.ienvelope[i][j] = + eData[1].sfb_nrg_coupling[c]; + c++; + } + } + + FDKsbrEnc_codeEnvelope(eData[0].noise_level_coupling, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 1, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[0]->encEnvData.sbr_noise_levels[i] = + eData[0].noise_level_coupling[i]; + + FDKsbrEnc_codeEnvelope(eData[1].noise_level_coupling, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 1, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[1]->encEnvData.sbr_noise_levels[i] = + eData[1].noise_level_coupling[i]; + + sbrHeaderData->coupling = 1; + + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + + tempFlagLeft = h_envChan[0]->encEnvData.addHarmonicFlag; + tempFlagRight = h_envChan[1]->encEnvData.addHarmonicFlag; + + payloadbitsCOUPLING = FDKsbrEnc_CountSbrChannelPairElement( + sbrHeaderData, hParametricStereo, sbrBitstreamData, + &h_envChan[0]->encEnvData, &h_envChan[1]->encEnvData, hCmonData, + h_con->sbrSyntaxFlags); + + h_envChan[0]->encEnvData.addHarmonicFlag = tempFlagLeft; + h_envChan[1]->encEnvData.addHarmonicFlag = tempFlagRight; + + if (payloadbitsCOUPLING < payloadbitsLR) { + /* + copy coded coupling envelope and noise data to l/r + */ + for (ch = 0; ch < nChannels; ch++) { + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + FDKmemcpy(ed->sfb_nrg, ed->sfb_nrg_coupling, + MAX_NUM_ENVELOPE_VALUES * sizeof(SCHAR)); + FDKmemcpy(ed->noise_level, ed->noise_level_coupling, + MAX_NUM_NOISE_VALUES * sizeof(SCHAR)); + } + + sbrHeaderData->coupling = 1; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + } else { + /* + restore saved l/r items + */ + for (ch = 0; ch < nChannels; ch++) { + FDKmemcpy(h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev, + sfbNrgPrevTemp[ch], MAX_FREQ_COEFFS * sizeof(SCHAR)); + + h_envChan[ch]->sbrCodeEnvelope.upDate = upDateNrgTemp[ch]; + + FDKmemcpy(h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev, + noisePrevTemp[ch], MAX_NUM_NOISE_COEFFS * sizeof(SCHAR)); + + FDKmemcpy(h_envChan[ch]->encEnvData.domain_vec, domainVecTemp[ch], + sizeof(INT) * MAX_ENVELOPES); + FDKmemcpy(h_envChan[ch]->encEnvData.domain_vec_noise, + domainVecNoiseTemp[ch], sizeof(INT) * MAX_ENVELOPES); + + h_envChan[ch]->sbrCodeNoiseFloor.upDate = upDateNoiseTemp[ch]; + } + + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + } + } break; + } /* switch */ + + /* tell the envelope encoders how long it has been, since we last sent + a frame starting with a dF-coded envelope */ + if (stereoMode == SBR_MONO) { + if (h_envChan[0]->encEnvData.domain_vec[0] == TIME) + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++; + else + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + } else { + if (h_envChan[0]->encEnvData.domain_vec[0] == TIME || + h_envChan[1]->encEnvData.domain_vec[0] == TIME) { + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++; + h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac++; + } else { + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + } + } + + /* + Send the encoded data to the bitstream + */ + for (ch = 0; ch < nChannels; ch++) { + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + c = 0; + for (i = 0; i < ed->nEnvelopes; i++) { + for (j = 0; j < h_envChan[ch]->encEnvData.noScfBands[i]; j++) { + h_envChan[ch]->encEnvData.ienvelope[i][j] = ed->sfb_nrg[c]; + + c++; + } + } + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + h_envChan[ch]->encEnvData.sbr_noise_levels[i] = ed->noise_level[i]; + } + } /* ch */ + + /* + Write bitstream + */ + if (nChannels == 2) { + FDKsbrEnc_WriteEnvChannelPairElement( + sbrHeaderData, hParametricStereo, sbrBitstreamData, + &h_envChan[0]->encEnvData, &h_envChan[1]->encEnvData, hCmonData, + h_con->sbrSyntaxFlags); + } else { + FDKsbrEnc_WriteEnvSingleChannelElement( + sbrHeaderData, hParametricStereo, sbrBitstreamData, + &h_envChan[0]->encEnvData, hCmonData, h_con->sbrSyntaxFlags); + } + + /* + * Update buffers. + */ + for (ch = 0; ch < nChannels; ch++) { + int YBufferLength = h_envChan[ch]->sbrExtractEnvelope.no_cols >> + h_envChan[ch]->sbrExtractEnvelope.YBufferSzShift; + for (i = 0; i < h_envChan[ch]->sbrExtractEnvelope.YBufferWriteOffset; i++) { + FDKmemcpy(h_envChan[ch]->sbrExtractEnvelope.YBuffer[i], + h_envChan[ch]->sbrExtractEnvelope.YBuffer[i + YBufferLength], + sizeof(FIXP_DBL) * 64); + } + h_envChan[ch]->sbrExtractEnvelope.YBufferScale[0] = + h_envChan[ch]->sbrExtractEnvelope.YBufferScale[1]; + } + + sbrHeaderData->prev_coupling = sbrHeaderData->coupling; +} + +/***************************************************************************/ +/*! + + \brief creates an envelope extractor handle + + \return error status + +****************************************************************************/ +INT FDKsbrEnc_CreateExtractSbrEnvelope(HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + INT channel, INT chInEl, + UCHAR *dynamic_RAM) { + INT i; + FIXP_DBL *rBuffer, *iBuffer; + INT n; + FIXP_DBL *YBufferDyn; + + FDKmemclear(hSbrCut, sizeof(SBR_EXTRACT_ENVELOPE)); + + if (NULL == (hSbrCut->p_YBuffer = GetRam_Sbr_envYBuffer(channel))) { + goto bail; + } + + for (i = 0; i < (32 >> 1); i++) { + hSbrCut->YBuffer[i] = hSbrCut->p_YBuffer + (i * 64); + } + YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM); + for (n = 0; i < 32; i++, n++) { + hSbrCut->YBuffer[i] = YBufferDyn + (n * 64); + } + + rBuffer = GetRam_Sbr_envRBuffer(0, dynamic_RAM); + iBuffer = GetRam_Sbr_envIBuffer(0, dynamic_RAM); + + for (i = 0; i < 32; i++) { + hSbrCut->rBuffer[i] = rBuffer + (i * 64); + hSbrCut->iBuffer[i] = iBuffer + (i * 64); + } + + return 0; + +bail: + FDKsbrEnc_deleteExtractSbrEnvelope(hSbrCut); + + return -1; +} + +/***************************************************************************/ +/*! + + \brief Initialize an envelope extractor instance. + + \return error status + +****************************************************************************/ +INT FDKsbrEnc_InitExtractSbrEnvelope(HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + int no_cols, int no_rows, int start_index, + int time_slots, int time_step, + int tran_off, ULONG statesInitFlag, + int chInEl, UCHAR *dynamic_RAM, + UINT sbrSyntaxFlags) { + int YBufferLength, rBufferLength; + int i; + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + int off = TRANSIENT_OFFSET_LD; + hSbrCut->YBufferWriteOffset = (no_cols >> 1) + off * time_step; + } else { + hSbrCut->YBufferWriteOffset = tran_off * time_step; + } + hSbrCut->rBufferReadOffset = 0; + + YBufferLength = hSbrCut->YBufferWriteOffset + no_cols; + rBufferLength = no_cols; + + hSbrCut->pre_transient_info[0] = 0; + hSbrCut->pre_transient_info[1] = 0; + + hSbrCut->no_cols = no_cols; + hSbrCut->no_rows = no_rows; + hSbrCut->start_index = start_index; + + hSbrCut->time_slots = time_slots; + hSbrCut->time_step = time_step; + + FDK_ASSERT(no_rows <= 64); + + /* Use half the Energy values if time step is 2 or greater */ + if (time_step >= 2) + hSbrCut->YBufferSzShift = 1; + else + hSbrCut->YBufferSzShift = 0; + + YBufferLength >>= hSbrCut->YBufferSzShift; + hSbrCut->YBufferWriteOffset >>= hSbrCut->YBufferSzShift; + + FDK_ASSERT(YBufferLength <= 32); + + FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM); + INT n = 0; + for (i = (32 >> 1); i < 32; i++, n++) { + hSbrCut->YBuffer[i] = YBufferDyn + (n * 64); + } + + if (statesInitFlag) { + for (i = 0; i < YBufferLength; i++) { + FDKmemclear(hSbrCut->YBuffer[i], 64 * sizeof(FIXP_DBL)); + } + } + + for (i = 0; i < rBufferLength; i++) { + FDKmemclear(hSbrCut->rBuffer[i], 64 * sizeof(FIXP_DBL)); + FDKmemclear(hSbrCut->iBuffer[i], 64 * sizeof(FIXP_DBL)); + } + + FDKmemclear(hSbrCut->envelopeCompensation, sizeof(UCHAR) * MAX_FREQ_COEFFS); + + if (statesInitFlag) { + hSbrCut->YBufferScale[0] = hSbrCut->YBufferScale[1] = FRACT_BITS - 1; + } + + return (0); +} + +/***************************************************************************/ +/*! + + \brief deinitializes an envelope extractor handle + + \return void + +****************************************************************************/ + +void FDKsbrEnc_deleteExtractSbrEnvelope(HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut) { + if (hSbrCut) { + FreeRam_Sbr_envYBuffer(&hSbrCut->p_YBuffer); + } +} + +INT FDKsbrEnc_GetEnvEstDelay(HANDLE_SBR_EXTRACT_ENVELOPE hSbr) { + return hSbr->no_rows * + ((hSbr->YBufferWriteOffset) * + 2 /* mult 2 because nrg's are grouped half */ + - hSbr->rBufferReadOffset); /* in reference hold half spec and calc + nrg's on overlapped spec */ +} diff --git a/fdk-aac/libSBRenc/src/env_est.h b/fdk-aac/libSBRenc/src/env_est.h new file mode 100644 index 0000000..006f55b --- /dev/null +++ b/fdk-aac/libSBRenc/src/env_est.h @@ -0,0 +1,223 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Envelope estimation structs and prototypes $Revision: 92790 $ +*/ +#ifndef ENV_EST_H +#define ENV_EST_H + +#include "sbr_def.h" +#include "sbr_encoder.h" /* SBR econfig structs */ +#include "ps_main.h" +#include "bit_sbr.h" +#include "fram_gen.h" +#include "tran_det.h" +#include "code_env.h" +#include "ton_corr.h" + +typedef struct { + FIXP_DBL *rBuffer[32]; + FIXP_DBL *iBuffer[32]; + + FIXP_DBL *p_YBuffer; + + FIXP_DBL *YBuffer[32]; + int YBufferScale[2]; + + UCHAR envelopeCompensation[MAX_FREQ_COEFFS]; + UCHAR pre_transient_info[2]; + + int YBufferWriteOffset; + int YBufferSzShift; + int rBufferReadOffset; + + int no_cols; + int no_rows; + int start_index; + + int time_slots; + int time_step; +} SBR_EXTRACT_ENVELOPE; +typedef SBR_EXTRACT_ENVELOPE *HANDLE_SBR_EXTRACT_ENVELOPE; + +struct ENV_CHANNEL { + FAST_TRAN_DETECTOR sbrFastTransientDetector; + SBR_TRANSIENT_DETECTOR sbrTransientDetector; + SBR_CODE_ENVELOPE sbrCodeEnvelope; + SBR_CODE_ENVELOPE sbrCodeNoiseFloor; + SBR_EXTRACT_ENVELOPE sbrExtractEnvelope; + + SBR_ENVELOPE_FRAME SbrEnvFrame; + SBR_TON_CORR_EST TonCorr; + + struct SBR_ENV_DATA encEnvData; + + int qmfScale; + UCHAR fLevelProtect; +}; +typedef struct ENV_CHANNEL *HANDLE_ENV_CHANNEL; + +/************ Function Declarations ***************/ + +INT FDKsbrEnc_CreateExtractSbrEnvelope(HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + INT channel, INT chInEl, + UCHAR *dynamic_RAM); + +INT FDKsbrEnc_InitExtractSbrEnvelope(HANDLE_SBR_EXTRACT_ENVELOPE hSbr, + int no_cols, int no_rows, int start_index, + int time_slots, int time_step, + int tran_off, ULONG statesInitFlag, + int chInEl, UCHAR *dynamic_RAM, + UINT sbrSyntaxFlags); + +void FDKsbrEnc_deleteExtractSbrEnvelope(HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut); + +typedef struct { + FREQ_RES res[MAX_NUM_NOISE_VALUES]; + int maxQuantError; + +} SBR_FRAME_TEMP_DATA; + +typedef struct { + const SBR_FRAME_INFO *frame_info; + FIXP_DBL noiseFloor[MAX_NUM_NOISE_VALUES]; + SCHAR sfb_nrg_coupling + [MAX_NUM_ENVELOPE_VALUES]; /* only used if stereomode = SWITCH_L_R_C */ + SCHAR sfb_nrg[MAX_NUM_ENVELOPE_VALUES]; + SCHAR noise_level_coupling + [MAX_NUM_NOISE_VALUES]; /* only used if stereomode = SWITCH_L_R_C */ + SCHAR noise_level[MAX_NUM_NOISE_VALUES]; + UCHAR transient_info[3]; + UCHAR nEnvelopes; +} SBR_ENV_TEMP_DATA; + +/* + * Extract features from QMF data. Afterwards, the QMF data is not required + * anymore. + */ +void FDKsbrEnc_extractSbrEnvelope1(HANDLE_SBR_CONFIG_DATA h_con, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL h_envChan, + HANDLE_COMMON_DATA cmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData); + +/* + * Process the previously features extracted by FDKsbrEnc_extractSbrEnvelope1 + * and create/encode SBR envelopes. + */ +void FDKsbrEnc_extractSbrEnvelope2(HANDLE_SBR_CONFIG_DATA h_con, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL sbrEnvChannel0, + HANDLE_ENV_CHANNEL sbrEnvChannel1, + HANDLE_COMMON_DATA cmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData, int clearOutput); + +INT FDKsbrEnc_GetEnvEstDelay(HANDLE_SBR_EXTRACT_ENVELOPE hSbr); + +#endif diff --git a/fdk-aac/libSBRenc/src/fram_gen.cpp b/fdk-aac/libSBRenc/src/fram_gen.cpp new file mode 100644 index 0000000..7ed6e79 --- /dev/null +++ b/fdk-aac/libSBRenc/src/fram_gen.cpp @@ -0,0 +1,1965 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "fram_gen.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +static const SBR_FRAME_INFO frameInfo1_2048 = {1, {0, 16}, {FREQ_RES_HIGH}, + 0, 1, {0, 16}}; + +static const SBR_FRAME_INFO frameInfo2_2048 = { + 2, {0, 8, 16}, {FREQ_RES_HIGH, FREQ_RES_HIGH}, 0, 2, {0, 8, 16}}; + +static const SBR_FRAME_INFO frameInfo4_2048 = { + 4, + {0, 4, 8, 12, 16}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + {0, 8, 16}}; + +static const SBR_FRAME_INFO frameInfo1_2304 = {1, {0, 18}, {FREQ_RES_HIGH}, + 0, 1, {0, 18}}; + +static const SBR_FRAME_INFO frameInfo2_2304 = { + 2, {0, 9, 18}, {FREQ_RES_HIGH, FREQ_RES_HIGH}, 0, 2, {0, 9, 18}}; + +static const SBR_FRAME_INFO frameInfo4_2304 = { + 4, + {0, 5, 9, 14, 18}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + {0, 9, 18}}; + +static const SBR_FRAME_INFO frameInfo1_1920 = {1, {0, 15}, {FREQ_RES_HIGH}, + 0, 1, {0, 15}}; + +static const SBR_FRAME_INFO frameInfo2_1920 = { + 2, {0, 8, 15}, {FREQ_RES_HIGH, FREQ_RES_HIGH}, 0, 2, {0, 8, 15}}; + +static const SBR_FRAME_INFO frameInfo4_1920 = { + 4, + {0, 4, 8, 12, 15}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + {0, 8, 15}}; + +static const SBR_FRAME_INFO frameInfo1_1152 = {1, {0, 9}, {FREQ_RES_HIGH}, + 0, 1, {0, 9}}; + +static const SBR_FRAME_INFO frameInfo2_1152 = { + 2, {0, 5, 9}, {FREQ_RES_HIGH, FREQ_RES_HIGH}, 0, 2, {0, 5, 9}}; + +static const SBR_FRAME_INFO frameInfo4_1152 = { + 4, + {0, 2, 5, 7, 9}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + {0, 5, 9}}; + +/* AACLD frame info */ +static const SBR_FRAME_INFO frameInfo1_512LD = {1, {0, 8}, {FREQ_RES_HIGH}, + 0, 1, {0, 8}}; + +static const SBR_FRAME_INFO frameInfo2_512LD = { + 2, {0, 4, 8}, {FREQ_RES_HIGH, FREQ_RES_HIGH}, 0, 2, {0, 4, 8}}; + +static const SBR_FRAME_INFO frameInfo4_512LD = { + 4, + {0, 2, 4, 6, 8}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + {0, 4, 8}}; + +static int calcFillLengthMax( + int tranPos, /*!< input : transient position (ref: tran det) */ + int numberTimeSlots /*!< input : number of timeslots */ +); + +static void fillFrameTran( + const int *v_tuningSegm, /*!< tuning: desired segment lengths */ + const int *v_tuningFreq, /*!< tuning: desired frequency resolutions */ + int tran, /*!< input : position of transient */ + int *v_bord, /*!< memNew: borders */ + int *length_v_bord, /*!< memNew: # borders */ + int *v_freq, /*!< memNew: frequency resolutions */ + int *length_v_freq, /*!< memNew: # frequency resolutions */ + int *bmin, /*!< hlpNew: first mandatory border */ + int *bmax /*!< hlpNew: last mandatory border */ +); + +static void fillFramePre(INT dmax, INT *v_bord, INT *length_v_bord, INT *v_freq, + INT *length_v_freq, INT bmin, INT rest); + +static void fillFramePost(INT *parts, INT *d, INT dmax, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT *length_v_freq, + INT bmax, INT bufferFrameStart, INT numberTimeSlots, + INT fmax); + +static void fillFrameInter(INT *nL, const int *v_tuningSegm, INT *v_bord, + INT *length_v_bord, INT bmin, INT *v_freq, + INT *length_v_freq, INT *v_bordFollow, + INT *length_v_bordFollow, INT *v_freqFollow, + INT *length_v_freqFollow, INT i_fillFollow, INT dmin, + INT dmax, INT numberTimeSlots); + +static void calcFrameClass(FRAME_CLASS *frameClass, FRAME_CLASS *frameClassOld, + INT tranFlag, INT *spreadFlag); + +static void specialCase(INT *spreadFlag, INT allowSpread, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT *length_v_freq, + INT *parts, INT d); + +static void calcCmonBorder(INT *i_cmon, INT *i_tran, INT *v_bord, + INT *length_v_bord, INT tran, INT bufferFrameStart, + INT numberTimeSlots); + +static void keepForFollowUp(INT *v_bordFollow, INT *length_v_bordFollow, + INT *v_freqFollow, INT *length_v_freqFollow, + INT *i_tranFollow, INT *i_fillFollow, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT i_cmon, + INT i_tran, INT parts, INT numberTimeSlots); + +static void calcCtrlSignal(HANDLE_SBR_GRID hSbrGrid, FRAME_CLASS frameClass, + INT *v_bord, INT length_v_bord, INT *v_freq, + INT length_v_freq, INT i_cmon, INT i_tran, + INT spreadFlag, INT nL); + +static void ctrlSignal2FrameInfo(HANDLE_SBR_GRID hSbrGrid, + HANDLE_SBR_FRAME_INFO hFrameInfo, + FREQ_RES *freq_res_fixfix); + +/* table for 8 time slot index */ +static const int envelopeTable_8[8][5] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* borders from left to right side; -1 = not in use */ + /*[|T-|------]*/ {2, 0, 0, 1, -1}, + /*[|-T-|-----]*/ {2, 0, 0, 2, -1}, + /*[--|T-|----]*/ {3, 1, 1, 2, 4}, + /*[---|T-|---]*/ {3, 1, 1, 3, 5}, + /*[----|T-|--]*/ {3, 1, 1, 4, 6}, + /*[-----|T--|]*/ {2, 1, 1, 5, -1}, + /*[------|T-|]*/ {2, 1, 1, 6, -1}, + /*[-------|T|]*/ {2, 1, 1, 7, -1}, +}; + +/* table for 16 time slot index */ +static const int envelopeTable_16[16][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------|]*/ {2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------|]*/ {2, 0, 0, 5, -1, -1}, + /*[|--|T---|----------]*/ {3, 1, 1, 2, 6, -1}, + /*[|---|T---|---------]*/ {3, 1, 1, 3, 7, -1}, + /*[|----|T---|--------]*/ {3, 1, 1, 4, 8, -1}, + /*[|-----|T---|-------]*/ {3, 1, 1, 5, 9, -1}, + /*[|------|T---|------]*/ {3, 1, 1, 6, 10, -1}, + /*[|-------|T---|-----]*/ {3, 1, 1, 7, 11, -1}, + /*[|--------|T---|----]*/ {3, 1, 1, 8, 12, -1}, + /*[|---------|T---|---]*/ {3, 1, 1, 9, 13, -1}, + /*[|----------|T---|--]*/ {3, 1, 1, 10, 14, -1}, + /*[|-----------|T----|]*/ {2, 1, 1, 11, -1, -1}, + /*[|------------|T---|]*/ {2, 1, 1, 12, -1, -1}, + /*[|-------------|T--|]*/ {2, 1, 1, 13, -1, -1}, + /*[|--------------|T-|]*/ {2, 1, 1, 14, -1, -1}, + /*[|---------------|T|]*/ {2, 1, 1, 15, -1, -1}, +}; + +/* table for 15 time slot index */ +static const int envelopeTable_15[15][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------]*/ {2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------]*/ {2, 0, 0, 5, -1, -1}, + /*[|--|T---|---------]*/ {3, 1, 1, 2, 6, -1}, + /*[|---|T---|--------]*/ {3, 1, 1, 3, 7, -1}, + /*[|----|T---|-------]*/ {3, 1, 1, 4, 8, -1}, + /*[|-----|T---|------]*/ {3, 1, 1, 5, 9, -1}, + /*[|------|T---|-----]*/ {3, 1, 1, 6, 10, -1}, + /*[|-------|T---|----]*/ {3, 1, 1, 7, 11, -1}, + /*[|--------|T---|---]*/ {3, 1, 1, 8, 12, -1}, + /*[|---------|T---|--]*/ {3, 1, 1, 9, 13, -1}, + /*[|----------|T----|]*/ {2, 1, 1, 10, -1, -1}, + /*[|-----------|T---|]*/ {2, 1, 1, 11, -1, -1}, + /*[|------------|T--|]*/ {2, 1, 1, 12, -1, -1}, + /*[|-------------|T-|]*/ {2, 1, 1, 13, -1, -1}, + /*[|--------------|T|]*/ {2, 1, 1, 14, -1, -1}, +}; + +static const int minFrameTranDistance = 4; + +static const FREQ_RES freqRes_table_8[] = { + FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, + FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}; + +static const FREQ_RES freqRes_table_16[16] = { + /* size of envelope */ + /* 0-4 */ FREQ_RES_LOW, + FREQ_RES_LOW, + FREQ_RES_LOW, + FREQ_RES_LOW, + FREQ_RES_LOW, + /* 5-9 */ FREQ_RES_LOW, + FREQ_RES_HIGH, + FREQ_RES_HIGH, + FREQ_RES_HIGH, + FREQ_RES_HIGH, + /* 10-16 */ FREQ_RES_HIGH, + FREQ_RES_HIGH, + FREQ_RES_HIGH, + FREQ_RES_HIGH, + FREQ_RES_HIGH, + FREQ_RES_HIGH}; + +static void generateFixFixOnly(HANDLE_SBR_FRAME_INFO hSbrFrameInfo, + HANDLE_SBR_GRID hSbrGrid, int tranPosInternal, + int numberTimeSlots, UCHAR fResTransIsLow); + +/*! + Functionname: FDKsbrEnc_frameInfoGenerator + + Description: produces the FRAME_INFO struct for the current frame + + Arguments: hSbrEnvFrame - pointer to sbr envelope handle + v_pre_transient_info - pointer to transient info vector + v_transient_info - pointer to previous transient info +vector v_tuning - pointer to tuning vector + + Return: frame_info - pointer to SBR_FRAME_INFO struct + +*******************************************************************************/ +HANDLE_SBR_FRAME_INFO +FDKsbrEnc_frameInfoGenerator(HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + UCHAR *v_transient_info, const INT rightBorderFIX, + UCHAR *v_transient_info_pre, int ldGrid, + const int *v_tuning) { + INT numEnv, tranPosInternal = 0, bmin = 0, bmax = 0, parts, d, i_cmon = 0, + i_tran = 0, nL; + INT fmax = 0; + + INT *v_bord = hSbrEnvFrame->v_bord; + INT *v_freq = hSbrEnvFrame->v_freq; + INT *v_bordFollow = hSbrEnvFrame->v_bordFollow; + INT *v_freqFollow = hSbrEnvFrame->v_freqFollow; + + INT *length_v_bordFollow = &hSbrEnvFrame->length_v_bordFollow; + INT *length_v_freqFollow = &hSbrEnvFrame->length_v_freqFollow; + INT *length_v_bord = &hSbrEnvFrame->length_v_bord; + INT *length_v_freq = &hSbrEnvFrame->length_v_freq; + INT *spreadFlag = &hSbrEnvFrame->spreadFlag; + INT *i_tranFollow = &hSbrEnvFrame->i_tranFollow; + INT *i_fillFollow = &hSbrEnvFrame->i_fillFollow; + FRAME_CLASS *frameClassOld = &hSbrEnvFrame->frameClassOld; + FRAME_CLASS frameClass = FIXFIX; + + INT allowSpread = hSbrEnvFrame->allowSpread; + INT numEnvStatic = hSbrEnvFrame->numEnvStatic; + INT staticFraming = hSbrEnvFrame->staticFraming; + INT dmin = hSbrEnvFrame->dmin; + INT dmax = hSbrEnvFrame->dmax; + + INT bufferFrameStart = hSbrEnvFrame->SbrGrid.bufferFrameStart; + INT numberTimeSlots = hSbrEnvFrame->SbrGrid.numberTimeSlots; + INT frameMiddleSlot = hSbrEnvFrame->frameMiddleSlot; + + INT tranPos = v_transient_info[0]; + INT tranFlag = v_transient_info[1]; + + const int *v_tuningSegm = v_tuning; + const int *v_tuningFreq = v_tuning + 3; + + hSbrEnvFrame->v_tuningSegm = v_tuningSegm; + + if (ldGrid) { + /* in case there was a transient at the very end of the previous frame, + * start with a transient envelope */ + if (!tranFlag && v_transient_info_pre[1] && + (numberTimeSlots - v_transient_info_pre[0] < minFrameTranDistance)) { + tranFlag = 1; + tranPos = 0; + } + } + + /* + * Synopsis: + * + * The frame generator creates the time-/frequency-grid for one SBR frame. + * Input signals are provided by the transient detector and the frame + * splitter (transientDetectNew() & FrameSplitter() in tran_det.c). The + * framing is controlled by adjusting tuning parameters stored in + * FRAME_GEN_TUNING. The parameter values are dependent on frame lengths + * and bitrates, and may in the future be signal dependent. + * + * The envelope borders are stored for frame generator internal use in + * aBorders. The contents of aBorders represent positions along the time + * axis given in the figures in fram_gen.h (the "frame-generator" rows). + * The unit is "time slot". The figures in fram_gen.h also define the + * detection ranges for the transient detector. For every border in + * aBorders, there is a corresponding entry in aFreqRes, which defines the + * frequency resolution of the envelope following (delimited by) the + * border. + * + * When no transients are present, FIXFIX class frames are used. The + * frame splitter decides whether to use one or two envelopes in the + * FIXFIX frame. "Sparse transients" (separated by a few frames without + * transients) are handeled by [FIXVAR, VARFIX] pairs or (depending on + * tuning and transient position relative the nominal frame boundaries) + * by [FIXVAR, VARVAR, VARFIX] triples. "Tight transients" (in + * consecutive frames) are handeled by [..., VARVAR, VARVAR, ...] + * sequences. + * + * The generator assumes that transients are "sparse", and designs + * borders for [FIXVAR, VARFIX] pairs right away, where the first frame + * corresponds to the present frame. At the next call of the generator + * it is known whether the transient actually is "sparse" or not. If + * 'yes', the already calculated VARFIX borders are used. If 'no', new + * borders, meeting the requirements of the "tight" transient, are + * calculated. + * + * The generator produces two outputs: A "clear-text bitstream" stored in + * SBR_GRID, and a straight-forward representation of the grid stored in + * SBR_FRAME_INFO. The former is subsequently converted to the actual + * bitstream sbr_grid() (encodeSbrGrid() in bit_sbr.c). The latter is + * used by other encoder functions, such as the envelope estimator + * (calculateSbrEnvelope() in env_est.c) and the noise floor and missing + * harmonics detector (TonCorrParamExtr() in nf_est.c). + */ + + if (staticFraming) { + /*-------------------------------------------------------------------------- + Ignore transient detector + ---------------------------------------------------------------------------*/ + + frameClass = FIXFIX; + numEnv = numEnvStatic; /* {1,2,4,8} */ + *frameClassOld = FIXFIX; /* for change to dyn */ + hSbrEnvFrame->SbrGrid.bs_num_env = numEnv; + hSbrEnvFrame->SbrGrid.frameClass = frameClass; + } else { + /*-------------------------------------------------------------------------- + Calculate frame class to use + ---------------------------------------------------------------------------*/ + if (rightBorderFIX) { + tranFlag = 0; + *spreadFlag = 0; + } + calcFrameClass(&frameClass, frameClassOld, tranFlag, spreadFlag); + + /* patch for new frame class FIXFIXonly for AAC LD */ + if (tranFlag && ldGrid) { + frameClass = FIXFIXonly; + *frameClassOld = FIXFIX; + } + + /* + * every transient is processed below by inserting + * + * - one border at the onset of the transient + * - one or more "decay borders" (after the onset of the transient) + * - optionally one "attack border" (before the onset of the transient) + * + * those borders are referred to as "mandatory borders" and are + * defined by the 'segmentLength' array in FRAME_GEN_TUNING + * + * the frequency resolutions of the corresponding envelopes are + * defined by the 'segmentRes' array in FRAME_GEN_TUNING + */ + + /*-------------------------------------------------------------------------- + Design frame (or follow-up old design) + ---------------------------------------------------------------------------*/ + if (tranFlag) { + /* Always for FixVar, often but not always for VarVar */ + + /*-------------------------------------------------------------------------- + Design part of T/F-grid around the new transient + ---------------------------------------------------------------------------*/ + + tranPosInternal = + frameMiddleSlot + tranPos + bufferFrameStart; /* FH 00-06-26 */ + /* + add mandatory borders around transient + */ + + fillFrameTran(v_tuningSegm, v_tuningFreq, tranPosInternal, v_bord, + length_v_bord, v_freq, length_v_freq, &bmin, &bmax); + + /* make sure we stay within the maximum SBR frame overlap */ + fmax = calcFillLengthMax(tranPos, numberTimeSlots); + } + + switch (frameClass) { + case FIXFIXonly: + FDK_ASSERT(ldGrid); + tranPosInternal = tranPos; + generateFixFixOnly(&(hSbrEnvFrame->SbrFrameInfo), + &(hSbrEnvFrame->SbrGrid), tranPosInternal, + numberTimeSlots, hSbrEnvFrame->fResTransIsLow); + + return &(hSbrEnvFrame->SbrFrameInfo); + + case FIXVAR: + + /*-------------------------------------------------------------------------- + Design remaining parts of T/F-grid (assuming next frame is VarFix) + ---------------------------------------------------------------------------*/ + + /*-------------------------------------------------------------------------- + Fill region before new transient: + ---------------------------------------------------------------------------*/ + fillFramePre(dmax, v_bord, length_v_bord, v_freq, length_v_freq, bmin, + bmin - bufferFrameStart); /* FH 00-06-26 */ + + /*-------------------------------------------------------------------------- + Fill region after new transient: + ---------------------------------------------------------------------------*/ + fillFramePost(&parts, &d, dmax, v_bord, length_v_bord, v_freq, + length_v_freq, bmax, bufferFrameStart, numberTimeSlots, + fmax); + + /*-------------------------------------------------------------------------- + Take care of special case: + ---------------------------------------------------------------------------*/ + if (parts == 1 && d < dmin) /* no fill, short last envelope */ + specialCase(spreadFlag, allowSpread, v_bord, length_v_bord, v_freq, + length_v_freq, &parts, d); + + /*-------------------------------------------------------------------------- + Calculate common border (split-point) + ---------------------------------------------------------------------------*/ + calcCmonBorder(&i_cmon, &i_tran, v_bord, length_v_bord, tranPosInternal, + bufferFrameStart, numberTimeSlots); /* FH 00-06-26 */ + + /*-------------------------------------------------------------------------- + Extract data for proper follow-up in next frame + ---------------------------------------------------------------------------*/ + keepForFollowUp(v_bordFollow, length_v_bordFollow, v_freqFollow, + length_v_freqFollow, i_tranFollow, i_fillFollow, v_bord, + length_v_bord, v_freq, i_cmon, i_tran, parts, + numberTimeSlots); /* FH 00-06-26 */ + + /*-------------------------------------------------------------------------- + Calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal(&hSbrEnvFrame->SbrGrid, frameClass, v_bord, + *length_v_bord, v_freq, *length_v_freq, i_cmon, i_tran, + *spreadFlag, DC); + break; + case VARFIX: + /*-------------------------------------------------------------------------- + Follow-up old transient - calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal(&hSbrEnvFrame->SbrGrid, frameClass, v_bordFollow, + *length_v_bordFollow, v_freqFollow, *length_v_freqFollow, + DC, *i_tranFollow, *spreadFlag, DC); + break; + case VARVAR: + if (*spreadFlag) { /* spread across three frames */ + /*-------------------------------------------------------------------------- + Follow-up old transient - calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal(&hSbrEnvFrame->SbrGrid, frameClass, v_bordFollow, + *length_v_bordFollow, v_freqFollow, + *length_v_freqFollow, DC, *i_tranFollow, *spreadFlag, + DC); + + *spreadFlag = 0; + + /*-------------------------------------------------------------------------- + Extract data for proper follow-up in next frame + ---------------------------------------------------------------------------*/ + v_bordFollow[0] = hSbrEnvFrame->SbrGrid.bs_abs_bord_1 - + numberTimeSlots; /* FH 00-06-26 */ + v_freqFollow[0] = 1; + *length_v_bordFollow = 1; + *length_v_freqFollow = 1; + + *i_tranFollow = -DC; + *i_fillFollow = -DC; + } else { + /*-------------------------------------------------------------------------- + Design remaining parts of T/F-grid (assuming next frame is VarFix) + adapt or fill region before new transient: + ---------------------------------------------------------------------------*/ + fillFrameInter(&nL, v_tuningSegm, v_bord, length_v_bord, bmin, v_freq, + length_v_freq, v_bordFollow, length_v_bordFollow, + v_freqFollow, length_v_freqFollow, *i_fillFollow, dmin, + dmax, numberTimeSlots); + + /*-------------------------------------------------------------------------- + Fill after transient: + ---------------------------------------------------------------------------*/ + fillFramePost(&parts, &d, dmax, v_bord, length_v_bord, v_freq, + length_v_freq, bmax, bufferFrameStart, numberTimeSlots, + fmax); + + /*-------------------------------------------------------------------------- + Take care of special case: + ---------------------------------------------------------------------------*/ + if (parts == 1 && d < dmin) /*% no fill, short last envelope */ + specialCase(spreadFlag, allowSpread, v_bord, length_v_bord, v_freq, + length_v_freq, &parts, d); + + /*-------------------------------------------------------------------------- + Calculate common border (split-point) + ---------------------------------------------------------------------------*/ + calcCmonBorder(&i_cmon, &i_tran, v_bord, length_v_bord, + tranPosInternal, bufferFrameStart, numberTimeSlots); + + /*-------------------------------------------------------------------------- + Extract data for proper follow-up in next frame + ---------------------------------------------------------------------------*/ + keepForFollowUp(v_bordFollow, length_v_bordFollow, v_freqFollow, + length_v_freqFollow, i_tranFollow, i_fillFollow, + v_bord, length_v_bord, v_freq, i_cmon, i_tran, parts, + numberTimeSlots); + + /*-------------------------------------------------------------------------- + Calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal(&hSbrEnvFrame->SbrGrid, frameClass, v_bord, + *length_v_bord, v_freq, *length_v_freq, i_cmon, i_tran, + 0, nL); + } + break; + case FIXFIX: + if (tranPos == 0) + numEnv = 1; + else + numEnv = 2; + + hSbrEnvFrame->SbrGrid.bs_num_env = numEnv; + hSbrEnvFrame->SbrGrid.frameClass = frameClass; + + break; + default: + FDK_ASSERT(0); + } + } + + /*------------------------------------------------------------------------- + Convert control signal to frame info struct + ---------------------------------------------------------------------------*/ + ctrlSignal2FrameInfo(&hSbrEnvFrame->SbrGrid, &hSbrEnvFrame->SbrFrameInfo, + hSbrEnvFrame->freq_res_fixfix); + + return &hSbrEnvFrame->SbrFrameInfo; +} + +/***************************************************************************/ +/*! + \brief Gnerates frame info for FIXFIXonly frame class used for low delay + version + + \return nothing + ****************************************************************************/ +static void generateFixFixOnly(HANDLE_SBR_FRAME_INFO hSbrFrameInfo, + HANDLE_SBR_GRID hSbrGrid, int tranPosInternal, + int numberTimeSlots, UCHAR fResTransIsLow) { + int nEnv, i, k = 0, tranIdx; + const int *pTable = NULL; + const FREQ_RES *freqResTable = NULL; + + switch (numberTimeSlots) { + case 8: { + pTable = envelopeTable_8[tranPosInternal]; + } + freqResTable = freqRes_table_8; + break; + case 15: + pTable = envelopeTable_15[tranPosInternal]; + freqResTable = freqRes_table_16; + break; + case 16: + pTable = envelopeTable_16[tranPosInternal]; + freqResTable = freqRes_table_16; + break; + } + + /* look number of envolpes in table */ + nEnv = pTable[0]; + /* look up envolpe distribution in table */ + for (i = 1; i < nEnv; i++) hSbrFrameInfo->borders[i] = pTable[i + 2]; + + /* open and close frame border */ + hSbrFrameInfo->borders[0] = 0; + hSbrFrameInfo->borders[nEnv] = numberTimeSlots; + + /* adjust segment-frequency-resolution according to the segment-length */ + for (i = 0; i < nEnv; i++) { + k = hSbrFrameInfo->borders[i + 1] - hSbrFrameInfo->borders[i]; + if (!fResTransIsLow) + hSbrFrameInfo->freqRes[i] = freqResTable[k]; + else + hSbrFrameInfo->freqRes[i] = FREQ_RES_LOW; + + hSbrGrid->v_f[i] = hSbrFrameInfo->freqRes[i]; + } + + hSbrFrameInfo->nEnvelopes = nEnv; + hSbrFrameInfo->shortEnv = pTable[2]; + /* transient idx */ + tranIdx = pTable[1]; + + /* add noise floors */ + hSbrFrameInfo->bordersNoise[0] = 0; + hSbrFrameInfo->bordersNoise[1] = + hSbrFrameInfo->borders[tranIdx ? tranIdx : 1]; + hSbrFrameInfo->bordersNoise[2] = numberTimeSlots; + hSbrFrameInfo->nNoiseEnvelopes = 2; + + hSbrGrid->frameClass = FIXFIXonly; + hSbrGrid->bs_abs_bord = tranPosInternal; + hSbrGrid->bs_num_env = nEnv; +} + +/******************************************************************************* + Functionname: FDKsbrEnc_initFrameInfoGenerator + ******************************************************************************* + + Description: + + Arguments: hSbrEnvFrame - pointer to sbr envelope handle + allowSpread - commandline parameter + numEnvStatic - commandline parameter + staticFraming - commandline parameter + + Return: none + +*******************************************************************************/ +void FDKsbrEnc_initFrameInfoGenerator(HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + INT allowSpread, INT numEnvStatic, + INT staticFraming, INT timeSlots, + const FREQ_RES *freq_res_fixfix, + UCHAR fResTransIsLow, + INT ldGrid) { /* FH 00-06-26 */ + + FDKmemclear(hSbrEnvFrame, sizeof(SBR_ENVELOPE_FRAME)); + + /* Initialisation */ + hSbrEnvFrame->frameClassOld = FIXFIX; + hSbrEnvFrame->spreadFlag = 0; + + hSbrEnvFrame->allowSpread = allowSpread; + hSbrEnvFrame->numEnvStatic = numEnvStatic; + hSbrEnvFrame->staticFraming = staticFraming; + hSbrEnvFrame->freq_res_fixfix[0] = freq_res_fixfix[0]; + hSbrEnvFrame->freq_res_fixfix[1] = freq_res_fixfix[1]; + hSbrEnvFrame->fResTransIsLow = fResTransIsLow; + + hSbrEnvFrame->length_v_bord = 0; + hSbrEnvFrame->length_v_bordFollow = 0; + + hSbrEnvFrame->length_v_freq = 0; + hSbrEnvFrame->length_v_freqFollow = 0; + + hSbrEnvFrame->i_tranFollow = 0; + hSbrEnvFrame->i_fillFollow = 0; + + hSbrEnvFrame->SbrGrid.numberTimeSlots = timeSlots; + + if (ldGrid) { + /*case CODEC_AACLD:*/ + hSbrEnvFrame->dmin = 2; + hSbrEnvFrame->dmax = 16; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_512LD; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + } else + switch (timeSlots) { + case NUMBER_TIME_SLOTS_1920: + hSbrEnvFrame->dmin = 4; + hSbrEnvFrame->dmax = 12; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_1920; + break; + case NUMBER_TIME_SLOTS_2048: + hSbrEnvFrame->dmin = 4; + hSbrEnvFrame->dmax = 12; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_2048; + break; + case NUMBER_TIME_SLOTS_1152: + hSbrEnvFrame->dmin = 2; + hSbrEnvFrame->dmax = 8; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_1152; + break; + case NUMBER_TIME_SLOTS_2304: + hSbrEnvFrame->dmin = 4; + hSbrEnvFrame->dmax = 15; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_2304; + break; + default: + FDK_ASSERT(0); + } +} + +/******************************************************************************* + Functionname: fillFrameTran + ******************************************************************************* + + Description: Add mandatory borders, as described by the tuning vector + and the current transient position + + Arguments: + modified: + v_bord - int pointer to v_bord vector + length_v_bord - length of v_bord vector + v_freq - int pointer to v_freq vector + length_v_freq - length of v_freq vector + bmin - int pointer to bmin (call by reference) + bmax - int pointer to bmax (call by reference) + not modified: + tran - position of transient + v_tuningSegm - int pointer to v_tuningSegm vector + v_tuningFreq - int pointer to v_tuningFreq vector + + Return: none + +*******************************************************************************/ +static void fillFrameTran( + const int *v_tuningSegm, /*!< tuning: desired segment lengths */ + const int *v_tuningFreq, /*!< tuning: desired frequency resolutions */ + int tran, /*!< input : position of transient */ + int *v_bord, /*!< memNew: borders */ + int *length_v_bord, /*!< memNew: # borders */ + int *v_freq, /*!< memNew: frequency resolutions */ + int *length_v_freq, /*!< memNew: # frequency resolutions */ + int *bmin, /*!< hlpNew: first mandatory border */ + int *bmax /*!< hlpNew: last mandatory border */ +) { + int bord, i; + + *length_v_bord = 0; + *length_v_freq = 0; + + /* add attack env leading border (optional) */ + if (v_tuningSegm[0]) { + /* v_bord = [(Ba)] start of attack env */ + FDKsbrEnc_AddRight(v_bord, length_v_bord, (tran - v_tuningSegm[0])); + + /* v_freq = [(Fa)] res of attack env */ + FDKsbrEnc_AddRight(v_freq, length_v_freq, v_tuningFreq[0]); + } + + /* add attack env trailing border/first decay env leading border */ + bord = tran; + FDKsbrEnc_AddRight(v_bord, length_v_bord, tran); /* v_bord = [(Ba),Bd1] */ + + /* add first decay env trailing border/2:nd decay env leading border */ + if (v_tuningSegm[1]) { + bord += v_tuningSegm[1]; + + /* v_bord = [(Ba),Bd1,Bd2] */ + FDKsbrEnc_AddRight(v_bord, length_v_bord, bord); + + /* v_freq = [(Fa),Fd1] */ + FDKsbrEnc_AddRight(v_freq, length_v_freq, v_tuningFreq[1]); + } + + /* add 2:nd decay env trailing border (optional) */ + if (v_tuningSegm[2] != 0) { + bord += v_tuningSegm[2]; + + /* v_bord = [(Ba),Bd1, Bd2,(Bd3)] */ + FDKsbrEnc_AddRight(v_bord, length_v_bord, bord); + + /* v_freq = [(Fa),Fd1,(Fd2)] */ + FDKsbrEnc_AddRight(v_freq, length_v_freq, v_tuningFreq[2]); + } + + /* v_freq = [(Fa),Fd1,(Fd2),1] */ + FDKsbrEnc_AddRight(v_freq, length_v_freq, 1); + + /* calc min and max values of mandatory borders */ + *bmin = v_bord[0]; + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] < *bmin) *bmin = v_bord[i]; + + *bmax = v_bord[0]; + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] > *bmax) *bmax = v_bord[i]; +} + +/******************************************************************************* + Functionname: fillFramePre + ******************************************************************************* + + Description: Add borders before mandatory borders, if needed + + Arguments: + modified: + v_bord - int pointer to v_bord vector + length_v_bord - length of v_bord vector + v_freq - int pointer to v_freq vector + length_v_freq - length of v_freq vector + not modified: + dmax - int value + bmin - int value + rest - int value + + Return: none + +*******************************************************************************/ +static void fillFramePre(INT dmax, INT *v_bord, INT *length_v_bord, INT *v_freq, + INT *length_v_freq, INT bmin, INT rest) { + /* + input state: + v_bord = [(Ba),Bd1, Bd2 ,(Bd3)] + v_freq = [(Fa),Fd1,(Fd2),1 ] + */ + + INT parts, d, j, S, s = 0, segm, bord; + + /* + start with one envelope + */ + + parts = 1; + d = rest; + + /* + calc # of additional envelopes and corresponding lengths + */ + + while (d > dmax) { + parts++; + + segm = rest / parts; + S = (segm - 2) >> 1; + s = fixMin(8, 2 * S + 2); + d = rest - (parts - 1) * s; + } + + /* + add borders before mandatory borders + */ + + bord = bmin; + + for (j = 0; j <= parts - 2; j++) { + bord = bord - s; + + /* v_bord = [...,(Bf),(Ba),Bd1, Bd2 ,(Bd3)] */ + FDKsbrEnc_AddLeft(v_bord, length_v_bord, bord); + + /* v_freq = [...,(1 ),(Fa),Fd1,(Fd2), 1 ] */ + FDKsbrEnc_AddLeft(v_freq, length_v_freq, 1); + } +} + +/***************************************************************************/ +/*! + \brief Overlap control + + Calculate max length of trailing fill segments, such that we always get a + border within the frame overlap region + + \return void + +****************************************************************************/ +static int calcFillLengthMax( + int tranPos, /*!< input : transient position (ref: tran det) */ + int numberTimeSlots /*!< input : number of timeslots */ +) { + int fmax; + + /* + calculate transient position within envelope buffer + */ + switch (numberTimeSlots) { + case NUMBER_TIME_SLOTS_2048: + if (tranPos < 4) + fmax = 6; + else if (tranPos == 4 || tranPos == 5) + fmax = 4; + else + fmax = 8; + break; + + case NUMBER_TIME_SLOTS_1920: + if (tranPos < 4) + fmax = 5; + else if (tranPos == 4 || tranPos == 5) + fmax = 3; + else + fmax = 7; + break; + + default: + fmax = 8; + break; + } + + return fmax; +} + +/******************************************************************************* + Functionname: fillFramePost + ******************************************************************************* + + Description: -Add borders after mandatory borders, if needed + Make a preliminary design of next frame, + assuming no transient is present there + + Arguments: + modified: + parts - int pointer to parts (call by reference) + d - int pointer to d (call by reference) + v_bord - int pointer to v_bord vector + length_v_bord - length of v_bord vector + v_freq - int pointer to v_freq vector + length_v_freq - length of v_freq vector + not modified: + bmax - int value + dmax - int value + + Return: none + +*******************************************************************************/ +static void fillFramePost(INT *parts, INT *d, INT dmax, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT *length_v_freq, + INT bmax, INT bufferFrameStart, INT numberTimeSlots, + INT fmax) { + INT j, rest, segm, S, s = 0, bord; + + /* + input state: + v_bord = [...,(Bf),(Ba),Bd1, Bd2 ,(Bd3)] + v_freq = [...,(1 ),(Fa),Fd1,(Fd2),1 ] + */ + + rest = bufferFrameStart + 2 * numberTimeSlots - bmax; + *d = rest; + + if (*d > 0) { + *parts = 1; /* start with one envelope */ + + /* calc # of additional envelopes and corresponding lengths */ + + while (*d > dmax) { + *parts = *parts + 1; + + segm = rest / (*parts); + S = (segm - 2) >> 1; + s = fixMin(fmax, 2 * S + 2); + *d = rest - (*parts - 1) * s; + } + + /* add borders after mandatory borders */ + + bord = bmax; + for (j = 0; j <= *parts - 2; j++) { + bord += s; + + /* v_bord = [...,(Bf),(Ba),Bd1, Bd2 ,(Bd3),(Bf)] */ + FDKsbrEnc_AddRight(v_bord, length_v_bord, bord); + + /* v_freq = [...,(1 ),(Fa),Fd1,(Fd2), 1 , 1! ,1] */ + FDKsbrEnc_AddRight(v_freq, length_v_freq, 1); + } + } else { + *parts = 1; + + /* remove last element from v_bord and v_freq */ + + *length_v_bord = *length_v_bord - 1; + *length_v_freq = *length_v_freq - 1; + } +} + +/******************************************************************************* + Functionname: fillFrameInter + ******************************************************************************* + + Description: + + Arguments: nL - + v_tuningSegm - + v_bord - + length_v_bord - + bmin - + v_freq - + length_v_freq - + v_bordFollow - + length_v_bordFollow - + v_freqFollow - + length_v_freqFollow - + i_fillFollow - + dmin - + dmax - + + Return: none + +*******************************************************************************/ +static void fillFrameInter(INT *nL, const int *v_tuningSegm, INT *v_bord, + INT *length_v_bord, INT bmin, INT *v_freq, + INT *length_v_freq, INT *v_bordFollow, + INT *length_v_bordFollow, INT *v_freqFollow, + INT *length_v_freqFollow, INT i_fillFollow, INT dmin, + INT dmax, INT numberTimeSlots) { + INT middle, b_new, numBordFollow, bordMaxFollow, i; + + if (numberTimeSlots != NUMBER_TIME_SLOTS_1152) { + /* % remove fill borders: */ + if (i_fillFollow >= 1) { + *length_v_bordFollow = i_fillFollow; + *length_v_freqFollow = i_fillFollow; + } + + numBordFollow = *length_v_bordFollow; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + + /* remove even more borders if needed */ + middle = bmin - bordMaxFollow; + while (middle < 0) { + numBordFollow--; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + middle = bmin - bordMaxFollow; + } + + *length_v_bordFollow = numBordFollow; + *length_v_freqFollow = numBordFollow; + *nL = numBordFollow - 1; + + b_new = *length_v_bord; + + if (middle <= dmax) { + if (middle >= dmin) { /* concatenate */ + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft(v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + + else { + if (v_tuningSegm[0] != 0) { /* remove one new border and concatenate */ + *length_v_bord = b_new - 1; + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + + *length_v_freq = b_new - 1; + FDKsbrEnc_AddVecLeft(v_freq + 1, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } else { + if (*length_v_bordFollow > + 1) { /* remove one old border and concatenate */ + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow - 1); + FDKsbrEnc_AddVecLeft(v_freq, length_v_freq, v_freqFollow, + *length_v_bordFollow - 1); + + *nL = *nL - 1; + } else { /* remove new "transient" border and concatenate */ + + for (i = 0; i < *length_v_bord - 1; i++) v_bord[i] = v_bord[i + 1]; + + for (i = 0; i < *length_v_freq - 1; i++) v_freq[i] = v_freq[i + 1]; + + *length_v_bord = b_new - 1; + *length_v_freq = b_new - 1; + + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft(v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + } + } + } else { /* middle > dmax */ + + fillFramePre(dmax, v_bord, length_v_bord, v_freq, length_v_freq, bmin, + middle); + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft(v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + + } else { /* numberTimeSlots==NUMBER_TIME_SLOTS_1152 */ + + INT l, m; + + /*------------------------------------------------------------------------ + remove fill borders + ------------------------------------------------------------------------*/ + if (i_fillFollow >= 1) { + *length_v_bordFollow = i_fillFollow; + *length_v_freqFollow = i_fillFollow; + } + + numBordFollow = *length_v_bordFollow; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + + /*------------------------------------------------------------------------ + remove more borders if necessary to eliminate overlap + ------------------------------------------------------------------------*/ + + /* check for overlap */ + middle = bmin - bordMaxFollow; + + /* intervals: + i) middle < 0 : overlap, must remove borders + ii) 0 <= middle < dmin : no overlap but too tight, must remove + borders iii) dmin <= middle <= dmax : ok, just concatenate iv) dmax + <= middle : too wide, must add borders + */ + + /* first remove old non-fill-borders... */ + while (middle < 0) { + /* ...but don't remove all of them */ + if (numBordFollow == 1) break; + + numBordFollow--; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + middle = bmin - bordMaxFollow; + } + + /* if this isn't enough, remove new non-fill borders */ + if (middle < 0) { + for (l = 0, m = 0; l < *length_v_bord; l++) { + if (v_bord[l] > bordMaxFollow) { + v_bord[m] = v_bord[l]; + v_freq[m] = v_freq[l]; + m++; + } + } + + *length_v_bord = l; + *length_v_freq = l; + + bmin = v_bord[0]; + } + + /*------------------------------------------------------------------------ + update modified follow-up data + ------------------------------------------------------------------------*/ + + *length_v_bordFollow = numBordFollow; + *length_v_freqFollow = numBordFollow; + + /* left relative borders correspond to follow-up */ + *nL = numBordFollow - 1; + + /*------------------------------------------------------------------------ + take care of intervals ii through iv + ------------------------------------------------------------------------*/ + + /* now middle should be >= 0 */ + middle = bmin - bordMaxFollow; + + if (middle <= dmin) /* (ii) */ + { + b_new = *length_v_bord; + + if (v_tuningSegm[0] != 0) { + /* remove new "luxury" border and concatenate */ + *length_v_bord = b_new - 1; + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + + *length_v_freq = b_new - 1; + FDKsbrEnc_AddVecLeft(v_freq + 1, length_v_freq, v_freqFollow, + *length_v_freqFollow); + + } else if (*length_v_bordFollow > 1) { + /* remove old border and concatenate */ + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow - 1); + FDKsbrEnc_AddVecLeft(v_freq, length_v_freq, v_freqFollow, + *length_v_bordFollow - 1); + + *nL = *nL - 1; + } else { + /* remove new border and concatenate */ + for (i = 0; i < *length_v_bord - 1; i++) v_bord[i] = v_bord[i + 1]; + + for (i = 0; i < *length_v_freq - 1; i++) v_freq[i] = v_freq[i + 1]; + + *length_v_bord = b_new - 1; + *length_v_freq = b_new - 1; + + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft(v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + } else if ((middle >= dmin) && (middle <= dmax)) /* (iii) */ + { + /* concatenate */ + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft(v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + + } else /* (iv) */ + { + fillFramePre(dmax, v_bord, length_v_bord, v_freq, length_v_freq, bmin, + middle); + FDKsbrEnc_AddVecLeft(v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft(v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + } +} + +/******************************************************************************* + Functionname: calcFrameClass + ******************************************************************************* + + Description: + + Arguments: INT* frameClass, INT* frameClassOld, INT tranFlag, INT* spreadFlag) + + Return: none + +*******************************************************************************/ +static void calcFrameClass(FRAME_CLASS *frameClass, FRAME_CLASS *frameClassOld, + INT tranFlag, INT *spreadFlag) { + switch (*frameClassOld) { + case FIXFIXonly: + case FIXFIX: + if (tranFlag) + *frameClass = FIXVAR; + else + *frameClass = FIXFIX; + break; + case FIXVAR: + if (tranFlag) { + *frameClass = VARVAR; + *spreadFlag = 0; + } else { + if (*spreadFlag) + *frameClass = VARVAR; + else + *frameClass = VARFIX; + } + break; + case VARFIX: + if (tranFlag) + *frameClass = FIXVAR; + else + *frameClass = FIXFIX; + break; + case VARVAR: + if (tranFlag) { + *frameClass = VARVAR; + *spreadFlag = 0; + } else { + if (*spreadFlag) + *frameClass = VARVAR; + else + *frameClass = VARFIX; + } + break; + }; + + *frameClassOld = *frameClass; +} + +/******************************************************************************* + Functionname: specialCase + ******************************************************************************* + + Description: + + Arguments: spreadFlag + allowSpread + v_bord + length_v_bord + v_freq + length_v_freq + parts + d + + Return: none + +*******************************************************************************/ +static void specialCase(INT *spreadFlag, INT allowSpread, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT *length_v_freq, + INT *parts, INT d) { + INT L; + + L = *length_v_bord; + + if (allowSpread) { /* add one "step 8" */ + *spreadFlag = 1; + FDKsbrEnc_AddRight(v_bord, length_v_bord, v_bord[L - 1] + 8); + FDKsbrEnc_AddRight(v_freq, length_v_freq, 1); + (*parts)++; + } else { + if (d == 1) { /* stretch one slot */ + *length_v_bord = L - 1; + *length_v_freq = L - 1; + } else { + if ((v_bord[L - 1] - v_bord[L - 2]) > 2) { /* compress one quant step */ + v_bord[L - 1] = v_bord[L - 1] - 2; + v_freq[*length_v_freq - 1] = 0; /* use low res for short segment */ + } + } + } +} + +/******************************************************************************* + Functionname: calcCmonBorder + ******************************************************************************* + + Description: + + Arguments: i_cmon + i_tran + v_bord + length_v_bord + tran + + Return: none + +*******************************************************************************/ +static void calcCmonBorder(INT *i_cmon, INT *i_tran, INT *v_bord, + INT *length_v_bord, INT tran, INT bufferFrameStart, + INT numberTimeSlots) { /* FH 00-06-26 */ + INT i; + + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] >= bufferFrameStart + numberTimeSlots) { /* FH 00-06-26 */ + *i_cmon = i; + break; + } + + /* keep track of transient: */ + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] >= tran) { + *i_tran = i; + break; + } else + *i_tran = EMPTY; +} + +/******************************************************************************* + Functionname: keepForFollowUp + ******************************************************************************* + + Description: + + Arguments: v_bordFollow + length_v_bordFollow + v_freqFollow + length_v_freqFollow + i_tranFollow + i_fillFollow + v_bord + length_v_bord + v_freq + i_cmon + i_tran + parts) + + Return: none + +*******************************************************************************/ +static void keepForFollowUp(INT *v_bordFollow, INT *length_v_bordFollow, + INT *v_freqFollow, INT *length_v_freqFollow, + INT *i_tranFollow, INT *i_fillFollow, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT i_cmon, + INT i_tran, INT parts, + INT numberTimeSlots) { /* FH 00-06-26 */ + INT L, i, j; + + L = *length_v_bord; + + (*length_v_bordFollow) = 0; + (*length_v_freqFollow) = 0; + + for (j = 0, i = i_cmon; i < L; i++, j++) { + v_bordFollow[j] = v_bord[i] - numberTimeSlots; /* FH 00-06-26 */ + v_freqFollow[j] = v_freq[i]; + (*length_v_bordFollow)++; + (*length_v_freqFollow)++; + } + if (i_tran != EMPTY) + *i_tranFollow = i_tran - i_cmon; + else + *i_tranFollow = EMPTY; + *i_fillFollow = L - (parts - 1) - i_cmon; +} + +/******************************************************************************* + Functionname: calcCtrlSignal + ******************************************************************************* + + Description: + + Arguments: hSbrGrid + frameClass + v_bord + length_v_bord + v_freq + length_v_freq + i_cmon + i_tran + spreadFlag + nL + + Return: none + +*******************************************************************************/ +static void calcCtrlSignal(HANDLE_SBR_GRID hSbrGrid, FRAME_CLASS frameClass, + INT *v_bord, INT length_v_bord, INT *v_freq, + INT length_v_freq, INT i_cmon, INT i_tran, + INT spreadFlag, INT nL) { + INT i, r, a, n, p, b, aL, aR, ntot, nmax, nR; + + INT *v_f = hSbrGrid->v_f; + INT *v_fLR = hSbrGrid->v_fLR; + INT *v_r = hSbrGrid->bs_rel_bord; + INT *v_rL = hSbrGrid->bs_rel_bord_0; + INT *v_rR = hSbrGrid->bs_rel_bord_1; + + INT length_v_r = 0; + INT length_v_rR = 0; + INT length_v_rL = 0; + + switch (frameClass) { + case FIXVAR: + /* absolute border: */ + + a = v_bord[i_cmon]; + + /* relative borders: */ + length_v_r = 0; + i = i_cmon; + + while (i >= 1) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight(v_r, &length_v_r, r); + i--; + } + + /* number of relative borders: */ + n = length_v_r; + + /* freq res: */ + for (i = 0; i < i_cmon; i++) v_f[i] = v_freq[i_cmon - 1 - i]; + v_f[i_cmon] = 1; + + /* pointer: */ + p = (i_cmon >= i_tran && i_tran != EMPTY) ? (i_cmon - i_tran + 1) : (0); + + hSbrGrid->frameClass = frameClass; + hSbrGrid->bs_abs_bord = a; + hSbrGrid->n = n; + hSbrGrid->p = p; + + break; + case VARFIX: + /* absolute border: */ + a = v_bord[0]; + + /* relative borders: */ + length_v_r = 0; + + for (i = 1; i < length_v_bord; i++) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight(v_r, &length_v_r, r); + } + + /* number of relative borders: */ + n = length_v_r; + + /* freq res: */ + FDKmemcpy(v_f, v_freq, length_v_freq * sizeof(INT)); + + /* pointer: */ + p = (i_tran >= 0 && i_tran != EMPTY) ? (i_tran + 1) : (0); + + hSbrGrid->frameClass = frameClass; + hSbrGrid->bs_abs_bord = a; + hSbrGrid->n = n; + hSbrGrid->p = p; + + break; + case VARVAR: + if (spreadFlag) { + /* absolute borders: */ + b = length_v_bord; + + aL = v_bord[0]; + aR = v_bord[b - 1]; + + /* number of relative borders: */ + ntot = b - 2; + + nmax = 2; /* n: {0,1,2} */ + if (ntot > nmax) { + nL = nmax; + nR = ntot - nmax; + } else { + nL = ntot; + nR = 0; + } + + /* relative borders: */ + length_v_rL = 0; + for (i = 1; i <= nL; i++) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight(v_rL, &length_v_rL, r); + } + + length_v_rR = 0; + i = b - 1; + while (i >= b - nR) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight(v_rR, &length_v_rR, r); + i--; + } + + /* pointer (only one due to constraint in frame info): */ + p = (i_tran > 0 && i_tran != EMPTY) ? (b - i_tran) : (0); + + /* freq res: */ + + for (i = 0; i < b - 1; i++) v_fLR[i] = v_freq[i]; + } else { + length_v_bord = i_cmon + 1; + + /* absolute borders: */ + b = length_v_bord; + + aL = v_bord[0]; + aR = v_bord[b - 1]; + + /* number of relative borders: */ + ntot = b - 2; + nR = ntot - nL; + + /* relative borders: */ + length_v_rL = 0; + for (i = 1; i <= nL; i++) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight(v_rL, &length_v_rL, r); + } + + length_v_rR = 0; + i = b - 1; + while (i >= b - nR) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight(v_rR, &length_v_rR, r); + i--; + } + + /* pointer (only one due to constraint in frame info): */ + p = (i_cmon >= i_tran && i_tran != EMPTY) ? (i_cmon - i_tran + 1) : (0); + + /* freq res: */ + for (i = 0; i < b - 1; i++) v_fLR[i] = v_freq[i]; + } + + hSbrGrid->frameClass = frameClass; + hSbrGrid->bs_abs_bord_0 = aL; + hSbrGrid->bs_abs_bord_1 = aR; + hSbrGrid->bs_num_rel_0 = nL; + hSbrGrid->bs_num_rel_1 = nR; + hSbrGrid->p = p; + + break; + + default: + /* do nothing */ + break; + } +} + +/******************************************************************************* + Functionname: createDefFrameInfo + ******************************************************************************* + + Description: Copies the default (static) frameInfo structs to the frameInfo + passed by reference; only used for FIXFIX frames + + Arguments: hFrameInfo - HANLDE_SBR_FRAME_INFO + nEnv - INT + nTimeSlots - INT + + Return: none; hSbrFrameInfo contains a copy of the default frameInfo + + Written: Andreas Schneider + Revised: +*******************************************************************************/ +static void createDefFrameInfo(HANDLE_SBR_FRAME_INFO hSbrFrameInfo, INT nEnv, + INT nTimeSlots) { + switch (nEnv) { + case 1: + switch (nTimeSlots) { + case NUMBER_TIME_SLOTS_1920: + FDKmemcpy(hSbrFrameInfo, &frameInfo1_1920, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2048: + FDKmemcpy(hSbrFrameInfo, &frameInfo1_2048, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_1152: + FDKmemcpy(hSbrFrameInfo, &frameInfo1_1152, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2304: + FDKmemcpy(hSbrFrameInfo, &frameInfo1_2304, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_512LD: + FDKmemcpy(hSbrFrameInfo, &frameInfo1_512LD, sizeof(SBR_FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 2: + switch (nTimeSlots) { + case NUMBER_TIME_SLOTS_1920: + FDKmemcpy(hSbrFrameInfo, &frameInfo2_1920, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2048: + FDKmemcpy(hSbrFrameInfo, &frameInfo2_2048, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_1152: + FDKmemcpy(hSbrFrameInfo, &frameInfo2_1152, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2304: + FDKmemcpy(hSbrFrameInfo, &frameInfo2_2304, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_512LD: + FDKmemcpy(hSbrFrameInfo, &frameInfo2_512LD, sizeof(SBR_FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 4: + switch (nTimeSlots) { + case NUMBER_TIME_SLOTS_1920: + FDKmemcpy(hSbrFrameInfo, &frameInfo4_1920, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2048: + FDKmemcpy(hSbrFrameInfo, &frameInfo4_2048, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_1152: + FDKmemcpy(hSbrFrameInfo, &frameInfo4_1152, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2304: + FDKmemcpy(hSbrFrameInfo, &frameInfo4_2304, sizeof(SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_512LD: + FDKmemcpy(hSbrFrameInfo, &frameInfo4_512LD, sizeof(SBR_FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + default: + FDK_ASSERT(0); + } +} + +/******************************************************************************* + Functionname: ctrlSignal2FrameInfo + ******************************************************************************* + + Description: Convert "clear-text" sbr_grid() to "frame info" used by the + envelope and noise floor estimators. + This is basically (except for "low level" calculations) the + bitstream decoder defined in the MPEG-4 standard, sub clause + 4.6.18.3.3, Time / Frequency Grid. See inline comments for + explanation of the shorten and noise border algorithms. + + Arguments: hSbrGrid - source + hSbrFrameInfo - destination + freq_res_fixfix - frequency resolution for FIXFIX frames + + Return: void; hSbrFrameInfo contains the updated FRAME_INFO struct + +*******************************************************************************/ +static void ctrlSignal2FrameInfo( + HANDLE_SBR_GRID hSbrGrid, /* input : the grid handle */ + HANDLE_SBR_FRAME_INFO hSbrFrameInfo, /* output: the frame info handle */ + FREQ_RES + *freq_res_fixfix /* in/out: frequency resolution for FIXFIX frames */ +) { + INT frameSplit = 0; + INT nEnv = 0, border = 0, i, k, p /*?*/; + INT *v_r = hSbrGrid->bs_rel_bord; + INT *v_f = hSbrGrid->v_f; + + FRAME_CLASS frameClass = hSbrGrid->frameClass; + INT bufferFrameStart = hSbrGrid->bufferFrameStart; + INT numberTimeSlots = hSbrGrid->numberTimeSlots; + + switch (frameClass) { + case FIXFIX: + createDefFrameInfo(hSbrFrameInfo, hSbrGrid->bs_num_env, numberTimeSlots); + + frameSplit = (hSbrFrameInfo->nEnvelopes > 1); + for (i = 0; i < hSbrFrameInfo->nEnvelopes; i++) { + hSbrGrid->v_f[i] = hSbrFrameInfo->freqRes[i] = + freq_res_fixfix[frameSplit]; + } + break; + + case FIXVAR: + case VARFIX: + nEnv = hSbrGrid->n + 1; /* read n [SBR_NUM_BITS bits] */ /*? snd*/ + FDK_ASSERT(nEnv <= MAX_ENVELOPES_FIXVAR_VARFIX); + + hSbrFrameInfo->nEnvelopes = nEnv; + + border = hSbrGrid->bs_abs_bord; /* read the absolute border */ + + if (nEnv == 1) + hSbrFrameInfo->nNoiseEnvelopes = 1; + else + hSbrFrameInfo->nNoiseEnvelopes = 2; + + break; + + default: + /* do nothing */ + break; + } + + switch (frameClass) { + case FIXVAR: + hSbrFrameInfo->borders[0] = + bufferFrameStart; /* start-position of 1st envelope */ + + hSbrFrameInfo->borders[nEnv] = border; + + for (k = 0, i = nEnv - 1; k < nEnv - 1; k++, i--) { + border -= v_r[k]; + hSbrFrameInfo->borders[i] = border; + } + + /* make either envelope nr. nEnv + 1 - p short; or don't shorten if p == 0 + */ + p = hSbrGrid->p; + if (p == 0) { + hSbrFrameInfo->shortEnv = 0; + } else { + hSbrFrameInfo->shortEnv = nEnv + 1 - p; + } + + for (k = 0, i = nEnv - 1; k < nEnv; k++, i--) { + hSbrFrameInfo->freqRes[i] = (FREQ_RES)v_f[k]; + } + + /* if either there is no short envelope or the last envelope is short... + */ + if (p == 0 || p == 1) { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv - 1]; + } else { + hSbrFrameInfo->bordersNoise[1] = + hSbrFrameInfo->borders[hSbrFrameInfo->shortEnv]; + } + + break; + + case VARFIX: + /* in this case 'border' indicates the start of the 1st envelope */ + hSbrFrameInfo->borders[0] = border; + + for (k = 0; k < nEnv - 1; k++) { + border += v_r[k]; + hSbrFrameInfo->borders[k + 1] = border; + } + + hSbrFrameInfo->borders[nEnv] = bufferFrameStart + numberTimeSlots; + + p = hSbrGrid->p; + if (p == 0 || p == 1) { + hSbrFrameInfo->shortEnv = 0; + } else { + hSbrFrameInfo->shortEnv = p - 1; + } + + for (k = 0; k < nEnv; k++) { + hSbrFrameInfo->freqRes[k] = (FREQ_RES)v_f[k]; + } + + switch (p) { + case 0: + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[1]; + break; + case 1: + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv - 1]; + break; + default: + hSbrFrameInfo->bordersNoise[1] = + hSbrFrameInfo->borders[hSbrFrameInfo->shortEnv]; + break; + } + break; + + case VARVAR: + nEnv = hSbrGrid->bs_num_rel_0 + hSbrGrid->bs_num_rel_1 + 1; + FDK_ASSERT(nEnv <= MAX_ENVELOPES_VARVAR); /* just to be sure */ + hSbrFrameInfo->nEnvelopes = nEnv; + + hSbrFrameInfo->borders[0] = border = hSbrGrid->bs_abs_bord_0; + + for (k = 0, i = 1; k < hSbrGrid->bs_num_rel_0; k++, i++) { + border += hSbrGrid->bs_rel_bord_0[k]; + hSbrFrameInfo->borders[i] = border; + } + + border = hSbrGrid->bs_abs_bord_1; + hSbrFrameInfo->borders[nEnv] = border; + + for (k = 0, i = nEnv - 1; k < hSbrGrid->bs_num_rel_1; k++, i--) { + border -= hSbrGrid->bs_rel_bord_1[k]; + hSbrFrameInfo->borders[i] = border; + } + + p = hSbrGrid->p; + if (p == 0) { + hSbrFrameInfo->shortEnv = 0; + } else { + hSbrFrameInfo->shortEnv = nEnv + 1 - p; + } + + for (k = 0; k < nEnv; k++) { + hSbrFrameInfo->freqRes[k] = (FREQ_RES)hSbrGrid->v_fLR[k]; + } + + if (nEnv == 1) { + hSbrFrameInfo->nNoiseEnvelopes = 1; + hSbrFrameInfo->bordersNoise[0] = hSbrGrid->bs_abs_bord_0; + hSbrFrameInfo->bordersNoise[1] = hSbrGrid->bs_abs_bord_1; + } else { + hSbrFrameInfo->nNoiseEnvelopes = 2; + hSbrFrameInfo->bordersNoise[0] = hSbrGrid->bs_abs_bord_0; + + if (p == 0 || p == 1) { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv - 1]; + } else { + hSbrFrameInfo->bordersNoise[1] = + hSbrFrameInfo->borders[hSbrFrameInfo->shortEnv]; + } + hSbrFrameInfo->bordersNoise[2] = hSbrGrid->bs_abs_bord_1; + } + break; + + default: + /* do nothing */ + break; + } + + if (frameClass == VARFIX || frameClass == FIXVAR) { + hSbrFrameInfo->bordersNoise[0] = hSbrFrameInfo->borders[0]; + if (nEnv == 1) { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv]; + } else { + hSbrFrameInfo->bordersNoise[2] = hSbrFrameInfo->borders[nEnv]; + } + } +} diff --git a/fdk-aac/libSBRenc/src/fram_gen.h b/fdk-aac/libSBRenc/src/fram_gen.h new file mode 100644 index 0000000..0c5edc3 --- /dev/null +++ b/fdk-aac/libSBRenc/src/fram_gen.h @@ -0,0 +1,343 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Framing generator prototypes and structs $Revision: 92790 $ +*/ +#ifndef FRAM_GEN_H +#define FRAM_GEN_H + +#include "sbr_def.h" /* for MAX_ENVELOPES and MAX_NOISE_ENVELOPES in struct FRAME_INFO and CODEC_TYPE */ +#include "sbr_encoder.h" /* for FREQ_RES */ + +#define MAX_ENVELOPES_VARVAR \ + MAX_ENVELOPES /*!< worst case number of envelopes in a VARVAR frame */ +#define MAX_ENVELOPES_FIXVAR_VARFIX \ + 4 /*!< worst case number of envelopes in VARFIX and FIXVAR frames */ +#define MAX_NUM_REL \ + 3 /*!< maximum number of relative borders in any VAR frame */ + +/* SBR frame class definitions */ +typedef enum { + FIXFIX = + 0, /*!< bs_frame_class: leading and trailing frame borders are fixed */ + FIXVAR, /*!< bs_frame_class: leading frame border is fixed, trailing frame + border is variable */ + VARFIX, /*!< bs_frame_class: leading frame border is variable, trailing frame + border is fixed */ + VARVAR /*!< bs_frame_class: leading and trailing frame borders are variable */ + , + FIXFIXonly /*!< bs_frame_class: leading border fixed (0), trailing border + fixed (nrTimeSlots) and encased borders are dynamically derived + from the tranPos */ +} FRAME_CLASS; + +/* helper constants */ +#define DC 4711 /*!< helper constant: don't care */ +#define EMPTY (-99) /*!< helper constant: empty */ + +/* system constants: AAC+SBR, DRM Frame-Length */ +#define FRAME_MIDDLE_SLOT_1920 4 +#define NUMBER_TIME_SLOTS_1920 15 + +#define LD_PRETRAN_OFF 3 +#define FRAME_MIDDLE_SLOT_512LD 4 +#define NUMBER_TIME_SLOTS_512LD 8 +#define TRANSIENT_OFFSET_LD 0 + +/* +system constants: AAC+SBR or aacPRO (hybrid format), Standard Frame-Length, +Multi-Rate +--------------------------------------------------------------------------- +Number of slots (numberTimeSlots): 16 (NUMBER_TIME_SLOTS_2048) +Detector-offset (frameMiddleSlot): 4 +Overlap : 3 +Buffer-offset : 8 (BUFFER_FRAME_START_2048 = 0) + + + |<------------tranPos---------->| + |c|d|e|f|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f| + FixFix | | + FixVar | :<- ->: + VarFix :<- ->: | + VarVar :<- ->: :<- ->: + 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 +................................................................................ + +|-|-|-|-|-|-|-|-B-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-B-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| + +frame-generator:0 16 24 32 +analysis-buffer:8 24 32 40 +*/ +#define FRAME_MIDDLE_SLOT_2048 4 +#define NUMBER_TIME_SLOTS_2048 16 + +/* +system constants: mp3PRO, Multi-Rate & Single-Rate +-------------------------------------------------- +Number of slots (numberTimeSlots): 9 (NUMBER_TIME_SLOTS_1152) +Detector-offset (frameMiddleSlot): 4 (FRAME_MIDDLE_SLOT_1152) +Overlap : 3 +Buffer-offset : 4.5 (BUFFER_FRAME_START_1152 = 0) + + + |<----tranPos---->| + |5|6|7|8|0|1|2|3|4|5|6|7|8| + FixFix | | + FixVar | :<- ->: + VarFix :<- ->: | + VarVar :<- ->: :<- ->: + 0 1 2 3 4 5 6 7 8 0 1 2 3 + ............................................. + + -|-|-|-|-B-|-|-|-|-|-|-|-|-B-|-|-|-|-|-|-|-|-| + +frame-generator: 0 9 13 18 +analysis-buffer: 4.5 13.5 22.5 +*/ +#define FRAME_MIDDLE_SLOT_1152 4 +#define NUMBER_TIME_SLOTS_1152 9 + +/* system constants: Layer2+SBR */ +#define FRAME_MIDDLE_SLOT_2304 8 +#define NUMBER_TIME_SLOTS_2304 18 + +/*! + \struct SBR_GRID + \brief sbr_grid() signals to be converted to bitstream elements + + The variables hold the signals (e.g. lengths and numbers) in "clear text" +*/ + +typedef struct { + /* system constants */ + INT bufferFrameStart; /*!< frame generator vs analysis buffer time alignment + (currently set to 0, offset added elsewhere) */ + INT numberTimeSlots; /*!< number of SBR timeslots per frame */ + + /* will be adjusted for every frame */ + FRAME_CLASS frameClass; /*!< SBR frame class */ + INT bs_num_env; /*!< bs_num_env, number of envelopes for FIXFIX */ + INT bs_abs_bord; /*!< bs_abs_bord, absolute border for VARFIX and FIXVAR */ + INT n; /*!< number of relative borders for VARFIX and FIXVAR */ + INT p; /*!< pointer-to-transient-border */ + INT bs_rel_bord[MAX_NUM_REL]; /*!< bs_rel_bord, relative borders for all VAR + */ + INT v_f[MAX_ENVELOPES_FIXVAR_VARFIX]; /*!< envelope frequency resolutions for + FIXVAR and VARFIX */ + + INT bs_abs_bord_0; /*!< bs_abs_bord_0, leading absolute border for VARVAR */ + INT bs_abs_bord_1; /*!< bs_abs_bord_1, trailing absolute border for VARVAR */ + INT bs_num_rel_0; /*!< bs_num_rel_0, number of relative borders associated + with leading absolute border for VARVAR */ + INT bs_num_rel_1; /*!< bs_num_rel_1, number of relative borders associated + with trailing absolute border for VARVAR */ + INT bs_rel_bord_0[MAX_NUM_REL]; /*!< bs_rel_bord_0, relative borders + associated with leading absolute border + for VARVAR */ + INT bs_rel_bord_1[MAX_NUM_REL]; /*!< bs_rel_bord_1, relative borders + associated with trailing absolute border + for VARVAR */ + INT v_fLR[MAX_ENVELOPES_VARVAR]; /*!< envelope frequency resolutions for + VARVAR */ + +} SBR_GRID; +typedef SBR_GRID *HANDLE_SBR_GRID; + +/*! + \struct SBR_FRAME_INFO + \brief time/frequency grid description for one frame +*/ +typedef struct { + INT nEnvelopes; /*!< number of envelopes */ + INT borders[MAX_ENVELOPES + 1]; /*!< envelope borders in SBR timeslots */ + FREQ_RES freqRes[MAX_ENVELOPES]; /*!< frequency resolution of each envelope */ + INT shortEnv; /*!< number of an envelope to be shortened (starting at 1) or 0 + for no shortened envelope */ + INT nNoiseEnvelopes; /*!< number of noise floors */ + INT bordersNoise[MAX_NOISE_ENVELOPES + + 1]; /*!< noise floor borders in SBR timeslots */ +} SBR_FRAME_INFO; +/* WARNING: When rearranging the elements of this struct keep in mind that the + * static initializations in the corresponding C-file have to be rearranged as + * well! snd 2002/01/23 + */ +typedef SBR_FRAME_INFO *HANDLE_SBR_FRAME_INFO; + +/*! + \struct SBR_ENVELOPE_FRAME + \brief frame generator main struct + + Contains tuning parameters, time/frequency grid description, sbr_grid() + bitstream elements, and generator internal signals +*/ +typedef struct { + /* system constants */ + INT frameMiddleSlot; /*!< transient detector offset in SBR timeslots */ + + /* basic tuning parameters */ + INT staticFraming; /*!< 1: run static framing in time, i.e. exclusive use of + bs_frame_class = FIXFIX */ + INT numEnvStatic; /*!< number of envelopes per frame for static framing */ + FREQ_RES + freq_res_fixfix[2]; /*!< envelope frequency resolution to use for + bs_frame_class = FIXFIX; single env and split */ + UCHAR + fResTransIsLow; /*!< frequency resolution for transient frames - always + low (0) or according to table (1) */ + + /* expert tuning parameters */ + const int *v_tuningSegm; /*!< segment lengths to use around transient */ + const int *v_tuningFreq; /*!< frequency resolutions to use around transient */ + INT dmin; /*!< minimum length of dependent segments */ + INT dmax; /*!< maximum length of dependent segments */ + INT allowSpread; /*!< 1: allow isolated transient to influence grid of 3 + consecutive frames */ + + /* internally used signals */ + FRAME_CLASS frameClassOld; /*!< frame class used for previous frame */ + INT spreadFlag; /*!< 1: use VARVAR instead of VARFIX to follow up old + transient */ + + INT v_bord[2 * MAX_ENVELOPES_VARVAR + 1]; /*!< borders for current frame and + preliminary borders for next + frame (fixed borders excluded) */ + INT length_v_bord; /*!< helper variable: length of v_bord */ + INT v_freq[2 * MAX_ENVELOPES_VARVAR + 1]; /*!< frequency resolutions for + current frame and preliminary + resolutions for next frame */ + INT length_v_freq; /*!< helper variable: length of v_freq */ + + INT v_bordFollow[MAX_ENVELOPES_VARVAR]; /*!< preliminary borders for current + frame (calculated during previous + frame) */ + INT length_v_bordFollow; /*!< helper variable: length of v_bordFollow */ + INT i_tranFollow; /*!< points to transient border in v_bordFollow (may be + negative, see keepForFollowUp()) */ + INT i_fillFollow; /*!< points to first fill border in v_bordFollow */ + INT v_freqFollow[MAX_ENVELOPES_VARVAR]; /*!< preliminary frequency resolutions + for current frame (calculated + during previous frame) */ + INT length_v_freqFollow; /*!< helper variable: length of v_freqFollow */ + + /* externally needed signals */ + SBR_GRID + SbrGrid; /*!< sbr_grid() signals to be converted to bitstream elements */ + SBR_FRAME_INFO + SbrFrameInfo; /*!< time/frequency grid description for one frame */ +} SBR_ENVELOPE_FRAME; +typedef SBR_ENVELOPE_FRAME *HANDLE_SBR_ENVELOPE_FRAME; + +void FDKsbrEnc_initFrameInfoGenerator(HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + INT allowSpread, INT numEnvStatic, + INT staticFraming, INT timeSlots, + const FREQ_RES *freq_res_fixfix, + UCHAR fResTransIsLow, INT ldGrid); + +HANDLE_SBR_FRAME_INFO +FDKsbrEnc_frameInfoGenerator(HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + UCHAR *v_transient_info, const INT rightBorderFIX, + UCHAR *v_transient_info_pre, int ldGrid, + const int *v_tuning); + +#endif diff --git a/fdk-aac/libSBRenc/src/invf_est.cpp b/fdk-aac/libSBRenc/src/invf_est.cpp new file mode 100644 index 0000000..53b47ac --- /dev/null +++ b/fdk-aac/libSBRenc/src/invf_est.cpp @@ -0,0 +1,610 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "invf_est.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +#define MAX_NUM_REGIONS 10 +#define SCALE_FAC_QUO 512.0f +#define SCALE_FAC_NRG 256.0f + +#ifndef min +#define min(a, b) (a < b ? a : b) +#endif + +#ifndef max +#define max(a, b) (a > b ? a : b) +#endif + +static const FIXP_DBL quantStepsSbr[4] = { + 0x00400000, 0x02800000, 0x03800000, + 0x04c00000}; /* table scaled with SCALE_FAC_QUO */ +static const FIXP_DBL quantStepsOrig[4] = { + 0x00000000, 0x00c00000, 0x01c00000, + 0x02800000}; /* table scaled with SCALE_FAC_QUO */ +static const FIXP_DBL nrgBorders[4] = { + 0x0c800000, 0x0f000000, 0x11800000, + 0x14000000}; /* table scaled with SCALE_FAC_NRG */ + +static const DETECTOR_PARAMETERS detectorParamsAAC = { + quantStepsSbr, + quantStepsOrig, + nrgBorders, + 4, /* Number of borders SBR. */ + 4, /* Number of borders orig. */ + 4, /* Number of borders Nrg. */ + { + /* Region space. */ + {INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, + INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF} /* | */ + }, /*------------------------ regionOrig ---------------------------------*/ + { + /* Region space transient. */ + {INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF} /* | */ + }, /*------------------------ regionOrig ---------------------------------*/ + {-4, -3, -2, -1, + 0} /* Reduction factor of the inverse filtering for low energies.*/ +}; + +static const FIXP_DBL hysteresis = + 0x00400000; /* Delta value for hysteresis. scaled with SCALE_FAC_QUO */ + +/* + * AAC+SBR PARAMETERS for Speech + *********************************/ +static const DETECTOR_PARAMETERS detectorParamsAACSpeech = { + quantStepsSbr, + quantStepsOrig, + nrgBorders, + 4, /* Number of borders SBR. */ + 4, /* Number of borders orig. */ + 4, /* Number of borders Nrg. */ + { + /* Region space. */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF} /* | */ + }, /*------------------------ regionOrig ---------------------------------*/ + { + /* Region space transient. */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, + INVF_OFF} /* | */ + }, /*------------------------ regionOrig ---------------------------------*/ + {-4, -3, -2, -1, + 0} /* Reduction factor of the inverse filtering for low energies.*/ +}; + +/* + * Smoothing filters. + ************************/ +typedef const FIXP_DBL FIR_FILTER[5]; + +static const FIR_FILTER fir_0 = {0x7fffffff, 0x00000000, 0x00000000, 0x00000000, + 0x00000000}; +static const FIR_FILTER fir_1 = {0x2aaaaa80, 0x555554ff, 0x00000000, 0x00000000, + 0x00000000}; +static const FIR_FILTER fir_2 = {0x10000000, 0x30000000, 0x40000000, 0x00000000, + 0x00000000}; +static const FIR_FILTER fir_3 = {0x077f80e8, 0x199999a0, 0x2bb3b240, 0x33333340, + 0x00000000}; +static const FIR_FILTER fir_4 = {0x04130598, 0x0ebdb000, 0x1becfa60, 0x2697a4c0, + 0x2aaaaa80}; + +static const FIR_FILTER *const fir_table[5] = {&fir_0, &fir_1, &fir_2, &fir_3, + &fir_4}; + +/**************************************************************************/ +/*! + \brief Calculates the values used for the detector. + + + \return none + +*/ +/**************************************************************************/ +static void calculateDetectorValues( + FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the tonality values of the + original. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + FIXP_DBL *nrgVector, /*!< Energy vector. */ + DETECTOR_VALUES *detectorValues, /*!< pointer to DETECTOR_VALUES struct. */ + INT startChannel, /*!< Start channel. */ + INT stopChannel, /*!< Stop channel. */ + INT startIndex, /*!< Start index. */ + INT stopIndex, /*!< Stop index. */ + INT numberOfStrongest /*!< The number of sorted tonal components to be + considered. */ +) { + INT i, temp, j; + + const FIXP_DBL *filter = *fir_table[INVF_SMOOTHING_LENGTH]; + FIXP_DBL origQuotaMeanStrongest, sbrQuotaMeanStrongest; + FIXP_DBL origQuota, sbrQuota; + FIXP_DBL invIndex, invChannel, invTemp; + FIXP_DBL quotaVecOrig[64], quotaVecSbr[64]; + + FDKmemclear(quotaVecOrig, 64 * sizeof(FIXP_DBL)); + FDKmemclear(quotaVecSbr, 64 * sizeof(FIXP_DBL)); + + invIndex = GetInvInt(stopIndex - startIndex); + invChannel = GetInvInt(stopChannel - startChannel); + + /* + Calculate the mean value, over the current time segment, for the original, + the HFR and the difference, over all channels in the current frequency range. + NOTE: the averaging is done on the values quota/(1 - quota + RELAXATION). + */ + + /* The original, the sbr signal and the total energy */ + detectorValues->avgNrg = FL2FXCONST_DBL(0.0f); + for (j = startIndex; j < stopIndex; j++) { + for (i = startChannel; i < stopChannel; i++) { + quotaVecOrig[i] += fMult(quotaMatrixOrig[j][i], invIndex); + + if (indexVector[i] != -1) + quotaVecSbr[i] += fMult(quotaMatrixOrig[j][indexVector[i]], invIndex); + } + detectorValues->avgNrg += fMult(nrgVector[j], invIndex); + } + + /* + Calculate the mean value, over the current frequency range, for the original, + the HFR and the difference. Also calculate the same mean values for the three + vectors, but only includeing the x strongest copmponents. + */ + + origQuota = FL2FXCONST_DBL(0.0f); + sbrQuota = FL2FXCONST_DBL(0.0f); + for (i = startChannel; i < stopChannel; i++) { + origQuota += fMultDiv2(quotaVecOrig[i], invChannel); + sbrQuota += fMultDiv2(quotaVecSbr[i], invChannel); + } + + /* + Calculate the mean value for the x strongest components + */ + FDKsbrEnc_Shellsort_fract(quotaVecOrig + startChannel, + stopChannel - startChannel); + FDKsbrEnc_Shellsort_fract(quotaVecSbr + startChannel, + stopChannel - startChannel); + + origQuotaMeanStrongest = FL2FXCONST_DBL(0.0f); + sbrQuotaMeanStrongest = FL2FXCONST_DBL(0.0f); + + temp = min(stopChannel - startChannel, numberOfStrongest); + invTemp = GetInvInt(temp); + + for (i = 0; i < temp; i++) { + origQuotaMeanStrongest += + fMultDiv2(quotaVecOrig[i + stopChannel - temp], invTemp); + sbrQuotaMeanStrongest += + fMultDiv2(quotaVecSbr[i + stopChannel - temp], invTemp); + } + + /* + The value for the strongest component + */ + detectorValues->origQuotaMax = quotaVecOrig[stopChannel - 1]; + detectorValues->sbrQuotaMax = quotaVecSbr[stopChannel - 1]; + + /* + Buffer values + */ + FDKmemmove(detectorValues->origQuotaMean, detectorValues->origQuotaMean + 1, + INVF_SMOOTHING_LENGTH * sizeof(FIXP_DBL)); + FDKmemmove(detectorValues->sbrQuotaMean, detectorValues->sbrQuotaMean + 1, + INVF_SMOOTHING_LENGTH * sizeof(FIXP_DBL)); + FDKmemmove(detectorValues->origQuotaMeanStrongest, + detectorValues->origQuotaMeanStrongest + 1, + INVF_SMOOTHING_LENGTH * sizeof(FIXP_DBL)); + FDKmemmove(detectorValues->sbrQuotaMeanStrongest, + detectorValues->sbrQuotaMeanStrongest + 1, + INVF_SMOOTHING_LENGTH * sizeof(FIXP_DBL)); + + detectorValues->origQuotaMean[INVF_SMOOTHING_LENGTH] = origQuota << 1; + detectorValues->sbrQuotaMean[INVF_SMOOTHING_LENGTH] = sbrQuota << 1; + detectorValues->origQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] = + origQuotaMeanStrongest << 1; + detectorValues->sbrQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] = + sbrQuotaMeanStrongest << 1; + + /* + Filter values + */ + detectorValues->origQuotaMeanFilt = FL2FXCONST_DBL(0.0f); + detectorValues->sbrQuotaMeanFilt = FL2FXCONST_DBL(0.0f); + detectorValues->origQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f); + detectorValues->sbrQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f); + + for (i = 0; i < INVF_SMOOTHING_LENGTH + 1; i++) { + detectorValues->origQuotaMeanFilt += + fMult(detectorValues->origQuotaMean[i], filter[i]); + detectorValues->sbrQuotaMeanFilt += + fMult(detectorValues->sbrQuotaMean[i], filter[i]); + detectorValues->origQuotaMeanStrongestFilt += + fMult(detectorValues->origQuotaMeanStrongest[i], filter[i]); + detectorValues->sbrQuotaMeanStrongestFilt += + fMult(detectorValues->sbrQuotaMeanStrongest[i], filter[i]); + } +} + +/**************************************************************************/ +/*! + \brief Returns the region in which the input value belongs. + + + + \return region. + +*/ +/**************************************************************************/ +static INT findRegion( + FIXP_DBL currVal, /*!< The current value. */ + const FIXP_DBL *borders, /*!< The border of the regions. */ + const INT numBorders /*!< The number of borders. */ +) { + INT i; + + if (currVal < borders[0]) { + return 0; + } + + for (i = 1; i < numBorders; i++) { + if (currVal >= borders[i - 1] && currVal < borders[i]) { + return i; + } + } + + if (currVal >= borders[numBorders - 1]) { + return numBorders; + } + + return 0; /* We never get here, it's just to avoid compiler warnings.*/ +} + +/**************************************************************************/ +/*! + \brief Makes a clever decision based on the quota vector. + + + \return decision on which invf mode to use + +*/ +/**************************************************************************/ +static INVF_MODE decisionAlgorithm( + const DETECTOR_PARAMETERS + *detectorParams, /*!< Struct with the detector parameters. */ + DETECTOR_VALUES *detectorValues, /*!< Struct with the detector values. */ + INT transientFlag, /*!< Flag indicating if there is a transient present.*/ + INT *prevRegionSbr, /*!< The previous region in which the Sbr value was. */ + INT *prevRegionOrig /*!< The previous region in which the Orig value was. */ +) { + INT invFiltLevel, regionSbr, regionOrig, regionNrg; + + /* + Current thresholds. + */ + const INT numRegionsSbr = detectorParams->numRegionsSbr; + const INT numRegionsOrig = detectorParams->numRegionsOrig; + const INT numRegionsNrg = detectorParams->numRegionsNrg; + + FIXP_DBL quantStepsSbrTmp[MAX_NUM_REGIONS]; + FIXP_DBL quantStepsOrigTmp[MAX_NUM_REGIONS]; + + /* + Current detector values. + */ + FIXP_DBL origQuotaMeanFilt; + FIXP_DBL sbrQuotaMeanFilt; + FIXP_DBL nrg; + + /* 0.375 = 3.0 / 8.0; 0.31143075889 = log2(RELAXATION)/64.0; 0.625 = + * log(16)/64.0; 0.6875 = 44/64.0 */ + origQuotaMeanFilt = + (fMultDiv2(FL2FXCONST_DBL(2.f * 0.375f), + (FIXP_DBL)(CalcLdData(max(detectorValues->origQuotaMeanFilt, + (FIXP_DBL)1)) + + FL2FXCONST_DBL(0.31143075889f)))) + << 0; /* scaled by 1/2^9 */ + sbrQuotaMeanFilt = + (fMultDiv2(FL2FXCONST_DBL(2.f * 0.375f), + (FIXP_DBL)(CalcLdData(max(detectorValues->sbrQuotaMeanFilt, + (FIXP_DBL)1)) + + FL2FXCONST_DBL(0.31143075889f)))) + << 0; /* scaled by 1/2^9 */ + /* If energy is zero then we will get different results for different word + * lengths. */ + nrg = + (fMultDiv2(FL2FXCONST_DBL(2.f * 0.375f), + (FIXP_DBL)(CalcLdData(detectorValues->avgNrg + (FIXP_DBL)1) + + FL2FXCONST_DBL(0.0625f) + FL2FXCONST_DBL(0.6875f)))) + << 0; /* scaled by 1/2^8; 2^44 -> qmf energy scale */ + + FDKmemcpy(quantStepsSbrTmp, detectorParams->quantStepsSbr, + numRegionsSbr * sizeof(FIXP_DBL)); + FDKmemcpy(quantStepsOrigTmp, detectorParams->quantStepsOrig, + numRegionsOrig * sizeof(FIXP_DBL)); + + if (*prevRegionSbr < numRegionsSbr) + quantStepsSbrTmp[*prevRegionSbr] = + detectorParams->quantStepsSbr[*prevRegionSbr] + hysteresis; + if (*prevRegionSbr > 0) + quantStepsSbrTmp[*prevRegionSbr - 1] = + detectorParams->quantStepsSbr[*prevRegionSbr - 1] - hysteresis; + + if (*prevRegionOrig < numRegionsOrig) + quantStepsOrigTmp[*prevRegionOrig] = + detectorParams->quantStepsOrig[*prevRegionOrig] + hysteresis; + if (*prevRegionOrig > 0) + quantStepsOrigTmp[*prevRegionOrig - 1] = + detectorParams->quantStepsOrig[*prevRegionOrig - 1] - hysteresis; + + regionSbr = findRegion(sbrQuotaMeanFilt, quantStepsSbrTmp, numRegionsSbr); + regionOrig = findRegion(origQuotaMeanFilt, quantStepsOrigTmp, numRegionsOrig); + regionNrg = findRegion(nrg, detectorParams->nrgBorders, numRegionsNrg); + + *prevRegionSbr = regionSbr; + *prevRegionOrig = regionOrig; + + /* Use different settings if a transient is present*/ + invFiltLevel = + (transientFlag == 1) + ? detectorParams->regionSpaceTransient[regionSbr][regionOrig] + : detectorParams->regionSpace[regionSbr][regionOrig]; + + /* Compensate for low energy.*/ + invFiltLevel = + max(invFiltLevel + detectorParams->EnergyCompFactor[regionNrg], 0); + + return (INVF_MODE)(invFiltLevel); +} + +/**************************************************************************/ +/*! + \brief Estiamtion of the inverse filtering level required + in the decoder. + + A second order LPC is calculated for every filterbank channel, using + the covariance method. THe ratio between the energy of the predicted + signal and the energy of the non-predictable signal is calcualted. + + \return none. + +*/ +/**************************************************************************/ +void FDKsbrEnc_qmfInverseFilteringDetector( + HANDLE_SBR_INV_FILT_EST + hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */ + FIXP_DBL **quotaMatrix, /*!< The matrix holding the tonality values of the + original. */ + FIXP_DBL *nrgVector, /*!< The energy vector. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + INT startIndex, /*!< Start index. */ + INT stopIndex, /*!< Stop index. */ + INT transientFlag, /*!< Flag indicating if a transient is present or not.*/ + INVF_MODE *infVec /*!< Vector holding the inverse filtering levels. */ +) { + INT band; + + /* + * Do the inverse filtering level estimation. + *****************************************************/ + for (band = 0; band < hInvFilt->noDetectorBands; band++) { + INT startChannel = hInvFilt->freqBandTableInvFilt[band]; + INT stopChannel = hInvFilt->freqBandTableInvFilt[band + 1]; + + calculateDetectorValues(quotaMatrix, indexVector, nrgVector, + &hInvFilt->detectorValues[band], startChannel, + stopChannel, startIndex, stopIndex, + hInvFilt->numberOfStrongest); + + infVec[band] = decisionAlgorithm( + hInvFilt->detectorParams, &hInvFilt->detectorValues[band], + transientFlag, &hInvFilt->prevRegionSbr[band], + &hInvFilt->prevRegionOrig[band]); + } +} + +/**************************************************************************/ +/*! + \brief Initialize an instance of the inverse filtering level estimator. + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +INT FDKsbrEnc_initInvFiltDetector( + HANDLE_SBR_INV_FILT_EST + hInvFilt, /*!< Pointer to a handle to the SBR_INV_FILT_EST struct. */ + INT *freqBandTableDetector, /*!< Frequency band table for the inverse + filtering. */ + INT numDetectorBands, /*!< Number of inverse filtering bands. */ + UINT + useSpeechConfig /*!< Flag: adapt tuning parameters according to speech*/ +) { + INT i; + + FDKmemclear(hInvFilt, sizeof(SBR_INV_FILT_EST)); + + hInvFilt->detectorParams = + (useSpeechConfig) ? &detectorParamsAACSpeech : &detectorParamsAAC; + + hInvFilt->noDetectorBandsMax = numDetectorBands; + + /* + Memory initialisation + */ + for (i = 0; i < hInvFilt->noDetectorBandsMax; i++) { + FDKmemclear(&hInvFilt->detectorValues[i], sizeof(DETECTOR_VALUES)); + hInvFilt->prevInvfMode[i] = INVF_OFF; + hInvFilt->prevRegionOrig[i] = 0; + hInvFilt->prevRegionSbr[i] = 0; + } + + /* + Reset the inverse fltering detector. + */ + FDKsbrEnc_resetInvFiltDetector(hInvFilt, freqBandTableDetector, + hInvFilt->noDetectorBandsMax); + + return (0); +} + +/**************************************************************************/ +/*! + \brief resets sbr inverse filtering structure. + + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +INT FDKsbrEnc_resetInvFiltDetector( + HANDLE_SBR_INV_FILT_EST + hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */ + INT *freqBandTableDetector, /*!< Frequency band table for the inverse + filtering. */ + INT numDetectorBands) /*!< Number of inverse filtering bands. */ +{ + hInvFilt->numberOfStrongest = 1; + FDKmemcpy(hInvFilt->freqBandTableInvFilt, freqBandTableDetector, + (numDetectorBands + 1) * sizeof(INT)); + hInvFilt->noDetectorBands = numDetectorBands; + + return (0); +} diff --git a/fdk-aac/libSBRenc/src/invf_est.h b/fdk-aac/libSBRenc/src/invf_est.h new file mode 100644 index 0000000..3ab6726 --- /dev/null +++ b/fdk-aac/libSBRenc/src/invf_est.h @@ -0,0 +1,181 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Inverse Filtering detection prototypes $Revision: 92790 $ +*/ +#ifndef INVF_EST_H +#define INVF_EST_H + +#include "sbr_encoder.h" +#include "sbr_def.h" + +#define INVF_SMOOTHING_LENGTH 2 + +typedef struct { + const FIXP_DBL *quantStepsSbr; + const FIXP_DBL *quantStepsOrig; + const FIXP_DBL *nrgBorders; + INT numRegionsSbr; + INT numRegionsOrig; + INT numRegionsNrg; + INVF_MODE regionSpace[5][5]; + INVF_MODE regionSpaceTransient[5][5]; + INT EnergyCompFactor[5]; + +} DETECTOR_PARAMETERS; + +typedef struct { + FIXP_DBL origQuotaMean[INVF_SMOOTHING_LENGTH + 1]; + FIXP_DBL sbrQuotaMean[INVF_SMOOTHING_LENGTH + 1]; + FIXP_DBL origQuotaMeanStrongest[INVF_SMOOTHING_LENGTH + 1]; + FIXP_DBL sbrQuotaMeanStrongest[INVF_SMOOTHING_LENGTH + 1]; + + FIXP_DBL origQuotaMeanFilt; + FIXP_DBL sbrQuotaMeanFilt; + FIXP_DBL origQuotaMeanStrongestFilt; + FIXP_DBL sbrQuotaMeanStrongestFilt; + + FIXP_DBL origQuotaMax; + FIXP_DBL sbrQuotaMax; + + FIXP_DBL avgNrg; +} DETECTOR_VALUES; + +typedef struct { + INT numberOfStrongest; + + INT prevRegionSbr[MAX_NUM_NOISE_VALUES]; + INT prevRegionOrig[MAX_NUM_NOISE_VALUES]; + + INT freqBandTableInvFilt[MAX_NUM_NOISE_VALUES]; + INT noDetectorBands; + INT noDetectorBandsMax; + + const DETECTOR_PARAMETERS *detectorParams; + + INVF_MODE prevInvfMode[MAX_NUM_NOISE_VALUES]; + DETECTOR_VALUES detectorValues[MAX_NUM_NOISE_VALUES]; + + FIXP_DBL nrgAvg; + FIXP_DBL wmQmf[MAX_NUM_NOISE_VALUES]; +} SBR_INV_FILT_EST; + +typedef SBR_INV_FILT_EST *HANDLE_SBR_INV_FILT_EST; + +void FDKsbrEnc_qmfInverseFilteringDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, + FIXP_DBL **quotaMatrix, + FIXP_DBL *nrgVector, + SCHAR *indexVector, INT startIndex, + INT stopIndex, INT transientFlag, + INVF_MODE *infVec); + +INT FDKsbrEnc_initInvFiltDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, + INT *freqBandTableDetector, + INT numDetectorBands, UINT useSpeechConfig); + +INT FDKsbrEnc_resetInvFiltDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, + INT *freqBandTableDetector, + INT numDetectorBands); + +#endif /* _QMF_INV_FILT_H */ diff --git a/fdk-aac/libSBRenc/src/mh_det.cpp b/fdk-aac/libSBRenc/src/mh_det.cpp new file mode 100644 index 0000000..2f3b386 --- /dev/null +++ b/fdk-aac/libSBRenc/src/mh_det.cpp @@ -0,0 +1,1396 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "mh_det.h" + +#include "sbrenc_ram.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +#define SFM_SHIFT 2 /* Attention: SFM_SCALE depends on SFM_SHIFT */ +#define SFM_SCALE (MAXVAL_DBL >> SFM_SHIFT) /* 1.0 >> SFM_SHIFT */ + +/*!< Detector Parameters for AAC core codec. */ +static const DETECTOR_PARAMETERS_MH paramsAac = { + 9, /*!< deltaTime */ + { + FL2FXCONST_DBL(20.0f * RELAXATION_FLOAT), /*!< thresHoldDiff */ + FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< thresHoldDiffGuide */ + FL2FXCONST_DBL(15.0f * RELAXATION_FLOAT), /*!< thresHoldTone */ + FL2FXCONST_DBL((1.0f / 15.0f) * + RELAXATION_FLOAT), /*!< invThresHoldTone */ + FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< thresHoldToneGuide */ + FL2FXCONST_DBL(0.3f) >> SFM_SHIFT, /*!< sfmThresSbr */ + FL2FXCONST_DBL(0.1f) >> SFM_SHIFT, /*!< sfmThresOrig */ + FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */ + FL2FXCONST_DBL(0.5f), /*!< decayGuideDiff */ + FL2FXCONST_DBL(-0.000112993269), + /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */ + FL2FXCONST_DBL(-0.000112993269), + /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */ + FL2FXCONST_DBL( + -0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!< + derivThresAboveLD64 + */ + }, + 50 /*!< maxComp */ +}; + +/*!< Detector Parameters for AAC LD core codec. */ +static const DETECTOR_PARAMETERS_MH paramsAacLd = { + 16, /*!< Delta time. */ + { + FL2FXCONST_DBL(25.0f * RELAXATION_FLOAT), /*!< thresHoldDiff */ + FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< tresHoldDiffGuide */ + FL2FXCONST_DBL(15.0f * RELAXATION_FLOAT), /*!< thresHoldTone */ + FL2FXCONST_DBL((1.0f / 15.0f) * + RELAXATION_FLOAT), /*!< invThresHoldTone */ + FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< thresHoldToneGuide */ + FL2FXCONST_DBL(0.3f) >> SFM_SHIFT, /*!< sfmThresSbr */ + FL2FXCONST_DBL(0.1f) >> SFM_SHIFT, /*!< sfmThresOrig */ + FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */ + FL2FXCONST_DBL(0.2f), /*!< decayGuideDiff */ + FL2FXCONST_DBL(-0.000112993269), + /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */ + FL2FXCONST_DBL(-0.000112993269), + /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */ + FL2FXCONST_DBL( + -0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!< + derivThresAboveLD64 + */ + }, + 50 /*!< maxComp */ +}; + +/**************************************************************************/ +/*! + \brief Calculates the difference in tonality between original and SBR + for a given time and frequency region. + + The values for pDiffMapped2Scfb are scaled by RELAXATION + + \return none. + +*/ +/**************************************************************************/ +static void diff(FIXP_DBL *RESTRICT pTonalityOrig, FIXP_DBL *pDiffMapped2Scfb, + const UCHAR *RESTRICT pFreqBandTable, INT nScfb, + SCHAR *indexVector) { + UCHAR i, ll, lu, k; + FIXP_DBL maxValOrig, maxValSbr, tmp; + INT scale; + + for (i = 0; i < nScfb; i++) { + ll = pFreqBandTable[i]; + lu = pFreqBandTable[i + 1]; + + maxValOrig = FL2FXCONST_DBL(0.0f); + maxValSbr = FL2FXCONST_DBL(0.0f); + + for (k = ll; k < lu; k++) { + maxValOrig = fixMax(maxValOrig, pTonalityOrig[k]); + maxValSbr = fixMax(maxValSbr, pTonalityOrig[indexVector[k]]); + } + + if ((maxValSbr >= RELAXATION)) { + tmp = fDivNorm(maxValOrig, maxValSbr, &scale); + pDiffMapped2Scfb[i] = + scaleValue(fMult(tmp, RELAXATION_FRACT), + fixMax(-(DFRACT_BITS - 1), (scale - RELAXATION_SHIFT))); + } else { + pDiffMapped2Scfb[i] = maxValOrig; + } + } +} + +/**************************************************************************/ +/*! + \brief Calculates a flatness measure of the tonality measures. + + Calculation of the power function and using scalefactor for basis: + Using log2: + z = (2^k * x)^y; + z' = CalcLd(z) = y*CalcLd(x) + y*k; + z = CalcInvLd(z'); + + Using ld64: + z = (2^k * x)^y; + z' = CalcLd64(z) = y*CalcLd64(x)/64 + y*k/64; + z = CalcInvLd64(z'); + + The values pSfmOrigVec and pSfmSbrVec are scaled by the factor 1/4.0 + + \return none. + +*/ +/**************************************************************************/ +static void calculateFlatnessMeasure(FIXP_DBL *pQuotaBuffer, SCHAR *indexVector, + FIXP_DBL *pSfmOrigVec, + FIXP_DBL *pSfmSbrVec, + const UCHAR *pFreqBandTable, INT nSfb) { + INT i, j; + FIXP_DBL invBands, tmp1, tmp2; + INT shiftFac0, shiftFacSum0; + INT shiftFac1, shiftFacSum1; + FIXP_DBL accu; + + for (i = 0; i < nSfb; i++) { + INT ll = pFreqBandTable[i]; + INT lu = pFreqBandTable[i + 1]; + pSfmOrigVec[i] = (FIXP_DBL)(MAXVAL_DBL >> 2); + pSfmSbrVec[i] = (FIXP_DBL)(MAXVAL_DBL >> 2); + + if (lu - ll > 1) { + FIXP_DBL amOrig, amTransp, gmOrig, gmTransp, sfmOrig, sfmTransp; + invBands = GetInvInt(lu - ll); + shiftFacSum0 = 0; + shiftFacSum1 = 0; + amOrig = amTransp = FL2FXCONST_DBL(0.0f); + gmOrig = gmTransp = (FIXP_DBL)MAXVAL_DBL; + + for (j = ll; j < lu; j++) { + sfmOrig = pQuotaBuffer[j]; + sfmTransp = pQuotaBuffer[indexVector[j]]; + + amOrig += fMult(sfmOrig, invBands); + amTransp += fMult(sfmTransp, invBands); + + shiftFac0 = CountLeadingBits(sfmOrig); + shiftFac1 = CountLeadingBits(sfmTransp); + + gmOrig = fMult(gmOrig, sfmOrig << shiftFac0); + gmTransp = fMult(gmTransp, sfmTransp << shiftFac1); + + shiftFacSum0 += shiftFac0; + shiftFacSum1 += shiftFac1; + } + + if (gmOrig > FL2FXCONST_DBL(0.0f)) { + tmp1 = CalcLdData(gmOrig); /* CalcLd64(x)/64 */ + tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */ + + /* y*k/64 */ + accu = (FIXP_DBL)-shiftFacSum0 << (DFRACT_BITS - 1 - 8); + tmp2 = fMultDiv2(invBands, accu) << (2 + 1); + + tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */ + gmOrig = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */ + } else { + gmOrig = FL2FXCONST_DBL(0.0f); + } + + if (gmTransp > FL2FXCONST_DBL(0.0f)) { + tmp1 = CalcLdData(gmTransp); /* CalcLd64(x)/64 */ + tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */ + + /* y*k/64 */ + accu = (FIXP_DBL)-shiftFacSum1 << (DFRACT_BITS - 1 - 8); + tmp2 = fMultDiv2(invBands, accu) << (2 + 1); + + tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */ + gmTransp = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */ + } else { + gmTransp = FL2FXCONST_DBL(0.0f); + } + if (amOrig != FL2FXCONST_DBL(0.0f)) + pSfmOrigVec[i] = + FDKsbrEnc_LSI_divide_scale_fract(gmOrig, amOrig, SFM_SCALE); + + if (amTransp != FL2FXCONST_DBL(0.0f)) + pSfmSbrVec[i] = + FDKsbrEnc_LSI_divide_scale_fract(gmTransp, amTransp, SFM_SCALE); + } + } +} + +/**************************************************************************/ +/*! + \brief Calculates the input to the missing harmonics detection. + + + \return none. + +*/ +/**************************************************************************/ +static void calculateDetectorInput( + FIXP_DBL **RESTRICT pQuotaBuffer, /*!< Pointer to tonality matrix. */ + SCHAR *RESTRICT indexVector, FIXP_DBL **RESTRICT tonalityDiff, + FIXP_DBL **RESTRICT pSfmOrig, FIXP_DBL **RESTRICT pSfmSbr, + const UCHAR *freqBandTable, INT nSfb, INT noEstPerFrame, INT move) { + INT est; + + /* + New estimate. + */ + for (est = 0; est < noEstPerFrame; est++) { + diff(pQuotaBuffer[est + move], tonalityDiff[est + move], freqBandTable, + nSfb, indexVector); + + calculateFlatnessMeasure(pQuotaBuffer[est + move], indexVector, + pSfmOrig[est + move], pSfmSbr[est + move], + freqBandTable, nSfb); + } +} + +/**************************************************************************/ +/*! + \brief Checks that the detection is not due to a LP filter + + This function determines if a newly detected missing harmonics is not + in fact just a low-pass filtere input signal. If so, the detection is + removed. + + \return none. + +*/ +/**************************************************************************/ +static void removeLowPassDetection(UCHAR *RESTRICT pAddHarmSfb, + UCHAR **RESTRICT pDetectionVectors, + INT start, INT stop, INT nSfb, + const UCHAR *RESTRICT pFreqBandTable, + FIXP_DBL *RESTRICT pNrgVector, + THRES_HOLDS mhThresh) + +{ + INT i, est; + INT maxDerivPos = pFreqBandTable[nSfb]; + INT numBands = pFreqBandTable[nSfb]; + FIXP_DBL nrgLow, nrgHigh; + FIXP_DBL nrgLD64, nrgLowLD64, nrgHighLD64, nrgDiffLD64; + FIXP_DBL valLD64, maxValLD64, maxValAboveLD64; + INT bLPsignal = 0; + + maxValLD64 = FL2FXCONST_DBL(-1.0f); + for (i = numBands - 1 - 2; i > pFreqBandTable[0]; i--) { + nrgLow = pNrgVector[i]; + nrgHigh = pNrgVector[i + 2]; + + if (nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh) { + nrgLowLD64 = CalcLdData(nrgLow >> 1); + nrgDiffLD64 = CalcLdData((nrgLow >> 1) - (nrgHigh >> 1)); + valLD64 = nrgDiffLD64 - nrgLowLD64; + if (valLD64 > maxValLD64) { + maxDerivPos = i; + maxValLD64 = valLD64; + } + if (maxValLD64 > mhThresh.derivThresMaxLD64) { + break; + } + } + } + + /* Find the largest "gradient" above. (should be relatively flat, hence we + expect a low value if the signal is LP.*/ + maxValAboveLD64 = FL2FXCONST_DBL(-1.0f); + for (i = numBands - 1 - 2; i > maxDerivPos + 2; i--) { + nrgLow = pNrgVector[i]; + nrgHigh = pNrgVector[i + 2]; + + if (nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh) { + nrgLowLD64 = CalcLdData(nrgLow >> 1); + nrgDiffLD64 = CalcLdData((nrgLow >> 1) - (nrgHigh >> 1)); + valLD64 = nrgDiffLD64 - nrgLowLD64; + if (valLD64 > maxValAboveLD64) { + maxValAboveLD64 = valLD64; + } + } else { + if (nrgHigh != FL2FXCONST_DBL(0.0f) && nrgHigh > nrgLow) { + nrgHighLD64 = CalcLdData(nrgHigh >> 1); + nrgDiffLD64 = CalcLdData((nrgHigh >> 1) - (nrgLow >> 1)); + valLD64 = nrgDiffLD64 - nrgHighLD64; + if (valLD64 > maxValAboveLD64) { + maxValAboveLD64 = valLD64; + } + } + } + } + + if (maxValLD64 > mhThresh.derivThresMaxLD64 && + maxValAboveLD64 < mhThresh.derivThresAboveLD64) { + bLPsignal = 1; + + for (i = maxDerivPos - 1; i > maxDerivPos - 5 && i >= 0; i--) { + if (pNrgVector[i] != FL2FXCONST_DBL(0.0f) && + pNrgVector[i] > pNrgVector[maxDerivPos + 2]) { + nrgDiffLD64 = CalcLdData((pNrgVector[i] >> 1) - + (pNrgVector[maxDerivPos + 2] >> 1)); + nrgLD64 = CalcLdData(pNrgVector[i] >> 1); + valLD64 = nrgDiffLD64 - nrgLD64; + if (valLD64 < mhThresh.derivThresBelowLD64) { + bLPsignal = 0; + break; + } + } else { + bLPsignal = 0; + break; + } + } + } + + if (bLPsignal) { + for (i = 0; i < nSfb; i++) { + if (maxDerivPos >= pFreqBandTable[i] && + maxDerivPos < pFreqBandTable[i + 1]) + break; + } + + if (pAddHarmSfb[i]) { + pAddHarmSfb[i] = 0; + for (est = start; est < stop; est++) { + pDetectionVectors[est][i] = 0; + } + } + } +} + +/**************************************************************************/ +/*! + \brief Checks if it is allowed to detect a missing tone, that wasn't + detected previously. + + + \return newDetectionAllowed flag. + +*/ +/**************************************************************************/ +static INT isDetectionOfNewToneAllowed( + const SBR_FRAME_INFO *pFrameInfo, INT *pDetectionStartPos, + INT noEstPerFrame, INT prevTransientFrame, INT prevTransientPos, + INT prevTransientFlag, INT transientPosOffset, INT transientFlag, + INT transientPos, INT deltaTime, + HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector) { + INT transientFrame, newDetectionAllowed; + + /* Determine if this is a frame where a transient starts... + * If the transient flag was set the previous frame but not the + * transient frame flag, the transient frame flag is set in the current frame. + *****************************************************************************/ + transientFrame = 0; + if (transientFlag) { + if (transientPos + transientPosOffset < + pFrameInfo->borders[pFrameInfo->nEnvelopes]) { + transientFrame = 1; + if (noEstPerFrame > 1) { + if (transientPos + transientPosOffset > + h_sbrMissingHarmonicsDetector->timeSlots >> 1) { + *pDetectionStartPos = noEstPerFrame; + } else { + *pDetectionStartPos = noEstPerFrame >> 1; + } + + } else { + *pDetectionStartPos = noEstPerFrame; + } + } + } else { + if (prevTransientFlag && !prevTransientFrame) { + transientFrame = 1; + *pDetectionStartPos = 0; + } + } + + /* + * Determine if detection of new missing harmonics are allowed. + * If the frame contains a transient it's ok. If the previous + * frame contained a transient it needs to be sufficiently close + * to the start of the current frame. + ****************************************************************/ + newDetectionAllowed = 0; + if (transientFrame) { + newDetectionAllowed = 1; + } else { + if (prevTransientFrame && + fixp_abs(pFrameInfo->borders[0] - + (prevTransientPos + transientPosOffset - + h_sbrMissingHarmonicsDetector->timeSlots)) < deltaTime) { + newDetectionAllowed = 1; + *pDetectionStartPos = 0; + } + } + + h_sbrMissingHarmonicsDetector->previousTransientFlag = transientFlag; + h_sbrMissingHarmonicsDetector->previousTransientFrame = transientFrame; + h_sbrMissingHarmonicsDetector->previousTransientPos = transientPos; + + return (newDetectionAllowed); +} + +/**************************************************************************/ +/*! + \brief Cleans up the detection after a transient. + + + \return none. + +*/ +/**************************************************************************/ +static void transientCleanUp(FIXP_DBL **quotaBuffer, INT nSfb, + UCHAR **detectionVectors, UCHAR *pAddHarmSfb, + UCHAR *pPrevAddHarmSfb, INT **signBuffer, + const UCHAR *pFreqBandTable, INT start, INT stop, + INT newDetectionAllowed, FIXP_DBL *pNrgVector, + THRES_HOLDS mhThresh) { + INT i, j, est; + + for (est = start; est < stop; est++) { + for (i = 0; i < nSfb; i++) { + pAddHarmSfb[i] = pAddHarmSfb[i] || detectionVectors[est][i]; + } + } + + if (newDetectionAllowed == 1) { + /* + * Check for duplication of sines located + * on the border of two scf-bands. + *************************************************/ + for (i = 0; i < nSfb - 1; i++) { + /* detection in adjacent channels.*/ + if (pAddHarmSfb[i] && pAddHarmSfb[i + 1]) { + FIXP_DBL maxVal1, maxVal2; + INT maxPos1, maxPos2, maxPosTime1, maxPosTime2; + + INT li = pFreqBandTable[i]; + INT ui = pFreqBandTable[i + 1]; + + /* Find maximum tonality in the the two scf bands.*/ + maxPosTime1 = start; + maxPos1 = li; + maxVal1 = quotaBuffer[start][li]; + for (est = start; est < stop; est++) { + for (j = li; j < ui; j++) { + if (quotaBuffer[est][j] > maxVal1) { + maxVal1 = quotaBuffer[est][j]; + maxPos1 = j; + maxPosTime1 = est; + } + } + } + + li = pFreqBandTable[i + 1]; + ui = pFreqBandTable[i + 2]; + + /* Find maximum tonality in the the two scf bands.*/ + maxPosTime2 = start; + maxPos2 = li; + maxVal2 = quotaBuffer[start][li]; + for (est = start; est < stop; est++) { + for (j = li; j < ui; j++) { + if (quotaBuffer[est][j] > maxVal2) { + maxVal2 = quotaBuffer[est][j]; + maxPos2 = j; + maxPosTime2 = est; + } + } + } + + /* If the maximum values are in adjacent QMF-channels, we need to remove + the lowest of the two.*/ + if (maxPos2 - maxPos1 < 2) { + if (pPrevAddHarmSfb[i] == 1 && pPrevAddHarmSfb[i + 1] == 0) { + /* Keep the lower, remove the upper.*/ + pAddHarmSfb[i + 1] = 0; + for (est = start; est < stop; est++) { + detectionVectors[est][i + 1] = 0; + } + } else { + if (pPrevAddHarmSfb[i] == 0 && pPrevAddHarmSfb[i + 1] == 1) { + /* Keep the upper, remove the lower.*/ + pAddHarmSfb[i] = 0; + for (est = start; est < stop; est++) { + detectionVectors[est][i] = 0; + } + } else { + /* If the maximum values are in adjacent QMF-channels, and if the + signs indicate that it is the same sine, we need to remove the + lowest of the two.*/ + if (maxVal1 > maxVal2) { + if (signBuffer[maxPosTime1][maxPos2] < 0 && + signBuffer[maxPosTime1][maxPos1] > 0) { + /* Keep the lower, remove the upper.*/ + pAddHarmSfb[i + 1] = 0; + for (est = start; est < stop; est++) { + detectionVectors[est][i + 1] = 0; + } + } + } else { + if (signBuffer[maxPosTime2][maxPos2] < 0 && + signBuffer[maxPosTime2][maxPos1] > 0) { + /* Keep the upper, remove the lower.*/ + pAddHarmSfb[i] = 0; + for (est = start; est < stop; est++) { + detectionVectors[est][i] = 0; + } + } + } + } + } + } + } + } + + /* Make sure that the detection is not the cut-off of a low pass filter. */ + removeLowPassDetection(pAddHarmSfb, detectionVectors, start, stop, nSfb, + pFreqBandTable, pNrgVector, mhThresh); + } else { + /* + * If a missing harmonic wasn't missing the previous frame + * the transient-flag needs to be set in order to be allowed to detect it. + *************************************************************************/ + for (i = 0; i < nSfb; i++) { + if (pAddHarmSfb[i] - pPrevAddHarmSfb[i] > 0) pAddHarmSfb[i] = 0; + } + } +} + +/*****************************************************************************/ +/*! + \brief Detection for one tonality estimate. + + This is the actual missing harmonics detection, using information from the + previous detection. + + If a missing harmonic was detected (in a previous frame) due to too high + tonality differences, but there was not enough tonality difference in the + current frame, the detection algorithm still continues to trace the strongest + tone in the scalefactor band (assuming that this is the tone that is going to + be replaced in the decoder). This is done to avoid abrupt endings of sines + fading out (e.g. in the glockenspiel). + + The function also tries to estimate where one sine is going to be replaced + with multiple sines (due to the patching). This is done by comparing the + tonality flatness measure of the original and the SBR signal. + + The function also tries to estimate (for the scalefactor bands only + containing one qmf subband) when a strong tone in the original will be + replaced by a strong tone in the adjacent QMF subband. + + \return none. + +*/ +/**************************************************************************/ +static void detection(FIXP_DBL *quotaBuffer, FIXP_DBL *pDiffVecScfb, INT nSfb, + UCHAR *pHarmVec, const UCHAR *pFreqBandTable, + FIXP_DBL *sfmOrig, FIXP_DBL *sfmSbr, + GUIDE_VECTORS guideVectors, GUIDE_VECTORS newGuideVectors, + THRES_HOLDS mhThresh) { + INT i, j, ll, lu; + FIXP_DBL thresTemp, thresOrig; + + /* + * Do detection on the difference vector, i.e. the difference between + * the original and the transposed. + *********************************************************************/ + for (i = 0; i < nSfb; i++) { + thresTemp = (guideVectors.guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)) + ? fMax(fMult(mhThresh.decayGuideDiff, + guideVectors.guideVectorDiff[i]), + mhThresh.thresHoldDiffGuide) + : mhThresh.thresHoldDiff; + + thresTemp = fMin(thresTemp, mhThresh.thresHoldDiff); + + if (pDiffVecScfb[i] > thresTemp) { + pHarmVec[i] = 1; + newGuideVectors.guideVectorDiff[i] = pDiffVecScfb[i]; + } else { + /* If the guide wasn't zero, but the current level is to low, + start tracking the decay on the tone in the original rather + than the difference.*/ + if (guideVectors.guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)) { + guideVectors.guideVectorOrig[i] = mhThresh.thresHoldToneGuide; + } + } + } + + /* + * Trace tones in the original signal that at one point + * have been detected because they will be replaced by + * multiple tones in the sbr signal. + ****************************************************/ + + for (i = 0; i < nSfb; i++) { + ll = pFreqBandTable[i]; + lu = pFreqBandTable[i + 1]; + + thresOrig = + fixMax(fMult(guideVectors.guideVectorOrig[i], mhThresh.decayGuideOrig), + mhThresh.thresHoldToneGuide); + thresOrig = fixMin(thresOrig, mhThresh.thresHoldTone); + + if (guideVectors.guideVectorOrig[i] != FL2FXCONST_DBL(0.0f)) { + for (j = ll; j < lu; j++) { + if (quotaBuffer[j] > thresOrig) { + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[j]; + } + } + } + } + + /* + * Check for multiple sines in the transposed signal, + * where there is only one in the original. + ****************************************************/ + thresOrig = mhThresh.thresHoldTone; + + for (i = 0; i < nSfb; i++) { + ll = pFreqBandTable[i]; + lu = pFreqBandTable[i + 1]; + + if (pHarmVec[i] == 0) { + if (lu - ll > 1) { + for (j = ll; j < lu; j++) { + if (quotaBuffer[j] > thresOrig && + (sfmSbr[i] > mhThresh.sfmThresSbr && + sfmOrig[i] < mhThresh.sfmThresOrig)) { + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[j]; + } + } + } else { + if (i < nSfb - 1) { + ll = pFreqBandTable[i]; + + if (i > 0) { + if (quotaBuffer[ll] > mhThresh.thresHoldTone && + (pDiffVecScfb[i + 1] < mhThresh.invThresHoldTone || + pDiffVecScfb[i - 1] < mhThresh.invThresHoldTone)) { + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll]; + } + } else { + if (quotaBuffer[ll] > mhThresh.thresHoldTone && + pDiffVecScfb[i + 1] < mhThresh.invThresHoldTone) { + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll]; + } + } + } + } + } + } +} + +/**************************************************************************/ +/*! + \brief Do detection for every tonality estimate, using forward prediction. + + + \return none. + +*/ +/**************************************************************************/ +static void detectionWithPrediction( + FIXP_DBL **quotaBuffer, FIXP_DBL **pDiffVecScfb, INT **signBuffer, INT nSfb, + const UCHAR *pFreqBandTable, FIXP_DBL **sfmOrig, FIXP_DBL **sfmSbr, + UCHAR **detectionVectors, UCHAR *pPrevAddHarmSfb, + GUIDE_VECTORS *guideVectors, INT noEstPerFrame, INT detectionStart, + INT totNoEst, INT newDetectionAllowed, INT *pAddHarmFlag, + UCHAR *pAddHarmSfb, FIXP_DBL *pNrgVector, + const DETECTOR_PARAMETERS_MH *mhParams) { + INT est = 0, i; + INT start; + + FDKmemclear(pAddHarmSfb, nSfb * sizeof(UCHAR)); + + if (newDetectionAllowed) { + /* Since we don't want to use the transient region for detection (since the + tonality values tend to be a bit unreliable for this region) the + guide-values are copied to the current starting point. */ + if (totNoEst > 1) { + start = detectionStart + 1; + + if (start != 0) { + FDKmemcpy(guideVectors[start].guideVectorDiff, + guideVectors[0].guideVectorDiff, nSfb * sizeof(FIXP_DBL)); + FDKmemcpy(guideVectors[start].guideVectorOrig, + guideVectors[0].guideVectorOrig, nSfb * sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[start - 1].guideVectorDetected, + nSfb * sizeof(UCHAR)); + } + } else { + start = 0; + } + } else { + start = 0; + } + + for (est = start; est < totNoEst; est++) { + /* + * Do detection on the current frame using + * guide-info from the previous. + *******************************************/ + if (est > 0) { + FDKmemcpy(guideVectors[est].guideVectorDetected, + detectionVectors[est - 1], nSfb * sizeof(UCHAR)); + } + + FDKmemclear(detectionVectors[est], nSfb * sizeof(UCHAR)); + + if (est < totNoEst - 1) { + FDKmemclear(guideVectors[est + 1].guideVectorDiff, + nSfb * sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est + 1].guideVectorOrig, + nSfb * sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est + 1].guideVectorDetected, + nSfb * sizeof(UCHAR)); + + detection(quotaBuffer[est], pDiffVecScfb[est], nSfb, + detectionVectors[est], pFreqBandTable, sfmOrig[est], + sfmSbr[est], guideVectors[est], guideVectors[est + 1], + mhParams->thresHolds); + } else { + FDKmemclear(guideVectors[est].guideVectorDiff, nSfb * sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est].guideVectorOrig, nSfb * sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est].guideVectorDetected, nSfb * sizeof(UCHAR)); + + detection(quotaBuffer[est], pDiffVecScfb[est], nSfb, + detectionVectors[est], pFreqBandTable, sfmOrig[est], + sfmSbr[est], guideVectors[est], guideVectors[est], + mhParams->thresHolds); + } + } + + /* Clean up the detection.*/ + transientCleanUp(quotaBuffer, nSfb, detectionVectors, pAddHarmSfb, + pPrevAddHarmSfb, signBuffer, pFreqBandTable, start, totNoEst, + newDetectionAllowed, pNrgVector, mhParams->thresHolds); + + /* Set flag... */ + *pAddHarmFlag = 0; + for (i = 0; i < nSfb; i++) { + if (pAddHarmSfb[i]) { + *pAddHarmFlag = 1; + break; + } + } + + FDKmemcpy(pPrevAddHarmSfb, pAddHarmSfb, nSfb * sizeof(UCHAR)); + FDKmemcpy(guideVectors[0].guideVectorDetected, pAddHarmSfb, + nSfb * sizeof(INT)); + + for (i = 0; i < nSfb; i++) { + guideVectors[0].guideVectorDiff[i] = FL2FXCONST_DBL(0.0f); + guideVectors[0].guideVectorOrig[i] = FL2FXCONST_DBL(0.0f); + + if (pAddHarmSfb[i] == 1) { + /* If we had a detection use the guide-value in the next frame from the + last estimate were the detection was done.*/ + for (est = start; est < totNoEst; est++) { + if (guideVectors[est].guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)) { + guideVectors[0].guideVectorDiff[i] = + guideVectors[est].guideVectorDiff[i]; + } + if (guideVectors[est].guideVectorOrig[i] != FL2FXCONST_DBL(0.0f)) { + guideVectors[0].guideVectorOrig[i] = + guideVectors[est].guideVectorOrig[i]; + } + } + } + } +} + +/**************************************************************************/ +/*! + \brief Calculates a compensation vector for the energy data. + + This function calculates a compensation vector for the energy data (i.e. + envelope data) that is calculated elsewhere. This is since, one sine on + the border of two scalefactor bands, will be replace by one sine in the + middle of either scalefactor band. However, since the sine that is replaced + will influence the energy estimate in both scalefactor bands (in the envelops + calculation function) a compensation value is required in order to avoid + noise substitution in the decoder next to the synthetic sine. + + \return none. + +*/ +/**************************************************************************/ +static void calculateCompVector(UCHAR *pAddHarmSfb, FIXP_DBL **pTonalityMatrix, + INT **pSignMatrix, UCHAR *pEnvComp, INT nSfb, + const UCHAR *freqBandTable, INT totNoEst, + INT maxComp, UCHAR *pPrevEnvComp, + INT newDetectionAllowed) { + INT scfBand, est, l, ll, lu, maxPosF, maxPosT; + FIXP_DBL maxVal; + INT compValue; + FIXP_DBL tmp; + + FDKmemclear(pEnvComp, nSfb * sizeof(UCHAR)); + + for (scfBand = 0; scfBand < nSfb; scfBand++) { + if (pAddHarmSfb[scfBand]) { /* A missing sine was detected */ + ll = freqBandTable[scfBand]; + lu = freqBandTable[scfBand + 1]; + + maxPosF = 0; /* First find the maximum*/ + maxPosT = 0; + maxVal = FL2FXCONST_DBL(0.0f); + + for (est = 0; est < totNoEst; est++) { + for (l = ll; l < lu; l++) { + if (pTonalityMatrix[est][l] > maxVal) { + maxVal = pTonalityMatrix[est][l]; + maxPosF = l; + maxPosT = est; + } + } + } + + /* + * If the maximum tonality is at the lower border of the + * scalefactor band, we check the sign of the adjacent channels + * to see if this sine is shared by the lower channel. If so, the + * energy of the single sine will be present in two scalefactor bands + * in the SBR data, which will cause problems in the decoder, when we + * add a sine to just one of the channels. + *********************************************************************/ + if (maxPosF == ll && scfBand) { + if (!pAddHarmSfb[scfBand - 1]) { /* No detection below*/ + if (pSignMatrix[maxPosT][maxPosF - 1] > 0 && + pSignMatrix[maxPosT][maxPosF] < 0) { + /* The comp value is calulated as the tonallity value, i.e we want + to reduce the envelope data for this channel with as much as the + tonality that is spread from the channel above. (ld64(RELAXATION) + = 0.31143075889) */ + tmp = fixp_abs( + (FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF - 1]) + + RELAXATION_LD64); + tmp = (tmp >> (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1)) + + (FIXP_DBL)1; /* shift one bit less for rounding */ + compValue = ((INT)(LONG)tmp) >> 1; + + /* limit the comp-value*/ + if (compValue > maxComp) compValue = maxComp; + + pEnvComp[scfBand - 1] = compValue; + } + } + } + + /* + * Same as above, but for the upper end of the scalefactor-band. + ***************************************************************/ + if (maxPosF == lu - 1 && scfBand + 1 < nSfb) { /* Upper border*/ + if (!pAddHarmSfb[scfBand + 1]) { + if (pSignMatrix[maxPosT][maxPosF] > 0 && + pSignMatrix[maxPosT][maxPosF + 1] < 0) { + tmp = fixp_abs( + (FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF + 1]) + + RELAXATION_LD64); + tmp = (tmp >> (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1)) + + (FIXP_DBL)1; /* shift one bit less for rounding */ + compValue = ((INT)(LONG)tmp) >> 1; + + if (compValue > maxComp) compValue = maxComp; + + pEnvComp[scfBand + 1] = compValue; + } + } + } + } + } + + if (newDetectionAllowed == 0) { + for (scfBand = 0; scfBand < nSfb; scfBand++) { + if (pEnvComp[scfBand] != 0 && pPrevEnvComp[scfBand] == 0) + pEnvComp[scfBand] = 0; + } + } + + /* remember the value for the next frame.*/ + FDKmemcpy(pPrevEnvComp, pEnvComp, nSfb * sizeof(UCHAR)); +} + +/**************************************************************************/ +/*! + \brief Detects where strong tonal components will be missing after + HFR in the decoder. + + + \return none. + +*/ +/**************************************************************************/ +void FDKsbrEnc_SbrMissingHarmonicsDetectorQmf( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMHDet, FIXP_DBL **pQuotaBuffer, + INT **pSignBuffer, SCHAR *indexVector, const SBR_FRAME_INFO *pFrameInfo, + const UCHAR *pTranInfo, INT *pAddHarmonicsFlag, + UCHAR *pAddHarmonicsScaleFactorBands, const UCHAR *freqBandTable, INT nSfb, + UCHAR *envelopeCompensation, FIXP_DBL *pNrgVector) { + INT transientFlag = pTranInfo[1]; + INT transientPos = pTranInfo[0]; + INT newDetectionAllowed; + INT transientDetStart = 0; + + UCHAR **detectionVectors = h_sbrMHDet->detectionVectors; + INT move = h_sbrMHDet->move; + INT noEstPerFrame = h_sbrMHDet->noEstPerFrame; + INT totNoEst = h_sbrMHDet->totNoEst; + INT prevTransientFlag = h_sbrMHDet->previousTransientFlag; + INT prevTransientFrame = h_sbrMHDet->previousTransientFrame; + INT transientPosOffset = h_sbrMHDet->transientPosOffset; + INT prevTransientPos = h_sbrMHDet->previousTransientPos; + GUIDE_VECTORS *guideVectors = h_sbrMHDet->guideVectors; + INT deltaTime = h_sbrMHDet->mhParams->deltaTime; + INT maxComp = h_sbrMHDet->mhParams->maxComp; + + int est; + + /* + Buffer values. + */ + FDK_ASSERT(move <= (MAX_NO_OF_ESTIMATES >> 1)); + FDK_ASSERT(noEstPerFrame <= (MAX_NO_OF_ESTIMATES >> 1)); + + FIXP_DBL *sfmSbr[MAX_NO_OF_ESTIMATES]; + FIXP_DBL *sfmOrig[MAX_NO_OF_ESTIMATES]; + FIXP_DBL *tonalityDiff[MAX_NO_OF_ESTIMATES]; + + for (est = 0; est < MAX_NO_OF_ESTIMATES / 2; est++) { + sfmSbr[est] = h_sbrMHDet->sfmSbr[est]; + sfmOrig[est] = h_sbrMHDet->sfmOrig[est]; + tonalityDiff[est] = h_sbrMHDet->tonalityDiff[est]; + } + + C_ALLOC_SCRATCH_START(_scratch, FIXP_DBL, + 3 * MAX_NO_OF_ESTIMATES / 2 * MAX_FREQ_COEFFS) + FIXP_DBL *scratch = _scratch; + for (; est < MAX_NO_OF_ESTIMATES; est++) { + sfmSbr[est] = scratch; + scratch += MAX_FREQ_COEFFS; + sfmOrig[est] = scratch; + scratch += MAX_FREQ_COEFFS; + tonalityDiff[est] = scratch; + scratch += MAX_FREQ_COEFFS; + } + + /* Determine if we're allowed to detect "missing harmonics" that wasn't + detected before. In order to be allowed to do new detection, there must be + a transient in the current frame, or a transient in the previous frame + sufficiently close to the current frame. */ + newDetectionAllowed = isDetectionOfNewToneAllowed( + pFrameInfo, &transientDetStart, noEstPerFrame, prevTransientFrame, + prevTransientPos, prevTransientFlag, transientPosOffset, transientFlag, + transientPos, deltaTime, h_sbrMHDet); + + /* Calulate the variables that will be used subsequently for the actual + * detection */ + calculateDetectorInput(pQuotaBuffer, indexVector, tonalityDiff, sfmOrig, + sfmSbr, freqBandTable, nSfb, noEstPerFrame, move); + + /* Do the actual detection using information from previous detections */ + detectionWithPrediction(pQuotaBuffer, tonalityDiff, pSignBuffer, nSfb, + freqBandTable, sfmOrig, sfmSbr, detectionVectors, + h_sbrMHDet->guideScfb, guideVectors, noEstPerFrame, + transientDetStart, totNoEst, newDetectionAllowed, + pAddHarmonicsFlag, pAddHarmonicsScaleFactorBands, + pNrgVector, h_sbrMHDet->mhParams); + + /* Calculate the comp vector, so that the energy can be + compensated for a sine between two QMF-bands. */ + calculateCompVector(pAddHarmonicsScaleFactorBands, pQuotaBuffer, pSignBuffer, + envelopeCompensation, nSfb, freqBandTable, totNoEst, + maxComp, h_sbrMHDet->prevEnvelopeCompensation, + newDetectionAllowed); + + for (est = 0; est < move; est++) { + FDKmemcpy(tonalityDiff[est], tonalityDiff[est + noEstPerFrame], + sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); + FDKmemcpy(sfmOrig[est], sfmOrig[est + noEstPerFrame], + sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); + FDKmemcpy(sfmSbr[est], sfmSbr[est + noEstPerFrame], + sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); + } + C_ALLOC_SCRATCH_END(_scratch, FIXP_DBL, + 3 * MAX_NO_OF_ESTIMATES / 2 * MAX_FREQ_COEFFS) +} + +/**************************************************************************/ +/*! + \brief Initialize an instance of the missing harmonics detector. + + + \return errorCode, noError if OK. + +*/ +/**************************************************************************/ +INT FDKsbrEnc_CreateSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, INT chan) { + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; + INT i; + + UCHAR *detectionVectors = GetRam_Sbr_detectionVectors(chan); + UCHAR *guideVectorDetected = GetRam_Sbr_guideVectorDetected(chan); + FIXP_DBL *guideVectorDiff = GetRam_Sbr_guideVectorDiff(chan); + FIXP_DBL *guideVectorOrig = GetRam_Sbr_guideVectorOrig(chan); + + FDKmemclear(hs, sizeof(SBR_MISSING_HARMONICS_DETECTOR)); + + hs->prevEnvelopeCompensation = GetRam_Sbr_prevEnvelopeCompensation(chan); + hs->guideScfb = GetRam_Sbr_guideScfb(chan); + + if ((NULL == detectionVectors) || (NULL == guideVectorDetected) || + (NULL == guideVectorDiff) || (NULL == guideVectorOrig) || + (NULL == hs->prevEnvelopeCompensation) || (NULL == hs->guideScfb)) { + goto bail; + } + + for (i = 0; i < MAX_NO_OF_ESTIMATES; i++) { + hs->guideVectors[i].guideVectorDiff = + guideVectorDiff + (i * MAX_FREQ_COEFFS); + hs->guideVectors[i].guideVectorOrig = + guideVectorOrig + (i * MAX_FREQ_COEFFS); + hs->detectionVectors[i] = detectionVectors + (i * MAX_FREQ_COEFFS); + hs->guideVectors[i].guideVectorDetected = + guideVectorDetected + (i * MAX_FREQ_COEFFS); + } + + return 0; + +bail: + hs->guideVectors[0].guideVectorDiff = guideVectorDiff; + hs->guideVectors[0].guideVectorOrig = guideVectorOrig; + hs->detectionVectors[0] = detectionVectors; + hs->guideVectors[0].guideVectorDetected = guideVectorDetected; + + FDKsbrEnc_DeleteSbrMissingHarmonicsDetector(hs); + return -1; +} + +/**************************************************************************/ +/*! + \brief Initialize an instance of the missing harmonics detector. + + + \return errorCode, noError if OK. + +*/ +/**************************************************************************/ +INT FDKsbrEnc_InitSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, INT sampleFreq, + INT frameSize, INT nSfb, INT qmfNoChannels, INT totNoEst, INT move, + INT noEstPerFrame, UINT sbrSyntaxFlags) { + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; + int i; + + FDK_ASSERT(totNoEst <= MAX_NO_OF_ESTIMATES); + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + switch (frameSize) { + case 1024: + case 512: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + hs->timeSlots = 16; + break; + case 960: + case 480: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + hs->timeSlots = 15; + break; + default: + return -1; + } + } else { + switch (frameSize) { + case 2048: + case 1024: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_2048; + hs->timeSlots = NUMBER_TIME_SLOTS_2048; + break; + case 1920: + case 960: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_1920; + hs->timeSlots = NUMBER_TIME_SLOTS_1920; + break; + default: + return -1; + } + } + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + hs->mhParams = ¶msAacLd; + } else + hs->mhParams = ¶msAac; + + hs->qmfNoChannels = qmfNoChannels; + hs->sampleFreq = sampleFreq; + hs->nSfb = nSfb; + + hs->totNoEst = totNoEst; + hs->move = move; + hs->noEstPerFrame = noEstPerFrame; + + for (i = 0; i < totNoEst; i++) { + FDKmemclear(hs->guideVectors[i].guideVectorDiff, + sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); + FDKmemclear(hs->guideVectors[i].guideVectorOrig, + sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); + FDKmemclear(hs->detectionVectors[i], sizeof(UCHAR) * MAX_FREQ_COEFFS); + FDKmemclear(hs->guideVectors[i].guideVectorDetected, + sizeof(UCHAR) * MAX_FREQ_COEFFS); + } + + // for(i=0; i<totNoEst/2; i++) { + for (i = 0; i < MAX_NO_OF_ESTIMATES / 2; i++) { + FDKmemclear(hs->tonalityDiff[i], sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); + FDKmemclear(hs->sfmOrig[i], sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); + FDKmemclear(hs->sfmSbr[i], sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); + } + + FDKmemclear(hs->prevEnvelopeCompensation, sizeof(UCHAR) * MAX_FREQ_COEFFS); + FDKmemclear(hs->guideScfb, sizeof(UCHAR) * MAX_FREQ_COEFFS); + + hs->previousTransientFlag = 0; + hs->previousTransientFrame = 0; + hs->previousTransientPos = 0; + + return (0); +} + +/**************************************************************************/ +/*! + \brief Deletes an instance of the missing harmonics detector. + + + \return none. + +*/ +/**************************************************************************/ +void FDKsbrEnc_DeleteSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet) { + if (hSbrMHDet) { + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; + + FreeRam_Sbr_detectionVectors(&hs->detectionVectors[0]); + FreeRam_Sbr_guideVectorDetected(&hs->guideVectors[0].guideVectorDetected); + FreeRam_Sbr_guideVectorDiff(&hs->guideVectors[0].guideVectorDiff); + FreeRam_Sbr_guideVectorOrig(&hs->guideVectors[0].guideVectorOrig); + FreeRam_Sbr_prevEnvelopeCompensation(&hs->prevEnvelopeCompensation); + FreeRam_Sbr_guideScfb(&hs->guideScfb); + } +} + +/**************************************************************************/ +/*! + \brief Resets an instance of the missing harmonics detector. + + + \return error code, noError if OK. + +*/ +/**************************************************************************/ +INT FDKsbrEnc_ResetSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMissingHarmonicsDetector, + INT nSfb) { + int i; + FIXP_DBL tempGuide[MAX_FREQ_COEFFS]; + UCHAR tempGuideInt[MAX_FREQ_COEFFS]; + INT nSfbPrev; + + nSfbPrev = hSbrMissingHarmonicsDetector->nSfb; + hSbrMissingHarmonicsDetector->nSfb = nSfb; + + FDKmemcpy(tempGuideInt, hSbrMissingHarmonicsDetector->guideScfb, + nSfbPrev * sizeof(UCHAR)); + + if (nSfb > nSfbPrev) { + for (i = 0; i < (nSfb - nSfbPrev); i++) { + hSbrMissingHarmonicsDetector->guideScfb[i] = 0; + } + + for (i = 0; i < nSfbPrev; i++) { + hSbrMissingHarmonicsDetector->guideScfb[i + (nSfb - nSfbPrev)] = + tempGuideInt[i]; + } + } else { + for (i = 0; i < nSfb; i++) { + hSbrMissingHarmonicsDetector->guideScfb[i] = + tempGuideInt[i + (nSfbPrev - nSfb)]; + } + } + + FDKmemcpy(tempGuide, + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff, + nSfbPrev * sizeof(FIXP_DBL)); + + if (nSfb > nSfbPrev) { + for (i = 0; i < (nSfb - nSfbPrev); i++) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] = + FL2FXCONST_DBL(0.0f); + } + + for (i = 0; i < nSfbPrev; i++) { + hSbrMissingHarmonicsDetector->guideVectors[0] + .guideVectorDiff[i + (nSfb - nSfbPrev)] = tempGuide[i]; + } + } else { + for (i = 0; i < nSfb; i++) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] = + tempGuide[i + (nSfbPrev - nSfb)]; + } + } + + FDKmemcpy(tempGuide, + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig, + nSfbPrev * sizeof(FIXP_DBL)); + + if (nSfb > nSfbPrev) { + for (i = 0; i < (nSfb - nSfbPrev); i++) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] = + FL2FXCONST_DBL(0.0f); + } + + for (i = 0; i < nSfbPrev; i++) { + hSbrMissingHarmonicsDetector->guideVectors[0] + .guideVectorOrig[i + (nSfb - nSfbPrev)] = tempGuide[i]; + } + } else { + for (i = 0; i < nSfb; i++) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] = + tempGuide[i + (nSfbPrev - nSfb)]; + } + } + + FDKmemcpy(tempGuideInt, + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected, + nSfbPrev * sizeof(UCHAR)); + + if (nSfb > nSfbPrev) { + for (i = 0; i < (nSfb - nSfbPrev); i++) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] = 0; + } + + for (i = 0; i < nSfbPrev; i++) { + hSbrMissingHarmonicsDetector->guideVectors[0] + .guideVectorDetected[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; + } + } else { + for (i = 0; i < nSfb; i++) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] = + tempGuideInt[i + (nSfbPrev - nSfb)]; + } + } + + FDKmemcpy(tempGuideInt, + hSbrMissingHarmonicsDetector->prevEnvelopeCompensation, + nSfbPrev * sizeof(UCHAR)); + + if (nSfb > nSfbPrev) { + for (i = 0; i < (nSfb - nSfbPrev); i++) { + hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] = 0; + } + + for (i = 0; i < nSfbPrev; i++) { + hSbrMissingHarmonicsDetector + ->prevEnvelopeCompensation[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; + } + } else { + for (i = 0; i < nSfb; i++) { + hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] = + tempGuideInt[i + (nSfbPrev - nSfb)]; + } + } + + return 0; +} diff --git a/fdk-aac/libSBRenc/src/mh_det.h b/fdk-aac/libSBRenc/src/mh_det.h new file mode 100644 index 0000000..89d81b5 --- /dev/null +++ b/fdk-aac/libSBRenc/src/mh_det.h @@ -0,0 +1,204 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief missing harmonics detection header file $Revision: 92790 $ +*/ + +#ifndef MH_DET_H +#define MH_DET_H + +#include "sbr_encoder.h" +#include "fram_gen.h" + +typedef struct { + FIXP_DBL thresHoldDiff; /*!< threshold for tonality difference */ + FIXP_DBL thresHoldDiffGuide; /*!< threshold for tonality difference for the + guide */ + FIXP_DBL thresHoldTone; /*!< threshold for tonality for a sine */ + FIXP_DBL invThresHoldTone; + FIXP_DBL thresHoldToneGuide; /*!< threshold for tonality for a sine for the + guide */ + FIXP_DBL sfmThresSbr; /*!< tonality flatness measure threshold for the SBR + signal.*/ + FIXP_DBL sfmThresOrig; /*!< tonality flatness measure threshold for the + original signal.*/ + FIXP_DBL decayGuideOrig; /*!< decay value of the tonality value of the guide + for the tone. */ + FIXP_DBL decayGuideDiff; /*!< decay value of the tonality value of the guide + for the tonality difference. */ + FIXP_DBL derivThresMaxLD64; /*!< threshold for detecting LP character in a + signal. */ + FIXP_DBL derivThresBelowLD64; /*!< threshold for detecting LP character in a + signal. */ + FIXP_DBL derivThresAboveLD64; /*!< threshold for detecting LP character in a + signal. */ +} THRES_HOLDS; + +typedef struct { + INT deltaTime; /*!< maximum allowed transient distance (from frame border in + number of qmf subband sample) for a frame to be considered a + transient frame.*/ + THRES_HOLDS thresHolds; /*!< the thresholds used for detection. */ + INT maxComp; /*!< maximum alllowed compensation factor for the envelope data. + */ +} DETECTOR_PARAMETERS_MH; + +typedef struct { + FIXP_DBL *guideVectorDiff; + FIXP_DBL *guideVectorOrig; + UCHAR *guideVectorDetected; +} GUIDE_VECTORS; + +typedef struct { + INT qmfNoChannels; + INT nSfb; + INT sampleFreq; + INT previousTransientFlag; + INT previousTransientFrame; + INT previousTransientPos; + + INT noVecPerFrame; + INT transientPosOffset; + + INT move; + INT totNoEst; + INT noEstPerFrame; + INT timeSlots; + + UCHAR *guideScfb; + UCHAR *prevEnvelopeCompensation; + UCHAR *detectionVectors[MAX_NO_OF_ESTIMATES]; + FIXP_DBL tonalityDiff[MAX_NO_OF_ESTIMATES / 2][MAX_FREQ_COEFFS]; + FIXP_DBL sfmOrig[MAX_NO_OF_ESTIMATES / 2][MAX_FREQ_COEFFS]; + FIXP_DBL sfmSbr[MAX_NO_OF_ESTIMATES / 2][MAX_FREQ_COEFFS]; + const DETECTOR_PARAMETERS_MH *mhParams; + GUIDE_VECTORS guideVectors[MAX_NO_OF_ESTIMATES]; +} SBR_MISSING_HARMONICS_DETECTOR; + +typedef SBR_MISSING_HARMONICS_DETECTOR *HANDLE_SBR_MISSING_HARMONICS_DETECTOR; + +void FDKsbrEnc_SbrMissingHarmonicsDetectorQmf( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector, + FIXP_DBL **pQuotaBuffer, INT **pSignBuffer, SCHAR *indexVector, + const SBR_FRAME_INFO *pFrameInfo, const UCHAR *pTranInfo, + INT *pAddHarmonicsFlag, UCHAR *pAddHarmonicsScaleFactorBands, + const UCHAR *freqBandTable, INT nSfb, UCHAR *envelopeCompensation, + FIXP_DBL *pNrgVector); + +INT FDKsbrEnc_CreateSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, INT chan); + +INT FDKsbrEnc_InitSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector, + INT sampleFreq, INT frameSize, INT nSfb, INT qmfNoChannels, INT totNoEst, + INT move, INT noEstPerFrame, UINT sbrSyntaxFlags); + +void FDKsbrEnc_DeleteSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector); + +INT FDKsbrEnc_ResetSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMissingHarmonicsDetector, + INT nSfb); + +#endif diff --git a/fdk-aac/libSBRenc/src/nf_est.cpp b/fdk-aac/libSBRenc/src/nf_est.cpp new file mode 100644 index 0000000..290ec35 --- /dev/null +++ b/fdk-aac/libSBRenc/src/nf_est.cpp @@ -0,0 +1,612 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "nf_est.h" + +#include "sbr_misc.h" + +#include "genericStds.h" + +/* smoothFilter[4] = {0.05857864376269f, 0.2f, 0.34142135623731f, 0.4f}; */ +static const FIXP_DBL smoothFilter[4] = {0x077f813d, 0x19999995, 0x2bb3b1f5, + 0x33333335}; + +/* static const INT smoothFilterLength = 4; */ + +static const FIXP_DBL QuantOffset = (INT)0xfc000000; /* ld64(0.25) */ + +#ifndef min +#define min(a, b) (a < b ? a : b) +#endif + +#ifndef max +#define max(a, b) (a > b ? a : b) +#endif + +#define NOISE_FLOOR_OFFSET_SCALING (4) + +/**************************************************************************/ +/*! + \brief The function applies smoothing to the noise levels. + + + + \return none + +*/ +/**************************************************************************/ +static void smoothingOfNoiseLevels( + FIXP_DBL *NoiseLevels, /*!< pointer to noise-floor levels.*/ + INT nEnvelopes, /*!< Number of noise floor envelopes.*/ + INT noNoiseBands, /*!< Number of noise bands for every noise floor envelope. + */ + FIXP_DBL prevNoiseLevels[NF_SMOOTHING_LENGTH] + [MAX_NUM_NOISE_VALUES], /*!< Previous noise floor + envelopes. */ + const FIXP_DBL * + pSmoothFilter, /*!< filter used for smoothing the noise floor levels. */ + INT transientFlag) /*!< flag indicating if a transient is present*/ + +{ + INT i, band, env; + FIXP_DBL accu; + + for (env = 0; env < nEnvelopes; env++) { + if (transientFlag) { + for (i = 0; i < NF_SMOOTHING_LENGTH; i++) { + FDKmemcpy(prevNoiseLevels[i], NoiseLevels + env * noNoiseBands, + noNoiseBands * sizeof(FIXP_DBL)); + } + } else { + for (i = 1; i < NF_SMOOTHING_LENGTH; i++) { + FDKmemcpy(prevNoiseLevels[i - 1], prevNoiseLevels[i], + noNoiseBands * sizeof(FIXP_DBL)); + } + FDKmemcpy(prevNoiseLevels[NF_SMOOTHING_LENGTH - 1], + NoiseLevels + env * noNoiseBands, + noNoiseBands * sizeof(FIXP_DBL)); + } + + for (band = 0; band < noNoiseBands; band++) { + accu = FL2FXCONST_DBL(0.0f); + for (i = 0; i < NF_SMOOTHING_LENGTH; i++) { + accu += fMultDiv2(pSmoothFilter[i], prevNoiseLevels[i][band]); + } + FDK_ASSERT((band + env * noNoiseBands) < MAX_NUM_NOISE_VALUES); + NoiseLevels[band + env * noNoiseBands] = accu << 1; + } + } +} + +/**************************************************************************/ +/*! + \brief Does the noise floor level estiamtion. + + The noiseLevel samples are scaled by the factor 0.25 + + \return none + +*/ +/**************************************************************************/ +static void qmfBasedNoiseFloorDetection( + FIXP_DBL *noiseLevel, /*!< Pointer to vector to + store the noise levels + in.*/ + FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the quota + values of the original. */ + SCHAR *indexVector, /*!< Index vector to obtain the + patched data. */ + INT startIndex, /*!< Start index. */ + INT stopIndex, /*!< Stop index. */ + INT startChannel, /*!< Start channel of the current + noise floor band.*/ + INT stopChannel, /*!< Stop channel of the current + noise floor band. */ + FIXP_DBL ana_max_level, /*!< Maximum level of the + adaptive noise.*/ + FIXP_DBL noiseFloorOffset, /*!< Noise floor offset. */ + INT missingHarmonicFlag, /*!< Flag indicating if a + strong tonal component + is missing.*/ + FIXP_DBL weightFac, /*!< Weightening factor for the + difference between orig and sbr. + */ + INVF_MODE diffThres, /*!< Threshold value to control the + inverse filtering decision.*/ + INVF_MODE inverseFilteringLevel) /*!< Inverse filtering + level of the current + band.*/ +{ + INT scale, l, k; + FIXP_DBL meanOrig = FL2FXCONST_DBL(0.0f), meanSbr = FL2FXCONST_DBL(0.0f), + diff; + FIXP_DBL invIndex = GetInvInt(stopIndex - startIndex); + FIXP_DBL invChannel = GetInvInt(stopChannel - startChannel); + FIXP_DBL accu; + + /* + Calculate the mean value, over the current time segment, for the original, the + HFR and the difference, over all channels in the current frequency range. + */ + + if (missingHarmonicFlag == 1) { + for (l = startChannel; l < stopChannel; l++) { + /* tonalityOrig */ + accu = FL2FXCONST_DBL(0.0f); + for (k = startIndex; k < stopIndex; k++) { + accu += fMultDiv2(quotaMatrixOrig[k][l], invIndex); + } + meanOrig = fixMax(meanOrig, (accu << 1)); + + /* tonalitySbr */ + accu = FL2FXCONST_DBL(0.0f); + for (k = startIndex; k < stopIndex; k++) { + accu += fMultDiv2(quotaMatrixOrig[k][indexVector[l]], invIndex); + } + meanSbr = fixMax(meanSbr, (accu << 1)); + } + } else { + for (l = startChannel; l < stopChannel; l++) { + /* tonalityOrig */ + accu = FL2FXCONST_DBL(0.0f); + for (k = startIndex; k < stopIndex; k++) { + accu += fMultDiv2(quotaMatrixOrig[k][l], invIndex); + } + meanOrig += fMult((accu << 1), invChannel); + + /* tonalitySbr */ + accu = FL2FXCONST_DBL(0.0f); + for (k = startIndex; k < stopIndex; k++) { + accu += fMultDiv2(quotaMatrixOrig[k][indexVector[l]], invIndex); + } + meanSbr += fMult((accu << 1), invChannel); + } + } + + /* Small fix to avoid noise during silent passages.*/ + if (meanOrig <= FL2FXCONST_DBL(0.000976562f * RELAXATION_FLOAT) && + meanSbr <= FL2FXCONST_DBL(0.000976562f * RELAXATION_FLOAT)) { + meanOrig = FL2FXCONST_DBL(101.5936673f * RELAXATION_FLOAT); + meanSbr = FL2FXCONST_DBL(101.5936673f * RELAXATION_FLOAT); + } + + meanOrig = fixMax(meanOrig, RELAXATION); + meanSbr = fixMax(meanSbr, RELAXATION); + + if (missingHarmonicFlag == 1 || inverseFilteringLevel == INVF_MID_LEVEL || + inverseFilteringLevel == INVF_LOW_LEVEL || + inverseFilteringLevel == INVF_OFF || inverseFilteringLevel <= diffThres) { + diff = RELAXATION; + } else { + accu = fDivNorm(meanSbr, meanOrig, &scale); + + diff = fixMax(RELAXATION, fMult(RELAXATION_FRACT, fMult(weightFac, accu)) >> + (RELAXATION_SHIFT - scale)); + } + + /* + * noise Level is now a positive value, i.e. + * the more harmonic the signal is the higher noise level, + * this makes no sense so we change the sign. + *********************************************************/ + accu = fDivNorm(diff, meanOrig, &scale); + scale -= 2; + + if ((scale > 0) && (accu > ((FIXP_DBL)MAXVAL_DBL) >> scale)) { + *noiseLevel = (FIXP_DBL)MAXVAL_DBL; + } else { + *noiseLevel = scaleValue(accu, scale); + } + + /* + * Add a noise floor offset to compensate for bias in the detector + *****************************************************************/ + if (!missingHarmonicFlag) { + *noiseLevel = fixMin(fMult(*noiseLevel, noiseFloorOffset), + (FIXP_DBL)MAXVAL_DBL >> NOISE_FLOOR_OFFSET_SCALING) + << NOISE_FLOOR_OFFSET_SCALING; + } + + /* + * check to see that we don't exceed the maximum allowed level + **************************************************************/ + *noiseLevel = + fixMin(*noiseLevel, + ana_max_level); /* ana_max_level is scaled with factor 0.25 */ +} + +/**************************************************************************/ +/*! + \brief Does the noise floor level estiamtion. + The function calls the Noisefloor estimation function + for the time segments decided based upon the transient + information. The block is always divided into one or two segments. + + + \return none + +*/ +/**************************************************************************/ +void FDKsbrEnc_sbrNoiseFloorEstimateQmf( + HANDLE_SBR_NOISE_FLOOR_ESTIMATE + h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct + */ + const SBR_FRAME_INFO + *frame_info, /*!< Time frequency grid of the current frame. */ + FIXP_DBL + *noiseLevels, /*!< Pointer to vector to store the noise levels in.*/ + FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the quota values of the + original. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + INT missingHarmonicsFlag, /*!< Flag indicating if a strong tonal component + will be missing. */ + INT startIndex, /*!< Start index. */ + UINT numberOfEstimatesPerFrame, /*!< The number of tonality estimates per + frame. */ + int transientFrame, /*!< A flag indicating if a transient is present. */ + INVF_MODE *pInvFiltLevels, /*!< Pointer to the vector holding the inverse + filtering levels. */ + UINT sbrSyntaxFlags) + +{ + INT nNoiseEnvelopes, startPos[2], stopPos[2], env, band; + + INT noNoiseBands = h_sbrNoiseFloorEstimate->noNoiseBands; + INT *freqBandTable = h_sbrNoiseFloorEstimate->freqBandTableQmf; + + nNoiseEnvelopes = frame_info->nNoiseEnvelopes; + + startPos[0] = startIndex; + + if (nNoiseEnvelopes == 1) { + stopPos[0] = startIndex + min(numberOfEstimatesPerFrame, 2); + } else { + stopPos[0] = startIndex + 1; + startPos[1] = startIndex + 1; + stopPos[1] = startIndex + min(numberOfEstimatesPerFrame, 2); + } + + /* + * Estimate the noise floor. + **************************************/ + for (env = 0; env < nNoiseEnvelopes; env++) { + for (band = 0; band < noNoiseBands; band++) { + FDK_ASSERT((band + env * noNoiseBands) < MAX_NUM_NOISE_VALUES); + qmfBasedNoiseFloorDetection( + &noiseLevels[band + env * noNoiseBands], quotaMatrixOrig, indexVector, + startPos[env], stopPos[env], freqBandTable[band], + freqBandTable[band + 1], h_sbrNoiseFloorEstimate->ana_max_level, + h_sbrNoiseFloorEstimate->noiseFloorOffset[band], missingHarmonicsFlag, + h_sbrNoiseFloorEstimate->weightFac, + h_sbrNoiseFloorEstimate->diffThres, pInvFiltLevels[band]); + } + } + + /* + * Smoothing of the values. + **************************/ + smoothingOfNoiseLevels(noiseLevels, nNoiseEnvelopes, + h_sbrNoiseFloorEstimate->noNoiseBands, + h_sbrNoiseFloorEstimate->prevNoiseLevels, + h_sbrNoiseFloorEstimate->smoothFilter, transientFrame); + + /* quantisation*/ + for (env = 0; env < nNoiseEnvelopes; env++) { + for (band = 0; band < noNoiseBands; band++) { + FDK_ASSERT((band + env * noNoiseBands) < MAX_NUM_NOISE_VALUES); + noiseLevels[band + env * noNoiseBands] = + (FIXP_DBL)NOISE_FLOOR_OFFSET_64 - + (FIXP_DBL)CalcLdData(noiseLevels[band + env * noNoiseBands] + + (FIXP_DBL)1) + + QuantOffset; + } + } +} + +/**************************************************************************/ +/*! + \brief + + + \return errorCode, noError if successful + +*/ +/**************************************************************************/ +static INT downSampleLoRes(INT *v_result, /*!< */ + INT num_result, /*!< */ + const UCHAR *freqBandTableRef, /*!< */ + INT num_Ref) /*!< */ +{ + INT step; + INT i, j; + INT org_length, result_length; + INT v_index[MAX_FREQ_COEFFS / 2]; + + /* init */ + org_length = num_Ref; + result_length = num_result; + + v_index[0] = 0; /* Always use left border */ + i = 0; + while (org_length > 0) /* Create downsample vector */ + { + i++; + step = org_length / result_length; /* floor; */ + org_length = org_length - step; + result_length--; + v_index[i] = v_index[i - 1] + step; + } + + if (i != num_result) /* Should never happen */ + return (1); /* error downsampling */ + + for (j = 0; j <= i; + j++) /* Use downsample vector to index LoResolution vector. */ + { + v_result[j] = freqBandTableRef[v_index[j]]; + } + + return (0); +} + +/**************************************************************************/ +/*! + \brief Initialize an instance of the noise floor level estimation module. + + + \return errorCode, noError if successful + +*/ +/**************************************************************************/ +INT FDKsbrEnc_InitSbrNoiseFloorEstimate( + HANDLE_SBR_NOISE_FLOOR_ESTIMATE + h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct + */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + const UCHAR *freqBandTable, /*!< Frequency band table. */ + INT nSfb, /*!< Number of frequency bands. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + INT timeSlots, /*!< Number of time slots in a frame. */ + UINT useSpeechConfig /*!< Flag: adapt tuning parameters according to speech + */ +) { + INT i, qexp, qtmp; + FIXP_DBL tmp, exp; + + FDKmemclear(h_sbrNoiseFloorEstimate, sizeof(SBR_NOISE_FLOOR_ESTIMATE)); + + h_sbrNoiseFloorEstimate->smoothFilter = smoothFilter; + if (useSpeechConfig) { + h_sbrNoiseFloorEstimate->weightFac = (FIXP_DBL)MAXVAL_DBL; + h_sbrNoiseFloorEstimate->diffThres = INVF_LOW_LEVEL; + } else { + h_sbrNoiseFloorEstimate->weightFac = FL2FXCONST_DBL(0.25f); + h_sbrNoiseFloorEstimate->diffThres = INVF_MID_LEVEL; + } + + h_sbrNoiseFloorEstimate->timeSlots = timeSlots; + h_sbrNoiseFloorEstimate->noiseBands = noiseBands; + + /* h_sbrNoiseFloorEstimate->ana_max_level is scaled by 0.25 */ + switch (ana_max_level) { + case 6: + h_sbrNoiseFloorEstimate->ana_max_level = (FIXP_DBL)MAXVAL_DBL; + break; + case 3: + h_sbrNoiseFloorEstimate->ana_max_level = FL2FXCONST_DBL(0.5); + break; + case -3: + h_sbrNoiseFloorEstimate->ana_max_level = FL2FXCONST_DBL(0.125); + break; + default: + /* Should not enter here */ + h_sbrNoiseFloorEstimate->ana_max_level = (FIXP_DBL)MAXVAL_DBL; + break; + } + + /* + calculate number of noise bands and allocate + */ + if (FDKsbrEnc_resetSbrNoiseFloorEstimate(h_sbrNoiseFloorEstimate, + freqBandTable, nSfb)) + return (1); + + if (noiseFloorOffset == 0) { + tmp = ((FIXP_DBL)MAXVAL_DBL) >> NOISE_FLOOR_OFFSET_SCALING; + } else { + /* noiseFloorOffset has to be smaller than 12, because + the result of the calculation below must be smaller than 1: + (2^(noiseFloorOffset/3))*2^4<1 */ + FDK_ASSERT(noiseFloorOffset < 12); + + /* Assumes the noise floor offset in tuning table are in q31 */ + /* Change the qformat here when non-zero values would be filled */ + exp = fDivNorm((FIXP_DBL)noiseFloorOffset, 3, &qexp); + tmp = fPow(2, DFRACT_BITS - 1, exp, qexp, &qtmp); + tmp = scaleValue(tmp, qtmp - NOISE_FLOOR_OFFSET_SCALING); + } + + for (i = 0; i < h_sbrNoiseFloorEstimate->noNoiseBands; i++) { + h_sbrNoiseFloorEstimate->noiseFloorOffset[i] = tmp; + } + + return (0); +} + +/**************************************************************************/ +/*! + \brief Resets the current instance of the noise floor estiamtion + module. + + + \return errorCode, noError if successful + +*/ +/**************************************************************************/ +INT FDKsbrEnc_resetSbrNoiseFloorEstimate( + HANDLE_SBR_NOISE_FLOOR_ESTIMATE + h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct + */ + const UCHAR *freqBandTable, /*!< Frequency band table. */ + INT nSfb /*!< Number of bands in the frequency band table. */ +) { + INT k2, kx; + + /* + * Calculate number of noise bands + ***********************************/ + k2 = freqBandTable[nSfb]; + kx = freqBandTable[0]; + if (h_sbrNoiseFloorEstimate->noiseBands == 0) { + h_sbrNoiseFloorEstimate->noNoiseBands = 1; + } else { + /* + * Calculate number of noise bands 1,2 or 3 bands/octave + ********************************************************/ + FIXP_DBL tmp, ratio, lg2; + INT ratio_e, qlg2, nNoiseBands; + + ratio = fDivNorm(k2, kx, &ratio_e); + lg2 = fLog2(ratio, ratio_e, &qlg2); + tmp = fMult((FIXP_DBL)(h_sbrNoiseFloorEstimate->noiseBands << 24), lg2); + tmp = scaleValue(tmp, qlg2 - 23); + + nNoiseBands = (INT)((tmp + (FIXP_DBL)1) >> 1); + + if (nNoiseBands > MAX_NUM_NOISE_COEFFS) { + nNoiseBands = MAX_NUM_NOISE_COEFFS; + } + + if (nNoiseBands == 0) { + nNoiseBands = 1; + } + + h_sbrNoiseFloorEstimate->noNoiseBands = nNoiseBands; + } + + return (downSampleLoRes(h_sbrNoiseFloorEstimate->freqBandTableQmf, + h_sbrNoiseFloorEstimate->noNoiseBands, freqBandTable, + nSfb)); +} + +/**************************************************************************/ +/*! + \brief Deletes the current instancce of the noise floor level + estimation module. + + + \return none + +*/ +/**************************************************************************/ +void FDKsbrEnc_deleteSbrNoiseFloorEstimate( + HANDLE_SBR_NOISE_FLOOR_ESTIMATE + h_sbrNoiseFloorEstimate) /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct + */ +{ + if (h_sbrNoiseFloorEstimate) { + /* + nothing to do + */ + } +} diff --git a/fdk-aac/libSBRenc/src/nf_est.h b/fdk-aac/libSBRenc/src/nf_est.h new file mode 100644 index 0000000..c2f16e9 --- /dev/null +++ b/fdk-aac/libSBRenc/src/nf_est.h @@ -0,0 +1,185 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Noise floor estimation structs and prototypes $Revision: 92790 $ +*/ + +#ifndef NF_EST_H +#define NF_EST_H + +#include "sbr_encoder.h" +#include "fram_gen.h" + +#define NF_SMOOTHING_LENGTH 4 /*!< Smoothing length of the noise floors. */ + +typedef struct { + FIXP_DBL + prevNoiseLevels[NF_SMOOTHING_LENGTH] + [MAX_NUM_NOISE_VALUES]; /*!< The previous noise levels. */ + FIXP_DBL noiseFloorOffset + [MAX_NUM_NOISE_VALUES]; /*!< Noise floor offset, scaled with + NOISE_FLOOR_OFFSET_SCALING */ + const FIXP_DBL *smoothFilter; /*!< Smoothing filter to use. */ + FIXP_DBL ana_max_level; /*!< Max level allowed. */ + FIXP_DBL weightFac; /*!< Weightening factor for the difference between orig + and sbr. */ + INT freqBandTableQmf[MAX_NUM_NOISE_VALUES + + 1]; /*!< Frequncy band table for the noise floor bands.*/ + INT noNoiseBands; /*!< Number of noisebands. */ + INT noiseBands; /*!< NoiseBands switch 4 bit.*/ + INT timeSlots; /*!< Number of timeslots in a frame. */ + INVF_MODE diffThres; /*!< Threshold value to control the inverse filtering + decision */ +} SBR_NOISE_FLOOR_ESTIMATE; + +typedef SBR_NOISE_FLOOR_ESTIMATE *HANDLE_SBR_NOISE_FLOOR_ESTIMATE; + +void FDKsbrEnc_sbrNoiseFloorEstimateQmf( + HANDLE_SBR_NOISE_FLOOR_ESTIMATE + h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct + */ + const SBR_FRAME_INFO + *frame_info, /*!< Time frequency grid of the current frame. */ + FIXP_DBL + *noiseLevels, /*!< Pointer to vector to store the noise levels in.*/ + FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the quota values of the + original. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + INT missingHarmonicsFlag, /*!< Flag indicating if a strong tonal component + will be missing. */ + INT startIndex, /*!< Start index. */ + UINT numberOfEstimatesPerFrame, /*!< The number of tonality estimates per + frame. */ + INT transientFrame, /*!< A flag indicating if a transient is present. */ + INVF_MODE *pInvFiltLevels, /*!< Pointer to the vector holding the inverse + filtering levels. */ + UINT sbrSyntaxFlags); + +INT FDKsbrEnc_InitSbrNoiseFloorEstimate( + HANDLE_SBR_NOISE_FLOOR_ESTIMATE + h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct + */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb, /*!< Number of frequency bands. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + INT timeSlots, /*!< Number of time slots in a frame. */ + UINT useSpeechConfig /*!< Flag: adapt tuning parameters according to speech + */ +); + +INT FDKsbrEnc_resetSbrNoiseFloorEstimate( + HANDLE_SBR_NOISE_FLOOR_ESTIMATE + h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct + */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb); /*!< Number of bands in the frequency band table. */ + +void FDKsbrEnc_deleteSbrNoiseFloorEstimate( + HANDLE_SBR_NOISE_FLOOR_ESTIMATE + h_sbrNoiseFloorEstimate); /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct + */ + +#endif diff --git a/fdk-aac/libSBRenc/src/ps_bitenc.cpp b/fdk-aac/libSBRenc/src/ps_bitenc.cpp new file mode 100644 index 0000000..e30af2a --- /dev/null +++ b/fdk-aac/libSBRenc/src/ps_bitenc.cpp @@ -0,0 +1,624 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): N. Rettelbach + + Description: Parametric Stereo bitstream encoder + +*******************************************************************************/ + +#include "ps_bitenc.h" + +#include "ps_main.h" + +static inline UCHAR FDKsbrEnc_WriteBits_ps(HANDLE_FDK_BITSTREAM hBitStream, + UINT value, + const UINT numberOfBits) { + /* hBitStream == NULL happens here intentionally */ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, value, numberOfBits); + } + return numberOfBits; +} + +#define SI_SBR_EXTENSION_SIZE_BITS 4 +#define SI_SBR_EXTENSION_ESC_COUNT_BITS 8 +#define SI_SBR_EXTENSION_ID_BITS 2 +#define EXTENSION_ID_PS_CODING 2 +#define PS_EXT_ID_V0 0 + +static const INT iidDeltaCoarse_Offset = 14; +static const INT iidDeltaCoarse_MaxVal = 28; +static const INT iidDeltaFine_Offset = 30; +static const INT iidDeltaFine_MaxVal = 60; + +/* PS Stereo Huffmantable: iidDeltaFreqCoarse */ +static const UINT iidDeltaFreqCoarse_Length[] = { + 17, 17, 17, 17, 16, 15, 13, 10, 9, 7, 6, 5, 4, 3, 1, + 3, 4, 5, 6, 6, 8, 11, 13, 14, 14, 15, 17, 18, 18}; +static const UINT iidDeltaFreqCoarse_Code[] = { + 0x0001fffb, 0x0001fffc, 0x0001fffd, 0x0001fffa, 0x0000fffc, 0x00007ffc, + 0x00001ffd, 0x000003fe, 0x000001fe, 0x0000007e, 0x0000003c, 0x0000001d, + 0x0000000d, 0x00000005, 0000000000, 0x00000004, 0x0000000c, 0x0000001c, + 0x0000003d, 0x0000003e, 0x000000fe, 0x000007fe, 0x00001ffc, 0x00003ffc, + 0x00003ffd, 0x00007ffd, 0x0001fffe, 0x0003fffe, 0x0003ffff}; + +/* PS Stereo Huffmantable: iidDeltaFreqFine */ +static const UINT iidDeltaFreqFine_Length[] = { + 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 18, 17, 17, 16, 16, 15, + 14, 14, 13, 12, 12, 11, 10, 10, 8, 7, 6, 5, 4, 3, 1, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 16, 16, + 17, 17, 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18}; +static const UINT iidDeltaFreqFine_Code[] = { + 0x0001feb4, 0x0001feb5, 0x0001fd76, 0x0001fd77, 0x0001fd74, 0x0001fd75, + 0x0001fe8a, 0x0001fe8b, 0x0001fe88, 0x0000fe80, 0x0001feb6, 0x0000fe82, + 0x0000feb8, 0x00007f42, 0x00007fae, 0x00003faf, 0x00001fd1, 0x00001fe9, + 0x00000fe9, 0x000007ea, 0x000007fb, 0x000003fb, 0x000001fb, 0x000001ff, + 0x0000007c, 0x0000003c, 0x0000001c, 0x0000000c, 0000000000, 0x00000001, + 0x00000001, 0x00000002, 0x00000001, 0x0000000d, 0x0000001d, 0x0000003d, + 0x0000007d, 0x000000fc, 0x000001fc, 0x000003fc, 0x000003f4, 0x000007eb, + 0x00000fea, 0x00001fea, 0x00001fd6, 0x00003fd0, 0x00007faf, 0x00007f43, + 0x0000feb9, 0x0000fe83, 0x0001feb7, 0x0000fe81, 0x0001fe89, 0x0001fe8e, + 0x0001fe8f, 0x0001fe8c, 0x0001fe8d, 0x0001feb2, 0x0001feb3, 0x0001feb0, + 0x0001feb1}; + +/* PS Stereo Huffmantable: iidDeltaTimeCoarse */ +static const UINT iidDeltaTimeCoarse_Length[] = { + 19, 19, 19, 20, 20, 20, 17, 15, 12, 10, 8, 6, 4, 2, 1, + 3, 5, 7, 9, 11, 13, 14, 17, 19, 20, 20, 20, 20, 20}; +static const UINT iidDeltaTimeCoarse_Code[] = { + 0x0007fff9, 0x0007fffa, 0x0007fffb, 0x000ffff8, 0x000ffff9, 0x000ffffa, + 0x0001fffd, 0x00007ffe, 0x00000ffe, 0x000003fe, 0x000000fe, 0x0000003e, + 0x0000000e, 0x00000002, 0000000000, 0x00000006, 0x0000001e, 0x0000007e, + 0x000001fe, 0x000007fe, 0x00001ffe, 0x00003ffe, 0x0001fffc, 0x0007fff8, + 0x000ffffb, 0x000ffffc, 0x000ffffd, 0x000ffffe, 0x000fffff}; + +/* PS Stereo Huffmantable: iidDeltaTimeFine */ +static const UINT iidDeltaTimeFine_Length[] = { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, + 14, 13, 13, 13, 12, 12, 11, 10, 9, 9, 7, 6, 5, 3, 1, 2, + 5, 6, 7, 8, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, + 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; +static const UINT iidDeltaTimeFine_Code[] = { + 0x00004ed4, 0x00004ed5, 0x00004ece, 0x00004ecf, 0x00004ecc, 0x00004ed6, + 0x00004ed8, 0x00004f46, 0x00004f60, 0x00002718, 0x00002719, 0x00002764, + 0x00002765, 0x0000276d, 0x000027b1, 0x000013b7, 0x000013d6, 0x000009c7, + 0x000009e9, 0x000009ed, 0x000004ee, 0x000004f7, 0x00000278, 0x00000139, + 0x0000009a, 0x0000009f, 0x00000020, 0x00000011, 0x0000000a, 0x00000003, + 0x00000001, 0000000000, 0x0000000b, 0x00000012, 0x00000021, 0x0000004c, + 0x0000009b, 0x0000013a, 0x00000279, 0x00000270, 0x000004ef, 0x000004e2, + 0x000009ea, 0x000009d8, 0x000013d7, 0x000013d0, 0x000027b2, 0x000027a2, + 0x0000271a, 0x0000271b, 0x00004f66, 0x00004f67, 0x00004f61, 0x00004f47, + 0x00004ed9, 0x00004ed7, 0x00004ecd, 0x00004ed2, 0x00004ed3, 0x00004ed0, + 0x00004ed1}; + +static const INT iccDelta_Offset = 7; +static const INT iccDelta_MaxVal = 14; +/* PS Stereo Huffmantable: iccDeltaFreq */ +static const UINT iccDeltaFreq_Length[] = {14, 14, 12, 10, 7, 5, 3, 1, + 2, 4, 6, 8, 9, 11, 13}; +static const UINT iccDeltaFreq_Code[] = { + 0x00003fff, 0x00003ffe, 0x00000ffe, 0x000003fe, 0x0000007e, + 0x0000001e, 0x00000006, 0000000000, 0x00000002, 0x0000000e, + 0x0000003e, 0x000000fe, 0x000001fe, 0x000007fe, 0x00001ffe}; + +/* PS Stereo Huffmantable: iccDeltaTime */ +static const UINT iccDeltaTime_Length[] = {14, 13, 11, 9, 7, 5, 3, 1, + 2, 4, 6, 8, 10, 12, 14}; +static const UINT iccDeltaTime_Code[] = { + 0x00003ffe, 0x00001ffe, 0x000007fe, 0x000001fe, 0x0000007e, + 0x0000001e, 0x00000006, 0000000000, 0x00000002, 0x0000000e, + 0x0000003e, 0x000000fe, 0x000003fe, 0x00000ffe, 0x00003fff}; + +static const INT ipdDelta_Offset = 0; +static const INT ipdDelta_MaxVal = 7; +/* PS Stereo Huffmantable: ipdDeltaFreq */ +static const UINT ipdDeltaFreq_Length[] = {1, 3, 4, 4, 4, 4, 4, 4}; +static const UINT ipdDeltaFreq_Code[] = {0x00000001, 0000000000, 0x00000006, + 0x00000004, 0x00000002, 0x00000003, + 0x00000005, 0x00000007}; + +/* PS Stereo Huffmantable: ipdDeltaTime */ +static const UINT ipdDeltaTime_Length[] = {1, 3, 4, 5, 5, 4, 4, 3}; +static const UINT ipdDeltaTime_Code[] = {0x00000001, 0x00000002, 0x00000002, + 0x00000003, 0x00000002, 0000000000, + 0x00000003, 0x00000003}; + +static const INT opdDelta_Offset = 0; +static const INT opdDelta_MaxVal = 7; +/* PS Stereo Huffmantable: opdDeltaFreq */ +static const UINT opdDeltaFreq_Length[] = {1, 3, 4, 4, 5, 5, 4, 3}; +static const UINT opdDeltaFreq_Code[] = { + 0x00000001, 0x00000001, 0x00000006, 0x00000004, + 0x0000000f, 0x0000000e, 0x00000005, 0000000000, +}; + +/* PS Stereo Huffmantable: opdDeltaTime */ +static const UINT opdDeltaTime_Length[] = {1, 3, 4, 5, 5, 4, 4, 3}; +static const UINT opdDeltaTime_Code[] = {0x00000001, 0x00000002, 0x00000001, + 0x00000007, 0x00000006, 0000000000, + 0x00000002, 0x00000003}; + +static INT getNoBands(const INT mode) { + INT noBands = 0; + + switch (mode) { + case 0: + case 3: /* coarse */ + noBands = PS_BANDS_COARSE; + break; + case 1: + case 4: /* mid */ + noBands = PS_BANDS_MID; + break; + case 2: + case 5: /* fine not supported */ + default: /* coarse as default */ + noBands = PS_BANDS_COARSE; + } + + return noBands; +} + +static INT getIIDRes(INT iidMode) { + if (iidMode < 3) + return PS_IID_RES_COARSE; + else + return PS_IID_RES_FINE; +} + +static INT encodeDeltaFreq(HANDLE_FDK_BITSTREAM hBitBuf, const INT *val, + const INT nBands, const UINT *codeTable, + const UINT *lengthTable, const INT tableOffset, + const INT maxVal, INT *error) { + INT bitCnt = 0; + INT lastVal = 0; + INT band; + + for (band = 0; band < nBands; band++) { + INT delta = (val[band] - lastVal) + tableOffset; + lastVal = val[band]; + if ((delta > maxVal) || (delta < 0)) { + *error = 1; + delta = delta > 0 ? maxVal : 0; + } + bitCnt += + FDKsbrEnc_WriteBits_ps(hBitBuf, codeTable[delta], lengthTable[delta]); + } + + return bitCnt; +} + +static INT encodeDeltaTime(HANDLE_FDK_BITSTREAM hBitBuf, const INT *val, + const INT *valLast, const INT nBands, + const UINT *codeTable, const UINT *lengthTable, + const INT tableOffset, const INT maxVal, + INT *error) { + INT bitCnt = 0; + INT band; + + for (band = 0; band < nBands; band++) { + INT delta = (val[band] - valLast[band]) + tableOffset; + if ((delta > maxVal) || (delta < 0)) { + *error = 1; + delta = delta > 0 ? maxVal : 0; + } + bitCnt += + FDKsbrEnc_WriteBits_ps(hBitBuf, codeTable[delta], lengthTable[delta]); + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeIid(HANDLE_FDK_BITSTREAM hBitBuf, const INT *iidVal, + const INT *iidValLast, const INT nBands, + const PS_IID_RESOLUTION res, const PS_DELTA mode, + INT *error) { + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + bitCnt = 0; + + switch (mode) { + case PS_DELTA_FREQ: + switch (res) { + case PS_IID_RES_COARSE: + codeTable = iidDeltaFreqCoarse_Code; + lengthTable = iidDeltaFreqCoarse_Length; + bitCnt += encodeDeltaFreq(hBitBuf, iidVal, nBands, codeTable, + lengthTable, iidDeltaCoarse_Offset, + iidDeltaCoarse_MaxVal, error); + break; + case PS_IID_RES_FINE: + codeTable = iidDeltaFreqFine_Code; + lengthTable = iidDeltaFreqFine_Length; + bitCnt += + encodeDeltaFreq(hBitBuf, iidVal, nBands, codeTable, lengthTable, + iidDeltaFine_Offset, iidDeltaFine_MaxVal, error); + break; + default: + *error = 1; + } + break; + + case PS_DELTA_TIME: + switch (res) { + case PS_IID_RES_COARSE: + codeTable = iidDeltaTimeCoarse_Code; + lengthTable = iidDeltaTimeCoarse_Length; + bitCnt += encodeDeltaTime( + hBitBuf, iidVal, iidValLast, nBands, codeTable, lengthTable, + iidDeltaCoarse_Offset, iidDeltaCoarse_MaxVal, error); + break; + case PS_IID_RES_FINE: + codeTable = iidDeltaTimeFine_Code; + lengthTable = iidDeltaTimeFine_Length; + bitCnt += encodeDeltaTime(hBitBuf, iidVal, iidValLast, nBands, + codeTable, lengthTable, iidDeltaFine_Offset, + iidDeltaFine_MaxVal, error); + break; + default: + *error = 1; + } + break; + + default: + *error = 1; + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeIcc(HANDLE_FDK_BITSTREAM hBitBuf, const INT *iccVal, + const INT *iccValLast, const INT nBands, + const PS_DELTA mode, INT *error) { + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + switch (mode) { + case PS_DELTA_FREQ: + codeTable = iccDeltaFreq_Code; + lengthTable = iccDeltaFreq_Length; + bitCnt += encodeDeltaFreq(hBitBuf, iccVal, nBands, codeTable, lengthTable, + iccDelta_Offset, iccDelta_MaxVal, error); + break; + + case PS_DELTA_TIME: + codeTable = iccDeltaTime_Code; + lengthTable = iccDeltaTime_Length; + + bitCnt += + encodeDeltaTime(hBitBuf, iccVal, iccValLast, nBands, codeTable, + lengthTable, iccDelta_Offset, iccDelta_MaxVal, error); + break; + + default: + *error = 1; + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeIpd(HANDLE_FDK_BITSTREAM hBitBuf, const INT *ipdVal, + const INT *ipdValLast, const INT nBands, + const PS_DELTA mode, INT *error) { + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + switch (mode) { + case PS_DELTA_FREQ: + codeTable = ipdDeltaFreq_Code; + lengthTable = ipdDeltaFreq_Length; + bitCnt += encodeDeltaFreq(hBitBuf, ipdVal, nBands, codeTable, lengthTable, + ipdDelta_Offset, ipdDelta_MaxVal, error); + break; + + case PS_DELTA_TIME: + codeTable = ipdDeltaTime_Code; + lengthTable = ipdDeltaTime_Length; + + bitCnt += + encodeDeltaTime(hBitBuf, ipdVal, ipdValLast, nBands, codeTable, + lengthTable, ipdDelta_Offset, ipdDelta_MaxVal, error); + break; + + default: + *error = 1; + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeOpd(HANDLE_FDK_BITSTREAM hBitBuf, const INT *opdVal, + const INT *opdValLast, const INT nBands, + const PS_DELTA mode, INT *error) { + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + switch (mode) { + case PS_DELTA_FREQ: + codeTable = opdDeltaFreq_Code; + lengthTable = opdDeltaFreq_Length; + bitCnt += encodeDeltaFreq(hBitBuf, opdVal, nBands, codeTable, lengthTable, + opdDelta_Offset, opdDelta_MaxVal, error); + break; + + case PS_DELTA_TIME: + codeTable = opdDeltaTime_Code; + lengthTable = opdDeltaTime_Length; + + bitCnt += + encodeDeltaTime(hBitBuf, opdVal, opdValLast, nBands, codeTable, + lengthTable, opdDelta_Offset, opdDelta_MaxVal, error); + break; + + default: + *error = 1; + } + + return bitCnt; +} + +static INT encodeIpdOpd(HANDLE_PS_OUT psOut, HANDLE_FDK_BITSTREAM hBitBuf) { + INT bitCnt = 0; + INT error = 0; + INT env; + + FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->enableIpdOpd, 1); + + if (psOut->enableIpdOpd == 1) { + INT *ipdLast = psOut->ipdLast; + INT *opdLast = psOut->opdLast; + + for (env = 0; env < psOut->nEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->deltaIPD[env], 1); + bitCnt += FDKsbrEnc_EncodeIpd(hBitBuf, psOut->ipd[env], ipdLast, + getNoBands(psOut->iidMode), + psOut->deltaIPD[env], &error); + + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->deltaOPD[env], 1); + bitCnt += FDKsbrEnc_EncodeOpd(hBitBuf, psOut->opd[env], opdLast, + getNoBands(psOut->iidMode), + psOut->deltaOPD[env], &error); + } + /* reserved bit */ + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, 0, 1); + } + + return bitCnt; +} + +static INT getEnvIdx(const INT nEnvelopes, const INT frameClass) { + INT envIdx = 0; + + switch (nEnvelopes) { + case 0: + envIdx = 0; + break; + + case 1: + if (frameClass == 0) + envIdx = 1; + else + envIdx = 0; + break; + + case 2: + if (frameClass == 0) + envIdx = 2; + else + envIdx = 1; + break; + + case 3: + envIdx = 2; + break; + + case 4: + envIdx = 3; + break; + + default: + /* unsupported number of envelopes */ + envIdx = 0; + } + + return envIdx; +} + +static INT encodePSExtension(const HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf) { + INT bitCnt = 0; + + if (psOut->enableIpdOpd == 1) { + INT ipdOpdBits = 0; + INT extSize = (2 + encodeIpdOpd(psOut, NULL) + 7) >> 3; + + if (extSize < 15) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, extSize, 4); + } else { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, 15, 4); + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, (extSize - 15), 8); + } + + /* write ipd opd data */ + ipdOpdBits += FDKsbrEnc_WriteBits_ps(hBitBuf, PS_EXT_ID_V0, 2); + ipdOpdBits += encodeIpdOpd(psOut, hBitBuf); + + /* byte align the ipd opd data */ + if (ipdOpdBits % 8) + ipdOpdBits += FDKsbrEnc_WriteBits_ps(hBitBuf, 0, (8 - (ipdOpdBits % 8))); + + bitCnt += ipdOpdBits; + } + + return (bitCnt); +} + +INT FDKsbrEnc_WritePSBitstream(const HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf) { + INT psExtEnable = 0; + INT bitCnt = 0; + INT error = 0; + INT env; + + if (psOut != NULL) { + /* PS HEADER */ + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->enablePSHeader, 1); + + if (psOut->enablePSHeader) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->enableIID, 1); + if (psOut->enableIID) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->iidMode, 3); + } + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->enableICC, 1); + if (psOut->enableICC) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->iccMode, 3); + } + if (psOut->enableIpdOpd) { + psExtEnable = 1; + } + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psExtEnable, 1); + } + + /* Frame class, number of envelopes */ + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->frameClass, 1); + bitCnt += FDKsbrEnc_WriteBits_ps( + hBitBuf, getEnvIdx(psOut->nEnvelopes, psOut->frameClass), 2); + + if (psOut->frameClass == 1) { + for (env = 0; env < psOut->nEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->frameBorder[env], 5); + } + } + + if (psOut->enableIID == 1) { + INT *iidLast = psOut->iidLast; + for (env = 0; env < psOut->nEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->deltaIID[env], 1); + bitCnt += FDKsbrEnc_EncodeIid( + hBitBuf, psOut->iid[env], iidLast, getNoBands(psOut->iidMode), + (PS_IID_RESOLUTION)getIIDRes(psOut->iidMode), psOut->deltaIID[env], + &error); + + iidLast = psOut->iid[env]; + } + } + + if (psOut->enableICC == 1) { + INT *iccLast = psOut->iccLast; + for (env = 0; env < psOut->nEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->deltaICC[env], 1); + bitCnt += FDKsbrEnc_EncodeIcc(hBitBuf, psOut->icc[env], iccLast, + getNoBands(psOut->iccMode), + psOut->deltaICC[env], &error); + + iccLast = psOut->icc[env]; + } + } + + if (psExtEnable != 0) { + bitCnt += encodePSExtension(psOut, hBitBuf); + } + + } /* if(psOut != NULL) */ + + return bitCnt; +} diff --git a/fdk-aac/libSBRenc/src/ps_bitenc.h b/fdk-aac/libSBRenc/src/ps_bitenc.h new file mode 100644 index 0000000..1d383e3 --- /dev/null +++ b/fdk-aac/libSBRenc/src/ps_bitenc.h @@ -0,0 +1,173 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): N. Rettelbach + + Description: Parametric Stereo bitstream encoder + +*******************************************************************************/ + +#include "ps_main.h" +#include "ps_const.h" +#include "FDK_bitstream.h" + +#ifndef PS_BITENC_H +#define PS_BITENC_H + +typedef struct T_PS_OUT { + INT enablePSHeader; + INT enableIID; + INT iidMode; + INT enableICC; + INT iccMode; + INT enableIpdOpd; + + INT frameClass; + INT nEnvelopes; + /* ENV data */ + INT frameBorder[PS_MAX_ENVELOPES]; + + /* iid data */ + PS_DELTA deltaIID[PS_MAX_ENVELOPES]; + INT iid[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iidLast[PS_MAX_BANDS]; + + /* icc data */ + PS_DELTA deltaICC[PS_MAX_ENVELOPES]; + INT icc[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iccLast[PS_MAX_BANDS]; + + /* ipd data */ + PS_DELTA deltaIPD[PS_MAX_ENVELOPES]; + INT ipd[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT ipdLast[PS_MAX_BANDS]; + + /* opd data */ + PS_DELTA deltaOPD[PS_MAX_ENVELOPES]; + INT opd[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT opdLast[PS_MAX_BANDS]; + +} PS_OUT, *HANDLE_PS_OUT; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +INT FDKsbrEnc_EncodeIid(HANDLE_FDK_BITSTREAM hBitBuf, const INT *iidVal, + const INT *iidValLast, const INT nBands, + const PS_IID_RESOLUTION res, const PS_DELTA mode, + INT *error); + +INT FDKsbrEnc_EncodeIcc(HANDLE_FDK_BITSTREAM hBitBuf, const INT *iccVal, + const INT *iccValLast, const INT nBands, + const PS_DELTA mode, INT *error); + +INT FDKsbrEnc_EncodeIpd(HANDLE_FDK_BITSTREAM hBitBuf, const INT *ipdVal, + const INT *ipdValLast, const INT nBands, + const PS_DELTA mode, INT *error); + +INT FDKsbrEnc_EncodeOpd(HANDLE_FDK_BITSTREAM hBitBuf, const INT *opdVal, + const INT *opdValLast, const INT nBands, + const PS_DELTA mode, INT *error); + +INT FDKsbrEnc_WritePSBitstream(const HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* defined(PSENC_ENABLE) */ diff --git a/fdk-aac/libSBRenc/src/ps_const.h b/fdk-aac/libSBRenc/src/ps_const.h new file mode 100644 index 0000000..b9a33f9 --- /dev/null +++ b/fdk-aac/libSBRenc/src/ps_const.h @@ -0,0 +1,150 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): N. Rettelbach + + Description: Parametric Stereo constants + +*******************************************************************************/ + +#ifndef PS_CONST_H +#define PS_CONST_H + +#define MAX_PS_CHANNELS (2) +#define HYBRID_MAX_QMF_BANDS (3) +#define HYBRID_FILTER_LENGTH (13) +#define HYBRID_FILTER_DELAY ((HYBRID_FILTER_LENGTH - 1) / 2) + +#define HYBRID_FRAMESIZE (32) +#define HYBRID_READ_OFFSET (10) + +#define MAX_HYBRID_BANDS ((64 - HYBRID_MAX_QMF_BANDS + 10)) + +typedef enum { + PS_RES_COARSE = 0, + PS_RES_MID = 1, + PS_RES_FINE = 2 +} PS_RESOLUTION; + +typedef enum { + PS_BANDS_COARSE = 10, + PS_BANDS_MID = 20, + PS_MAX_BANDS = PS_BANDS_MID +} PS_BANDS; + +typedef enum { PS_IID_RES_COARSE = 0, PS_IID_RES_FINE } PS_IID_RESOLUTION; + +typedef enum { PS_ICC_ROT_A = 0, PS_ICC_ROT_B } PS_ICC_ROTATION_MODE; + +typedef enum { PS_DELTA_FREQ, PS_DELTA_TIME } PS_DELTA; + +typedef enum { + PS_MAX_ENVELOPES = 4 + +} PS_CONSTS; + +typedef enum { + PSENC_OK = 0x0000, /*!< No error happened. All fine. */ + PSENC_INVALID_HANDLE = + 0x0020, /*!< Handle passed to function call was invalid. */ + PSENC_MEMORY_ERROR = 0x0021, /*!< Memory allocation failed. */ + PSENC_INIT_ERROR = 0x0040, /*!< General initialization error. */ + PSENC_ENCODE_ERROR = 0x0060 /*!< The encoding process was interrupted by an + unexpected error. */ + +} FDK_PSENC_ERROR; + +#endif diff --git a/fdk-aac/libSBRenc/src/ps_encode.cpp b/fdk-aac/libSBRenc/src/ps_encode.cpp new file mode 100644 index 0000000..88d3131 --- /dev/null +++ b/fdk-aac/libSBRenc/src/ps_encode.cpp @@ -0,0 +1,1031 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): M. Neuendorf, N. Rettelbach, M. Multrus + + Description: PS parameter extraction, encoding + +*******************************************************************************/ + +/*! + \file + \brief PS parameter extraction, encoding functions $Revision: 96441 $ +*/ + +#include "ps_main.h" +#include "ps_encode.h" +#include "qmf.h" +#include "sbr_misc.h" +#include "sbrenc_ram.h" + +#include "genericStds.h" + +inline void FDKsbrEnc_addFIXP_DBL(const FIXP_DBL *X, const FIXP_DBL *Y, + FIXP_DBL *Z, INT n) { + for (INT i = 0; i < n; i++) Z[i] = (X[i] >> 1) + (Y[i] >> 1); +} + +#define LOG10_2_10 3.01029995664f /* 10.0f*log10(2.f) */ + +static const INT + iidGroupBordersLoRes[QMF_GROUPS_LO_RES + SUBQMF_GROUPS_LO_RES + 1] = { + 0, 1, 2, 3, 4, 5, /* 6 subqmf subbands - 0th qmf subband */ + 6, 7, /* 2 subqmf subbands - 1st qmf subband */ + 8, 9, /* 2 subqmf subbands - 2nd qmf subband */ + 10, 11, 12, 13, 14, 15, 16, 18, 21, 25, 30, 42, 71}; + +static const UCHAR + iidGroupWidthLdLoRes[QMF_GROUPS_LO_RES + SUBQMF_GROUPS_LO_RES] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 4, 5}; + +static const INT subband2parameter20[QMF_GROUPS_LO_RES + SUBQMF_GROUPS_LO_RES] = + {1, 0, 0, 1, 2, 3, /* 6 subqmf subbands - 0th qmf subband */ + 4, 5, /* 2 subqmf subbands - 1st qmf subband */ + 6, 7, /* 2 subqmf subbands - 2nd qmf subband */ + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + +typedef enum { + MAX_TIME_DIFF_FRAMES = 20, + MAX_PS_NOHEADER_CNT = 10, + MAX_NOENV_CNT = 10, + DO_NOT_USE_THIS_MODE = 0x7FFFFF +} __PS_CONSTANTS; + +static const FIXP_DBL iidQuant_fx[15] = { + (FIXP_DBL)0xce000000, (FIXP_DBL)0xdc000000, (FIXP_DBL)0xe4000000, + (FIXP_DBL)0xec000000, (FIXP_DBL)0xf2000000, (FIXP_DBL)0xf8000000, + (FIXP_DBL)0xfc000000, (FIXP_DBL)0x00000000, (FIXP_DBL)0x04000000, + (FIXP_DBL)0x08000000, (FIXP_DBL)0x0e000000, (FIXP_DBL)0x14000000, + (FIXP_DBL)0x1c000000, (FIXP_DBL)0x24000000, (FIXP_DBL)0x32000000}; + +static const FIXP_DBL iidQuantFine_fx[31] = { + (FIXP_DBL)0x9c000001, (FIXP_DBL)0xa6000001, (FIXP_DBL)0xb0000001, + (FIXP_DBL)0xba000001, (FIXP_DBL)0xc4000000, (FIXP_DBL)0xce000000, + (FIXP_DBL)0xd4000000, (FIXP_DBL)0xda000000, (FIXP_DBL)0xe0000000, + (FIXP_DBL)0xe6000000, (FIXP_DBL)0xec000000, (FIXP_DBL)0xf0000000, + (FIXP_DBL)0xf4000000, (FIXP_DBL)0xf8000000, (FIXP_DBL)0xfc000000, + (FIXP_DBL)0x00000000, (FIXP_DBL)0x04000000, (FIXP_DBL)0x08000000, + (FIXP_DBL)0x0c000000, (FIXP_DBL)0x10000000, (FIXP_DBL)0x14000000, + (FIXP_DBL)0x1a000000, (FIXP_DBL)0x20000000, (FIXP_DBL)0x26000000, + (FIXP_DBL)0x2c000000, (FIXP_DBL)0x32000000, (FIXP_DBL)0x3c000000, + (FIXP_DBL)0x45ffffff, (FIXP_DBL)0x4fffffff, (FIXP_DBL)0x59ffffff, + (FIXP_DBL)0x63ffffff}; + +static const FIXP_DBL iccQuant[8] = { + (FIXP_DBL)0x7fffffff, (FIXP_DBL)0x77ef9d7f, (FIXP_DBL)0x6babc97f, + (FIXP_DBL)0x4ceaf27f, (FIXP_DBL)0x2f0ed3c0, (FIXP_DBL)0x00000000, + (FIXP_DBL)0xb49ba601, (FIXP_DBL)0x80000000}; + +static FDK_PSENC_ERROR InitPSData(HANDLE_PS_DATA hPsData) { + FDK_PSENC_ERROR error = PSENC_OK; + + if (hPsData == NULL) { + error = PSENC_INVALID_HANDLE; + } else { + int i, env; + FDKmemclear(hPsData, sizeof(PS_DATA)); + + for (i = 0; i < PS_MAX_BANDS; i++) { + hPsData->iidIdxLast[i] = 0; + hPsData->iccIdxLast[i] = 0; + } + + hPsData->iidEnable = hPsData->iidEnableLast = 0; + hPsData->iccEnable = hPsData->iccEnableLast = 0; + hPsData->iidQuantMode = hPsData->iidQuantModeLast = PS_IID_RES_COARSE; + hPsData->iccQuantMode = hPsData->iccQuantModeLast = PS_ICC_ROT_A; + + for (env = 0; env < PS_MAX_ENVELOPES; env++) { + hPsData->iccDiffMode[env] = PS_DELTA_FREQ; + hPsData->iccDiffMode[env] = PS_DELTA_FREQ; + + for (i = 0; i < PS_MAX_BANDS; i++) { + hPsData->iidIdx[env][i] = 0; + hPsData->iccIdx[env][i] = 0; + } + } + + hPsData->nEnvelopesLast = 0; + + hPsData->headerCnt = MAX_PS_NOHEADER_CNT; + hPsData->iidTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->noEnvCnt = MAX_NOENV_CNT; + } + + return error; +} + +static FIXP_DBL quantizeCoef(const FIXP_DBL *RESTRICT input, const INT nBands, + const FIXP_DBL *RESTRICT quantTable, + const INT idxOffset, const INT nQuantSteps, + INT *RESTRICT quantOut) { + INT idx, band; + FIXP_DBL quantErr = FL2FXCONST_DBL(0.f); + + for (band = 0; band < nBands; band++) { + for (idx = 0; idx < nQuantSteps - 1; idx++) { + if (fixp_abs((input[band] >> 1) - (quantTable[idx + 1] >> 1)) > + fixp_abs((input[band] >> 1) - (quantTable[idx] >> 1))) { + break; + } + } + quantErr += (fixp_abs(input[band] - quantTable[idx]) >> + PS_QUANT_SCALE); /* don't scale before subtraction; diff + smaller (64-25)/64 */ + quantOut[band] = idx - idxOffset; + } + + return quantErr; +} + +static INT getICCMode(const INT nBands, const INT rotType) { + INT mode = 0; + + switch (nBands) { + case PS_BANDS_COARSE: + mode = PS_RES_COARSE; + break; + case PS_BANDS_MID: + mode = PS_RES_MID; + break; + default: + mode = 0; + } + if (rotType == PS_ICC_ROT_B) { + mode += 3; + } + + return mode; +} + +static INT getIIDMode(const INT nBands, const INT iidRes) { + INT mode = 0; + + switch (nBands) { + case PS_BANDS_COARSE: + mode = PS_RES_COARSE; + break; + case PS_BANDS_MID: + mode = PS_RES_MID; + break; + default: + mode = 0; + break; + } + + if (iidRes == PS_IID_RES_FINE) { + mode += 3; + } + + return mode; +} + +static INT envelopeReducible(FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS], + INT psBands, INT nEnvelopes) { +#define THRESH_SCALE 7 + + INT reducible = 1; /* true */ + INT e = 0, b = 0; + FIXP_DBL dIid = FL2FXCONST_DBL(0.f); + FIXP_DBL dIcc = FL2FXCONST_DBL(0.f); + + FIXP_DBL iidErrThreshold, iccErrThreshold; + FIXP_DBL iidMeanError, iccMeanError; + + /* square values to prevent sqrt, + multiply bands to prevent division; bands shifted DFRACT_BITS instead + (DFRACT_BITS-1) because fMultDiv2 used*/ + iidErrThreshold = + fMultDiv2(FL2FXCONST_DBL(6.5f * 6.5f / (IID_SCALE_FT * IID_SCALE_FT)), + (FIXP_DBL)(psBands << ((DFRACT_BITS)-THRESH_SCALE))); + iccErrThreshold = + fMultDiv2(FL2FXCONST_DBL(0.75f * 0.75f), + (FIXP_DBL)(psBands << ((DFRACT_BITS)-THRESH_SCALE))); + + if (nEnvelopes <= 1) { + reducible = 0; + } else { + /* mean error criterion */ + for (e = 0; (e < nEnvelopes / 2) && (reducible != 0); e++) { + iidMeanError = iccMeanError = FL2FXCONST_DBL(0.f); + for (b = 0; b < psBands; b++) { + dIid = (iid[2 * e][b] >> 1) - + (iid[2 * e + 1][b] >> 1); /* scale 1 bit; squared -> 2 bit */ + dIcc = (icc[2 * e][b] >> 1) - (icc[2 * e + 1][b] >> 1); + iidMeanError += fPow2Div2(dIid) >> (5 - 1); /* + (bands=20) scale = 5 */ + iccMeanError += fPow2Div2(dIcc) >> (5 - 1); + } /* --> scaling = 7 bit = THRESH_SCALE !! */ + + /* instead sqrt values are squared! + instead of division, multiply threshold with psBands + scaling necessary!! */ + + /* quit as soon as threshold is reached */ + if ((iidMeanError > (iidErrThreshold)) || + (iccMeanError > (iccErrThreshold))) { + reducible = 0; + } + } + } /* nEnvelopes != 1 */ + + return reducible; +} + +static void processIidData(PS_DATA *psData, + FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS], + const INT psBands, const INT nEnvelopes, + const FIXP_DBL quantErrorThreshold) { + INT iidIdxFine[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iidIdxCoarse[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + + FIXP_DBL errIID = FL2FXCONST_DBL(0.f); + FIXP_DBL errIIDFine = FL2FXCONST_DBL(0.f); + INT bitsIidFreq = 0; + INT bitsIidTime = 0; + INT bitsFineTot = 0; + INT bitsCoarseTot = 0; + INT error = 0; + INT env, band; + INT diffMode[PS_MAX_ENVELOPES], diffModeFine[PS_MAX_ENVELOPES]; + INT loudnDiff = 0; + INT iidTransmit = 0; + + /* Quantize IID coefficients */ + for (env = 0; env < nEnvelopes; env++) { + errIID += + quantizeCoef(iid[env], psBands, iidQuant_fx, 7, 15, iidIdxCoarse[env]); + errIIDFine += quantizeCoef(iid[env], psBands, iidQuantFine_fx, 15, 31, + iidIdxFine[env]); + } + + /* normalize error to number of envelopes, ps bands + errIID /= psBands*nEnvelopes; + errIIDFine /= psBands*nEnvelopes; */ + + /* Check if IID coefficients should be used in this frame */ + psData->iidEnable = 0; + for (env = 0; env < nEnvelopes; env++) { + for (band = 0; band < psBands; band++) { + loudnDiff += fixp_abs(iidIdxCoarse[env][band]); + iidTransmit++; + } + } + + if (loudnDiff > + fMultI(FL2FXCONST_DBL(0.7f), iidTransmit)) { /* 0.7f empiric value */ + psData->iidEnable = 1; + } + + /* if iid not active -> RESET data */ + if (psData->iidEnable == 0) { + psData->iidTimeCnt = MAX_TIME_DIFF_FRAMES; + for (env = 0; env < nEnvelopes; env++) { + psData->iidDiffMode[env] = PS_DELTA_FREQ; + FDKmemclear(psData->iidIdx[env], sizeof(INT) * psBands); + } + return; + } + + /* count COARSE quantization bits for first envelope*/ + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[0], NULL, psBands, + PS_IID_RES_COARSE, PS_DELTA_FREQ, &error); + + if ((psData->iidTimeCnt >= MAX_TIME_DIFF_FRAMES) || + (psData->iidQuantModeLast == PS_IID_RES_FINE)) { + bitsIidTime = DO_NOT_USE_THIS_MODE; + } else { + bitsIidTime = + FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[0], psData->iidIdxLast, psBands, + PS_IID_RES_COARSE, PS_DELTA_TIME, &error); + } + + /* decision DELTA_FREQ vs DELTA_TIME */ + if (bitsIidTime > bitsIidFreq) { + diffMode[0] = PS_DELTA_FREQ; + bitsCoarseTot = bitsIidFreq; + } else { + diffMode[0] = PS_DELTA_TIME; + bitsCoarseTot = bitsIidTime; + } + + /* count COARSE quantization bits for following envelopes*/ + for (env = 1; env < nEnvelopes; env++) { + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[env], NULL, psBands, + PS_IID_RES_COARSE, PS_DELTA_FREQ, &error); + bitsIidTime = + FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[env], iidIdxCoarse[env - 1], + psBands, PS_IID_RES_COARSE, PS_DELTA_TIME, &error); + + /* decision DELTA_FREQ vs DELTA_TIME */ + if (bitsIidTime > bitsIidFreq) { + diffMode[env] = PS_DELTA_FREQ; + bitsCoarseTot += bitsIidFreq; + } else { + diffMode[env] = PS_DELTA_TIME; + bitsCoarseTot += bitsIidTime; + } + } + + /* count FINE quantization bits for first envelope*/ + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxFine[0], NULL, psBands, + PS_IID_RES_FINE, PS_DELTA_FREQ, &error); + + if ((psData->iidTimeCnt >= MAX_TIME_DIFF_FRAMES) || + (psData->iidQuantModeLast == PS_IID_RES_COARSE)) { + bitsIidTime = DO_NOT_USE_THIS_MODE; + } else { + bitsIidTime = + FDKsbrEnc_EncodeIid(NULL, iidIdxFine[0], psData->iidIdxLast, psBands, + PS_IID_RES_FINE, PS_DELTA_TIME, &error); + } + + /* decision DELTA_FREQ vs DELTA_TIME */ + if (bitsIidTime > bitsIidFreq) { + diffModeFine[0] = PS_DELTA_FREQ; + bitsFineTot = bitsIidFreq; + } else { + diffModeFine[0] = PS_DELTA_TIME; + bitsFineTot = bitsIidTime; + } + + /* count FINE quantization bits for following envelopes*/ + for (env = 1; env < nEnvelopes; env++) { + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxFine[env], NULL, psBands, + PS_IID_RES_FINE, PS_DELTA_FREQ, &error); + bitsIidTime = + FDKsbrEnc_EncodeIid(NULL, iidIdxFine[env], iidIdxFine[env - 1], psBands, + PS_IID_RES_FINE, PS_DELTA_TIME, &error); + + /* decision DELTA_FREQ vs DELTA_TIME */ + if (bitsIidTime > bitsIidFreq) { + diffModeFine[env] = PS_DELTA_FREQ; + bitsFineTot += bitsIidFreq; + } else { + diffModeFine[env] = PS_DELTA_TIME; + bitsFineTot += bitsIidTime; + } + } + + if (bitsFineTot == bitsCoarseTot) { + /* if same number of bits is needed, use the quantization with lower error + */ + if (errIIDFine < errIID) { + bitsCoarseTot = DO_NOT_USE_THIS_MODE; + } else { + bitsFineTot = DO_NOT_USE_THIS_MODE; + } + } else { + /* const FIXP_DBL minThreshold = + * FL2FXCONST_DBL(0.2f/(IID_SCALE_FT*PS_QUANT_SCALE_FT)*(psBands*nEnvelopes)); + */ + const FIXP_DBL minThreshold = + (FIXP_DBL)((LONG)0x00019999 * (psBands * nEnvelopes)); + + /* decision RES_FINE vs RES_COARSE */ + /* test if errIIDFine*quantErrorThreshold < errIID */ + /* shiftVal 2 comes from scaling of quantErrorThreshold */ + if (fixMax(((errIIDFine >> 1) + (minThreshold >> 1)) >> 1, + fMult(quantErrorThreshold, errIIDFine)) < (errIID >> 2)) { + bitsCoarseTot = DO_NOT_USE_THIS_MODE; + } else if (fixMax(((errIID >> 1) + (minThreshold >> 1)) >> 1, + fMult(quantErrorThreshold, errIID)) < (errIIDFine >> 2)) { + bitsFineTot = DO_NOT_USE_THIS_MODE; + } + } + + /* decision RES_FINE vs RES_COARSE */ + if (bitsFineTot < bitsCoarseTot) { + psData->iidQuantMode = PS_IID_RES_FINE; + for (env = 0; env < nEnvelopes; env++) { + psData->iidDiffMode[env] = diffModeFine[env]; + FDKmemcpy(psData->iidIdx[env], iidIdxFine[env], psBands * sizeof(INT)); + } + } else { + psData->iidQuantMode = PS_IID_RES_COARSE; + for (env = 0; env < nEnvelopes; env++) { + psData->iidDiffMode[env] = diffMode[env]; + FDKmemcpy(psData->iidIdx[env], iidIdxCoarse[env], psBands * sizeof(INT)); + } + } + + /* Count DELTA_TIME encoding streaks */ + for (env = 0; env < nEnvelopes; env++) { + if (psData->iidDiffMode[env] == PS_DELTA_TIME) + psData->iidTimeCnt++; + else + psData->iidTimeCnt = 0; + } +} + +static INT similarIid(PS_DATA *psData, const INT psBands, + const INT nEnvelopes) { + const INT diffThr = (psData->iidQuantMode == PS_IID_RES_COARSE) ? 2 : 3; + const INT sumDiffThr = diffThr * psBands / 4; + INT similar = 0; + INT diff = 0; + INT sumDiff = 0; + INT env = 0; + INT b = 0; + if ((nEnvelopes == psData->nEnvelopesLast) && (nEnvelopes == 1)) { + similar = 1; + for (env = 0; env < nEnvelopes; env++) { + sumDiff = 0; + b = 0; + do { + diff = fixp_abs(psData->iidIdx[env][b] - psData->iidIdxLast[b]); + sumDiff += diff; + if ((diff > diffThr) /* more than x quantization steps in any band */ + || (sumDiff > sumDiffThr)) { /* more than x quantisations steps + overall difference */ + similar = 0; + } + b++; + } while ((b < psBands) && (similar > 0)); + } + } /* nEnvelopes==1 */ + + return similar; +} + +static INT similarIcc(PS_DATA *psData, const INT psBands, + const INT nEnvelopes) { + const INT diffThr = 2; + const INT sumDiffThr = diffThr * psBands / 4; + INT similar = 0; + INT diff = 0; + INT sumDiff = 0; + INT env = 0; + INT b = 0; + if ((nEnvelopes == psData->nEnvelopesLast) && (nEnvelopes == 1)) { + similar = 1; + for (env = 0; env < nEnvelopes; env++) { + sumDiff = 0; + b = 0; + do { + diff = fixp_abs(psData->iccIdx[env][b] - psData->iccIdxLast[b]); + sumDiff += diff; + if ((diff > diffThr) /* more than x quantisation step in any band */ + || (sumDiff > sumDiffThr)) { /* more than x quantisations steps + overall difference */ + similar = 0; + } + b++; + } while ((b < psBands) && (similar > 0)); + } + } /* nEnvelopes==1 */ + + return similar; +} + +static void processIccData( + PS_DATA *psData, + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS], /* const input values: + unable to declare as + const, since it does + not poINT to const + memory */ + const INT psBands, const INT nEnvelopes) { + FIXP_DBL errICC = FL2FXCONST_DBL(0.f); + INT env, band; + INT bitsIccFreq, bitsIccTime; + INT error = 0; + INT inCoherence = 0, iccTransmit = 0; + INT *iccIdxLast; + + iccIdxLast = psData->iccIdxLast; + + /* Quantize ICC coefficients */ + for (env = 0; env < nEnvelopes; env++) { + errICC += + quantizeCoef(icc[env], psBands, iccQuant, 0, 8, psData->iccIdx[env]); + } + + /* Check if ICC coefficients should be used */ + psData->iccEnable = 0; + for (env = 0; env < nEnvelopes; env++) { + for (band = 0; band < psBands; band++) { + inCoherence += psData->iccIdx[env][band]; + iccTransmit++; + } + } + if (inCoherence > + fMultI(FL2FXCONST_DBL(0.5f), iccTransmit)) { /* 0.5f empiric value */ + psData->iccEnable = 1; + } + + if (psData->iccEnable == 0) { + psData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; + for (env = 0; env < nEnvelopes; env++) { + psData->iccDiffMode[env] = PS_DELTA_FREQ; + FDKmemclear(psData->iccIdx[env], sizeof(INT) * psBands); + } + return; + } + + for (env = 0; env < nEnvelopes; env++) { + bitsIccFreq = FDKsbrEnc_EncodeIcc(NULL, psData->iccIdx[env], NULL, psBands, + PS_DELTA_FREQ, &error); + + if (psData->iccTimeCnt < MAX_TIME_DIFF_FRAMES) { + bitsIccTime = FDKsbrEnc_EncodeIcc(NULL, psData->iccIdx[env], iccIdxLast, + psBands, PS_DELTA_TIME, &error); + } else { + bitsIccTime = DO_NOT_USE_THIS_MODE; + } + + if (bitsIccFreq > bitsIccTime) { + psData->iccDiffMode[env] = PS_DELTA_TIME; + psData->iccTimeCnt++; + } else { + psData->iccDiffMode[env] = PS_DELTA_FREQ; + psData->iccTimeCnt = 0; + } + iccIdxLast = psData->iccIdx[env]; + } +} + +static void calculateIID(FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL ldPwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS], + INT nEnvelopes, INT psBands) { + INT i = 0; + INT env = 0; + for (env = 0; env < nEnvelopes; env++) { + for (i = 0; i < psBands; i++) { + /* iid[env][i] = 10.0f*(float)log10(pwrL[env][i]/pwrR[env][i]); + */ + FIXP_DBL IID = fMultDiv2(FL2FXCONST_DBL(LOG10_2_10 / IID_SCALE_FT), + (ldPwrL[env][i] - ldPwrR[env][i])); + + IID = fixMin(IID, (FIXP_DBL)(MAXVAL_DBL >> (LD_DATA_SHIFT + 1))); + IID = fixMax(IID, (FIXP_DBL)(MINVAL_DBL >> (LD_DATA_SHIFT + 1))); + iid[env][i] = IID << (LD_DATA_SHIFT + 1); + } + } +} + +static void calculateICC(FIXP_DBL pwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL pwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL pwrCr[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL pwrCi[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS], + INT nEnvelopes, INT psBands) { + INT i = 0; + INT env = 0; + INT border = psBands; + + switch (psBands) { + case PS_BANDS_COARSE: + border = 5; + break; + case PS_BANDS_MID: + border = 11; + break; + default: + break; + } + + for (env = 0; env < nEnvelopes; env++) { + for (i = 0; i < border; i++) { + /* icc[env][i] = min( pwrCr[env][i] / (float) sqrt(pwrL[env][i] * + * pwrR[env][i]) , 1.f); + */ + int scale; + FIXP_DBL invNrg = invSqrtNorm2( + fMax(fMult(pwrL[env][i], pwrR[env][i]), (FIXP_DBL)1), &scale); + icc[env][i] = + SATURATE_LEFT_SHIFT(fMult(pwrCr[env][i], invNrg), scale, DFRACT_BITS); + } + + for (; i < psBands; i++) { + int denom_e; + FIXP_DBL denom_m = fMultNorm(pwrL[env][i], pwrR[env][i], &denom_e); + + if (denom_m == (FIXP_DBL)0) { + icc[env][i] = (FIXP_DBL)MAXVAL_DBL; + } else { + int num_e, result_e; + FIXP_DBL num_m, result_m; + + num_e = CountLeadingBits( + fixMax(fixp_abs(pwrCr[env][i]), fixp_abs(pwrCi[env][i]))); + num_m = fPow2Div2((pwrCr[env][i] << num_e)) + + fPow2Div2((pwrCi[env][i] << num_e)); + + result_m = fDivNorm(num_m, denom_m, &result_e); + result_e += (-2 * num_e + 1) - denom_e; + icc[env][i] = scaleValueSaturate(sqrtFixp(result_m >> (result_e & 1)), + (result_e + (result_e & 1)) >> 1); + } + } + } +} + +void FDKsbrEnc_initPsBandNrgScale(HANDLE_PS_ENCODE hPsEncode) { + INT group, bin; + INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; + + FDKmemclear(hPsEncode->psBandNrgScale, PS_MAX_BANDS * sizeof(SCHAR)); + + for (group = 0; group < nIidGroups; group++) { + /* Translate group to bin */ + bin = hPsEncode->subband2parameterIndex[group]; + + /* Translate from 20 bins to 10 bins */ + if (hPsEncode->psEncMode == PS_BANDS_COARSE) { + bin = bin >> 1; + } + + hPsEncode->psBandNrgScale[bin] = + (hPsEncode->psBandNrgScale[bin] == 0) + ? (hPsEncode->iidGroupWidthLd[group] + 5) + : (fixMax(hPsEncode->iidGroupWidthLd[group], + hPsEncode->psBandNrgScale[bin]) + + 1); + } +} + +FDK_PSENC_ERROR FDKsbrEnc_CreatePSEncode(HANDLE_PS_ENCODE *phPsEncode) { + FDK_PSENC_ERROR error = PSENC_OK; + + if (phPsEncode == NULL) { + error = PSENC_INVALID_HANDLE; + } else { + HANDLE_PS_ENCODE hPsEncode = NULL; + if (NULL == (hPsEncode = GetRam_PsEncode())) { + error = PSENC_MEMORY_ERROR; + goto bail; + } + FDKmemclear(hPsEncode, sizeof(PS_ENCODE)); + *phPsEncode = hPsEncode; /* return allocated handle */ + } +bail: + return error; +} + +FDK_PSENC_ERROR FDKsbrEnc_InitPSEncode(HANDLE_PS_ENCODE hPsEncode, + const PS_BANDS psEncMode, + const FIXP_DBL iidQuantErrorThreshold) { + FDK_PSENC_ERROR error = PSENC_OK; + + if (NULL == hPsEncode) { + error = PSENC_INVALID_HANDLE; + } else { + if (PSENC_OK != (InitPSData(&hPsEncode->psData))) { + goto bail; + } + + switch (psEncMode) { + case PS_BANDS_COARSE: + case PS_BANDS_MID: + hPsEncode->nQmfIidGroups = QMF_GROUPS_LO_RES; + hPsEncode->nSubQmfIidGroups = SUBQMF_GROUPS_LO_RES; + FDKmemcpy(hPsEncode->iidGroupBorders, iidGroupBordersLoRes, + (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups + 1) * + sizeof(INT)); + FDKmemcpy(hPsEncode->subband2parameterIndex, subband2parameter20, + (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) * + sizeof(INT)); + FDKmemcpy(hPsEncode->iidGroupWidthLd, iidGroupWidthLdLoRes, + (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) * + sizeof(UCHAR)); + break; + default: + error = PSENC_INIT_ERROR; + goto bail; + } + + hPsEncode->psEncMode = psEncMode; + hPsEncode->iidQuantErrorThreshold = iidQuantErrorThreshold; + FDKsbrEnc_initPsBandNrgScale(hPsEncode); + } +bail: + return error; +} + +FDK_PSENC_ERROR FDKsbrEnc_DestroyPSEncode(HANDLE_PS_ENCODE *phPsEncode) { + FDK_PSENC_ERROR error = PSENC_OK; + + if (NULL != phPsEncode) { + FreeRam_PsEncode(phPsEncode); + } + + return error; +} + +typedef struct { + FIXP_DBL pwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL pwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL ldPwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL pwrCr[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL pwrCi[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + +} PS_PWR_DATA; + +FDK_PSENC_ERROR FDKsbrEnc_PSEncode( + HANDLE_PS_ENCODE hPsEncode, HANDLE_PS_OUT hPsOut, UCHAR *dynBandScale, + UINT maxEnvelopes, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + const INT frameSize, const INT sendHeader) { + FDK_PSENC_ERROR error = PSENC_OK; + + HANDLE_PS_DATA hPsData = &hPsEncode->psData; + FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + int envBorder[PS_MAX_ENVELOPES + 1]; + + int group, bin, col, subband, band; + int i = 0; + + int env = 0; + int psBands = (int)hPsEncode->psEncMode; + int nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; + int nEnvelopes = fixMin(maxEnvelopes, (UINT)PS_MAX_ENVELOPES); + + C_ALLOC_SCRATCH_START(pwrData, PS_PWR_DATA, 1) + + for (env = 0; env < nEnvelopes + 1; env++) { + envBorder[env] = fMultI(GetInvInt(nEnvelopes), frameSize * env); + } + + for (env = 0; env < nEnvelopes; env++) { + /* clear energy array */ + for (band = 0; band < psBands; band++) { + pwrData->pwrL[env][band] = pwrData->pwrR[env][band] = + pwrData->pwrCr[env][band] = pwrData->pwrCi[env][band] = FIXP_DBL(1); + } + + /**** calculate energies and correlation ****/ + + /* start with hybrid data */ + for (group = 0; group < nIidGroups; group++) { + /* Translate group to bin */ + bin = hPsEncode->subband2parameterIndex[group]; + + /* Translate from 20 bins to 10 bins */ + if (hPsEncode->psEncMode == PS_BANDS_COARSE) { + bin >>= 1; + } + + /* determine group border */ + int bScale = hPsEncode->psBandNrgScale[bin]; + + FIXP_DBL pwrL_env_bin = pwrData->pwrL[env][bin]; + FIXP_DBL pwrR_env_bin = pwrData->pwrR[env][bin]; + FIXP_DBL pwrCr_env_bin = pwrData->pwrCr[env][bin]; + FIXP_DBL pwrCi_env_bin = pwrData->pwrCi[env][bin]; + + int scale = (int)dynBandScale[bin]; + for (col = envBorder[env]; col < envBorder[env + 1]; col++) { + for (subband = hPsEncode->iidGroupBorders[group]; + subband < hPsEncode->iidGroupBorders[group + 1]; subband++) { + FIXP_DBL l_real = (hybridData[col][0][0][subband]) << scale; + FIXP_DBL l_imag = (hybridData[col][0][1][subband]) << scale; + FIXP_DBL r_real = (hybridData[col][1][0][subband]) << scale; + FIXP_DBL r_imag = (hybridData[col][1][1][subband]) << scale; + + pwrL_env_bin += (fPow2Div2(l_real) + fPow2Div2(l_imag)) >> bScale; + pwrR_env_bin += (fPow2Div2(r_real) + fPow2Div2(r_imag)) >> bScale; + pwrCr_env_bin += + (fMultDiv2(l_real, r_real) + fMultDiv2(l_imag, r_imag)) >> bScale; + pwrCi_env_bin += + (fMultDiv2(r_real, l_imag) - fMultDiv2(l_real, r_imag)) >> bScale; + } + } + /* assure, nrg's of left and right channel are not negative; necessary on + * 16 bit multiply units */ + pwrData->pwrL[env][bin] = fixMax((FIXP_DBL)0, pwrL_env_bin); + pwrData->pwrR[env][bin] = fixMax((FIXP_DBL)0, pwrR_env_bin); + + pwrData->pwrCr[env][bin] = pwrCr_env_bin; + pwrData->pwrCi[env][bin] = pwrCi_env_bin; + + } /* nIidGroups */ + + /* calc logarithmic energy */ + LdDataVector(pwrData->pwrL[env], pwrData->ldPwrL[env], psBands); + LdDataVector(pwrData->pwrR[env], pwrData->ldPwrR[env], psBands); + + } /* nEnvelopes */ + + /* calculate iid and icc */ + calculateIID(pwrData->ldPwrL, pwrData->ldPwrR, iid, nEnvelopes, psBands); + calculateICC(pwrData->pwrL, pwrData->pwrR, pwrData->pwrCr, pwrData->pwrCi, + icc, nEnvelopes, psBands); + + /*** Envelope Reduction ***/ + while (envelopeReducible(iid, icc, psBands, nEnvelopes)) { + int e = 0; + /* sum energies of two neighboring envelopes */ + nEnvelopes >>= 1; + for (e = 0; e < nEnvelopes; e++) { + FDKsbrEnc_addFIXP_DBL(pwrData->pwrL[2 * e], pwrData->pwrL[2 * e + 1], + pwrData->pwrL[e], psBands); + FDKsbrEnc_addFIXP_DBL(pwrData->pwrR[2 * e], pwrData->pwrR[2 * e + 1], + pwrData->pwrR[e], psBands); + FDKsbrEnc_addFIXP_DBL(pwrData->pwrCr[2 * e], pwrData->pwrCr[2 * e + 1], + pwrData->pwrCr[e], psBands); + FDKsbrEnc_addFIXP_DBL(pwrData->pwrCi[2 * e], pwrData->pwrCi[2 * e + 1], + pwrData->pwrCi[e], psBands); + + /* calc logarithmic energy */ + LdDataVector(pwrData->pwrL[e], pwrData->ldPwrL[e], psBands); + LdDataVector(pwrData->pwrR[e], pwrData->ldPwrR[e], psBands); + + /* reduce number of envelopes and adjust borders */ + envBorder[e] = envBorder[2 * e]; + } + envBorder[nEnvelopes] = envBorder[2 * nEnvelopes]; + + /* re-calculate iid and icc */ + calculateIID(pwrData->ldPwrL, pwrData->ldPwrR, iid, nEnvelopes, psBands); + calculateICC(pwrData->pwrL, pwrData->pwrR, pwrData->pwrCr, pwrData->pwrCi, + icc, nEnvelopes, psBands); + } + + /* */ + if (sendHeader) { + hPsData->headerCnt = MAX_PS_NOHEADER_CNT; + hPsData->iidTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->noEnvCnt = MAX_NOENV_CNT; + } + + /*** Parameter processing, quantisation etc ***/ + processIidData(hPsData, iid, psBands, nEnvelopes, + hPsEncode->iidQuantErrorThreshold); + processIccData(hPsData, icc, psBands, nEnvelopes); + + /*** Initialize output struct ***/ + + /* PS Header on/off ? */ + if ((hPsData->headerCnt < MAX_PS_NOHEADER_CNT) && + ((hPsData->iidQuantMode == hPsData->iidQuantModeLast) && + (hPsData->iccQuantMode == hPsData->iccQuantModeLast)) && + ((hPsData->iidEnable == hPsData->iidEnableLast) && + (hPsData->iccEnable == hPsData->iccEnableLast))) { + hPsOut->enablePSHeader = 0; + } else { + hPsOut->enablePSHeader = 1; + hPsData->headerCnt = 0; + } + + /* nEnvelopes = 0 ? */ + if ((hPsData->noEnvCnt < MAX_NOENV_CNT) && + (similarIid(hPsData, psBands, nEnvelopes)) && + (similarIcc(hPsData, psBands, nEnvelopes))) { + hPsOut->nEnvelopes = nEnvelopes = 0; + hPsData->noEnvCnt++; + } else { + hPsData->noEnvCnt = 0; + } + + if (nEnvelopes > 0) { + hPsOut->enableIID = hPsData->iidEnable; + hPsOut->iidMode = getIIDMode(psBands, hPsData->iidQuantMode); + + hPsOut->enableICC = hPsData->iccEnable; + hPsOut->iccMode = getICCMode(psBands, hPsData->iccQuantMode); + + hPsOut->enableIpdOpd = 0; + hPsOut->frameClass = 0; + hPsOut->nEnvelopes = nEnvelopes; + + for (env = 0; env < nEnvelopes; env++) { + hPsOut->frameBorder[env] = envBorder[env + 1]; + hPsOut->deltaIID[env] = (PS_DELTA)hPsData->iidDiffMode[env]; + hPsOut->deltaICC[env] = (PS_DELTA)hPsData->iccDiffMode[env]; + for (band = 0; band < psBands; band++) { + hPsOut->iid[env][band] = hPsData->iidIdx[env][band]; + hPsOut->icc[env][band] = hPsData->iccIdx[env][band]; + } + } + + /* IPD OPD not supported right now */ + FDKmemclear(hPsOut->ipd, + PS_MAX_ENVELOPES * PS_MAX_BANDS * sizeof(PS_DELTA)); + for (env = 0; env < PS_MAX_ENVELOPES; env++) { + hPsOut->deltaIPD[env] = PS_DELTA_FREQ; + hPsOut->deltaOPD[env] = PS_DELTA_FREQ; + } + + FDKmemclear(hPsOut->ipdLast, PS_MAX_BANDS * sizeof(INT)); + FDKmemclear(hPsOut->opdLast, PS_MAX_BANDS * sizeof(INT)); + + for (band = 0; band < PS_MAX_BANDS; band++) { + hPsOut->iidLast[band] = hPsData->iidIdxLast[band]; + hPsOut->iccLast[band] = hPsData->iccIdxLast[band]; + } + + /* save iids and iccs for differential time coding in the next frame */ + hPsData->nEnvelopesLast = nEnvelopes; + hPsData->iidEnableLast = hPsData->iidEnable; + hPsData->iccEnableLast = hPsData->iccEnable; + hPsData->iidQuantModeLast = hPsData->iidQuantMode; + hPsData->iccQuantModeLast = hPsData->iccQuantMode; + for (i = 0; i < psBands; i++) { + hPsData->iidIdxLast[i] = hPsData->iidIdx[nEnvelopes - 1][i]; + hPsData->iccIdxLast[i] = hPsData->iccIdx[nEnvelopes - 1][i]; + } + } /* Envelope > 0 */ + + C_ALLOC_SCRATCH_END(pwrData, PS_PWR_DATA, 1) + + return error; +} diff --git a/fdk-aac/libSBRenc/src/ps_encode.h b/fdk-aac/libSBRenc/src/ps_encode.h new file mode 100644 index 0000000..4237a00 --- /dev/null +++ b/fdk-aac/libSBRenc/src/ps_encode.h @@ -0,0 +1,185 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): M. Neuendorf, N. Rettelbach, M. Multrus + + Description: PS Parameter extraction, encoding + +*******************************************************************************/ + +/*! + \file + \brief PS parameter extraction, encoding functions $Revision: 92790 $ +*/ + +#ifndef PS_ENCODE_H +#define PS_ENCODE_H + +#include "ps_const.h" +#include "ps_bitenc.h" + +#define IID_SCALE_FT (64.f) /* maxVal in Quant tab is +/- 50 */ +#define IID_SCALE 6 /* maxVal in Quant tab is +/- 50 */ +#define IID_MAXVAL (1 << IID_SCALE) + +#define PS_QUANT_SCALE_FT \ + (64.f) /* error smaller (64-25)/64 * 20 bands * 4 env -> QuantScale 64 */ +#define PS_QUANT_SCALE \ + 6 /* error smaller (64-25)/64 * 20 bands * 4 env -> QuantScale 6 bit */ + +#define QMF_GROUPS_LO_RES 12 +#define SUBQMF_GROUPS_LO_RES 10 +#define QMF_GROUPS_HI_RES 18 +#define SUBQMF_GROUPS_HI_RES 30 + +typedef struct T_PS_DATA { + INT iidEnable; + INT iidEnableLast; + INT iidQuantMode; + INT iidQuantModeLast; + INT iidDiffMode[PS_MAX_ENVELOPES]; + INT iidIdx[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iidIdxLast[PS_MAX_BANDS]; + + INT iccEnable; + INT iccEnableLast; + INT iccQuantMode; + INT iccQuantModeLast; + INT iccDiffMode[PS_MAX_ENVELOPES]; + INT iccIdx[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iccIdxLast[PS_MAX_BANDS]; + + INT nEnvelopesLast; + + INT headerCnt; + INT iidTimeCnt; + INT iccTimeCnt; + INT noEnvCnt; + +} PS_DATA, *HANDLE_PS_DATA; + +typedef struct T_PS_ENCODE { + PS_DATA psData; + + PS_BANDS psEncMode; + INT nQmfIidGroups; + INT nSubQmfIidGroups; + INT iidGroupBorders[QMF_GROUPS_HI_RES + SUBQMF_GROUPS_HI_RES + 1]; + INT subband2parameterIndex[QMF_GROUPS_HI_RES + SUBQMF_GROUPS_HI_RES]; + UCHAR iidGroupWidthLd[QMF_GROUPS_HI_RES + SUBQMF_GROUPS_HI_RES]; + FIXP_DBL iidQuantErrorThreshold; + + UCHAR psBandNrgScale[PS_MAX_BANDS]; + +} PS_ENCODE; + +typedef struct T_PS_ENCODE *HANDLE_PS_ENCODE; + +FDK_PSENC_ERROR FDKsbrEnc_CreatePSEncode(HANDLE_PS_ENCODE *phPsEncode); + +FDK_PSENC_ERROR FDKsbrEnc_InitPSEncode(HANDLE_PS_ENCODE hPsEncode, + const PS_BANDS psEncMode, + const FIXP_DBL iidQuantErrorThreshold); + +FDK_PSENC_ERROR FDKsbrEnc_DestroyPSEncode(HANDLE_PS_ENCODE *phPsEncode); + +FDK_PSENC_ERROR FDKsbrEnc_PSEncode( + HANDLE_PS_ENCODE hPsEncode, HANDLE_PS_OUT hPsOut, UCHAR *dynBandScale, + UINT maxEnvelopes, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + const INT frameSize, const INT sendHeader); + +#endif diff --git a/fdk-aac/libSBRenc/src/ps_main.cpp b/fdk-aac/libSBRenc/src/ps_main.cpp new file mode 100644 index 0000000..4d7a7a5 --- /dev/null +++ b/fdk-aac/libSBRenc/src/ps_main.cpp @@ -0,0 +1,606 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): M. Multrus + + Description: PS Wrapper, Downmix + +*******************************************************************************/ + +#include "ps_main.h" + +/* Includes ******************************************************************/ +#include "ps_bitenc.h" +#include "sbrenc_ram.h" + +/*--------------- function declarations --------------------*/ +static void psFindBestScaling( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + UCHAR *dynBandScale, FIXP_DBL *maxBandValue, SCHAR *dmxScale); + +/*------------- function definitions ----------------*/ +FDK_PSENC_ERROR PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo) { + FDK_PSENC_ERROR error = PSENC_OK; + HANDLE_PARAMETRIC_STEREO hParametricStereo = NULL; + + if (phParametricStereo == NULL) { + error = PSENC_INVALID_HANDLE; + } else { + int i; + + if (NULL == (hParametricStereo = GetRam_ParamStereo())) { + error = PSENC_MEMORY_ERROR; + goto bail; + } + FDKmemclear(hParametricStereo, sizeof(PARAMETRIC_STEREO)); + + if (PSENC_OK != + (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) { + error = PSENC_MEMORY_ERROR; + goto bail; + } + + for (i = 0; i < MAX_PS_CHANNELS; i++) { + if (FDKhybridAnalysisOpen( + &hParametricStereo->fdkHybAnaFilter[i], + hParametricStereo->__staticHybAnaStatesLF[i], + sizeof(hParametricStereo->__staticHybAnaStatesLF[i]), + hParametricStereo->__staticHybAnaStatesHF[i], + sizeof(hParametricStereo->__staticHybAnaStatesHF[i])) != 0) { + error = PSENC_MEMORY_ERROR; + goto bail; + } + } + } + +bail: + if (phParametricStereo != NULL) { + *phParametricStereo = hParametricStereo; /* return allocated handle */ + } + + if (error != PSENC_OK) { + PSEnc_Destroy(phParametricStereo); + } + return error; +} + +FDK_PSENC_ERROR PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo, + const HANDLE_PSENC_CONFIG hPsEncConfig, + INT noQmfSlots, INT noQmfBands, UCHAR *dynamic_RAM) { + FDK_PSENC_ERROR error = PSENC_OK; + + if ((NULL == hParametricStereo) || (NULL == hPsEncConfig)) { + error = PSENC_INVALID_HANDLE; + } else { + int ch, i; + + hParametricStereo->initPS = 1; + hParametricStereo->noQmfSlots = noQmfSlots; + hParametricStereo->noQmfBands = noQmfBands; + + /* clear delay lines */ + FDKmemclear(hParametricStereo->qmfDelayLines, + sizeof(hParametricStereo->qmfDelayLines)); + + hParametricStereo->qmfDelayScale = FRACT_BITS - 1; + + /* create configuration for hybrid filter bank */ + for (ch = 0; ch < MAX_PS_CHANNELS; ch++) { + FDKhybridAnalysisInit(&hParametricStereo->fdkHybAnaFilter[ch], + THREE_TO_TEN, 64, 64, 1); + } /* ch */ + + FDKhybridSynthesisInit(&hParametricStereo->fdkHybSynFilter, THREE_TO_TEN, + 64, 64); + + /* determine average delay */ + hParametricStereo->psDelay = + (HYBRID_FILTER_DELAY * hParametricStereo->noQmfBands); + + if ((hPsEncConfig->maxEnvelopes < PSENC_NENV_1) || + (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX)) { + hPsEncConfig->maxEnvelopes = PSENC_NENV_DEFAULT; + } + hParametricStereo->maxEnvelopes = hPsEncConfig->maxEnvelopes; + + if (PSENC_OK != + (error = FDKsbrEnc_InitPSEncode( + hParametricStereo->hPsEncode, (PS_BANDS)hPsEncConfig->nStereoBands, + hPsEncConfig->iidQuantErrorThreshold))) { + goto bail; + } + + for (ch = 0; ch < MAX_PS_CHANNELS; ch++) { + FIXP_DBL *pDynReal = GetRam_Sbr_envRBuffer(ch, dynamic_RAM); + FIXP_DBL *pDynImag = GetRam_Sbr_envIBuffer(ch, dynamic_RAM); + + for (i = 0; i < HYBRID_FRAMESIZE; i++) { + hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][ch][0] = + &pDynReal[i * MAX_HYBRID_BANDS]; + hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][ch][1] = + &pDynImag[i * MAX_HYBRID_BANDS]; + ; + } + + for (i = 0; i < HYBRID_READ_OFFSET; i++) { + hParametricStereo->pHybridData[i][ch][0] = + hParametricStereo->__staticHybridData[i][ch][0]; + hParametricStereo->pHybridData[i][ch][1] = + hParametricStereo->__staticHybridData[i][ch][1]; + } + } /* ch */ + + /* clear static hybrid buffer */ + FDKmemclear(hParametricStereo->__staticHybridData, + sizeof(hParametricStereo->__staticHybridData)); + + /* clear bs buffer */ + FDKmemclear(hParametricStereo->psOut, sizeof(hParametricStereo->psOut)); + + hParametricStereo->psOut[0].enablePSHeader = + 1; /* write ps header in first frame */ + + /* clear scaling buffer */ + FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR) * PS_MAX_BANDS); + FDKmemclear(hParametricStereo->maxBandValue, + sizeof(FIXP_DBL) * PS_MAX_BANDS); + + } /* valid handle */ +bail: + return error; +} + +FDK_PSENC_ERROR PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *phParametricStereo) { + FDK_PSENC_ERROR error = PSENC_OK; + + if (NULL != phParametricStereo) { + HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo; + if (hParametricStereo != NULL) { + FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode); + FreeRam_ParamStereo(phParametricStereo); + } + } + + return error; +} + +static FDK_PSENC_ERROR ExtractPSParameters( + HANDLE_PARAMETRIC_STEREO hParametricStereo, const int sendHeader, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2]) { + FDK_PSENC_ERROR error = PSENC_OK; + + if (hParametricStereo == NULL) { + error = PSENC_INVALID_HANDLE; + } else { + /* call ps encode function */ + if (hParametricStereo->initPS) { + hParametricStereo->psOut[1] = hParametricStereo->psOut[0]; + } + hParametricStereo->psOut[0] = hParametricStereo->psOut[1]; + + if (PSENC_OK != + (error = FDKsbrEnc_PSEncode( + hParametricStereo->hPsEncode, &hParametricStereo->psOut[1], + hParametricStereo->dynBandScale, hParametricStereo->maxEnvelopes, + hybridData, hParametricStereo->noQmfSlots, sendHeader))) { + goto bail; + } + + if (hParametricStereo->initPS) { + hParametricStereo->psOut[0] = hParametricStereo->psOut[1]; + hParametricStereo->initPS = 0; + } + } +bail: + return error; +} + +static FDK_PSENC_ERROR DownmixPSQmfData( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, FIXP_DBL **RESTRICT mixRealQmfData, + FIXP_DBL **RESTRICT mixImagQmfData, INT_PCM *downsampledOutSignal, + const UINT downsampledOutSignalBufSize, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + const INT noQmfSlots, const INT psQmfScale[MAX_PS_CHANNELS], + SCHAR *qmfScale) { + FDK_PSENC_ERROR error = PSENC_OK; + + if (hParametricStereo == NULL) { + error = PSENC_INVALID_HANDLE; + } else { + int n, k; + C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 2 * 64) + + /* define scalings */ + int dynQmfScale = fixMax( + 0, hParametricStereo->dmxScale - + 1); /* scale one bit more for addition of left and right */ + int downmixScale = psQmfScale[0] - dynQmfScale; + const FIXP_DBL maxStereoScaleFactor = MAXVAL_DBL; /* 2.f/2.f */ + + for (n = 0; n < noQmfSlots; n++) { + FIXP_DBL tmpHybrid[2][MAX_HYBRID_BANDS]; + + for (k = 0; k < 71; k++) { + int dynScale, sc; /* scaling */ + FIXP_DBL tmpLeftReal, tmpRightReal, tmpLeftImag, tmpRightImag; + FIXP_DBL tmpScaleFactor, stereoScaleFactor; + + tmpLeftReal = hybridData[n][0][0][k]; + tmpLeftImag = hybridData[n][0][1][k]; + tmpRightReal = hybridData[n][1][0][k]; + tmpRightImag = hybridData[n][1][1][k]; + + sc = fixMax( + 0, CntLeadingZeros(fixMax( + fixMax(fixp_abs(tmpLeftReal), fixp_abs(tmpLeftImag)), + fixMax(fixp_abs(tmpRightReal), fixp_abs(tmpRightImag)))) - + 2); + + tmpLeftReal <<= sc; + tmpLeftImag <<= sc; + tmpRightReal <<= sc; + tmpRightImag <<= sc; + dynScale = fixMin(sc - dynQmfScale, DFRACT_BITS - 1); + + /* calc stereo scale factor to avoid loss of energy in bands */ + /* stereo scale factor = min(2.0f, sqrt( (abs(l(k, n)^2 + abs(r(k, n)^2 + * )))/(0.5f*abs(l(k, n) + r(k, n))) )) */ + stereoScaleFactor = fPow2Div2(tmpLeftReal) + fPow2Div2(tmpLeftImag) + + fPow2Div2(tmpRightReal) + fPow2Div2(tmpRightImag); + + /* might be that tmpScaleFactor becomes negative, so fabs(.) */ + tmpScaleFactor = + fixp_abs(stereoScaleFactor + fMult(tmpLeftReal, tmpRightReal) + + fMult(tmpLeftImag, tmpRightImag)); + + /* min(2.0f, sqrt(stereoScaleFactor/(0.5f*tmpScaleFactor))) */ + if ((stereoScaleFactor >> 1) < + fMult(maxStereoScaleFactor, tmpScaleFactor)) { + int sc_num = CountLeadingBits(stereoScaleFactor); + int sc_denum = CountLeadingBits(tmpScaleFactor); + sc = -(sc_num - sc_denum); + + tmpScaleFactor = schur_div((stereoScaleFactor << (sc_num)) >> 1, + tmpScaleFactor << sc_denum, 16); + + /* prevent odd scaling for next sqrt calculation */ + if (sc & 0x1) { + sc++; + tmpScaleFactor >>= 1; + } + stereoScaleFactor = sqrtFixp(tmpScaleFactor); + stereoScaleFactor <<= (sc >> 1); + } else { + stereoScaleFactor = maxStereoScaleFactor; + } + + /* write data to hybrid output */ + tmpHybrid[0][k] = fMultDiv2(stereoScaleFactor, + (FIXP_DBL)(tmpLeftReal + tmpRightReal)) >> + dynScale; + tmpHybrid[1][k] = fMultDiv2(stereoScaleFactor, + (FIXP_DBL)(tmpLeftImag + tmpRightImag)) >> + dynScale; + + } /* hybrid bands - k */ + + FDKhybridSynthesisApply(&hParametricStereo->fdkHybSynFilter, tmpHybrid[0], + tmpHybrid[1], mixRealQmfData[n], + mixImagQmfData[n]); + + qmfSynthesisFilteringSlot( + sbrSynthQmf, mixRealQmfData[n], mixImagQmfData[n], downmixScale - 7, + downmixScale - 7, + downsampledOutSignal + (n * sbrSynthQmf->no_channels), 1, + pWorkBuffer); + + } /* slots */ + + *qmfScale = -downmixScale + 7; + + C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2 * 64) + + { + const INT noQmfSlots2 = hParametricStereo->noQmfSlots >> 1; + const int noQmfBands = hParametricStereo->noQmfBands; + + INT scale, i, j, slotOffset; + + FIXP_DBL tmp[2][64]; + + for (i = 0; i < noQmfSlots2; i++) { + FDKmemcpy(tmp[0], hParametricStereo->qmfDelayLines[0][i], + noQmfBands * sizeof(FIXP_DBL)); + FDKmemcpy(tmp[1], hParametricStereo->qmfDelayLines[1][i], + noQmfBands * sizeof(FIXP_DBL)); + + FDKmemcpy(hParametricStereo->qmfDelayLines[0][i], + mixRealQmfData[i + noQmfSlots2], + noQmfBands * sizeof(FIXP_DBL)); + FDKmemcpy(hParametricStereo->qmfDelayLines[1][i], + mixImagQmfData[i + noQmfSlots2], + noQmfBands * sizeof(FIXP_DBL)); + + FDKmemcpy(mixRealQmfData[i + noQmfSlots2], mixRealQmfData[i], + noQmfBands * sizeof(FIXP_DBL)); + FDKmemcpy(mixImagQmfData[i + noQmfSlots2], mixImagQmfData[i], + noQmfBands * sizeof(FIXP_DBL)); + + FDKmemcpy(mixRealQmfData[i], tmp[0], noQmfBands * sizeof(FIXP_DBL)); + FDKmemcpy(mixImagQmfData[i], tmp[1], noQmfBands * sizeof(FIXP_DBL)); + } + + if (hParametricStereo->qmfDelayScale > *qmfScale) { + scale = hParametricStereo->qmfDelayScale - *qmfScale; + slotOffset = 0; + } else { + scale = *qmfScale - hParametricStereo->qmfDelayScale; + slotOffset = noQmfSlots2; + } + + for (i = 0; i < noQmfSlots2; i++) { + for (j = 0; j < noQmfBands; j++) { + mixRealQmfData[i + slotOffset][j] >>= scale; + mixImagQmfData[i + slotOffset][j] >>= scale; + } + } + + scale = *qmfScale; + *qmfScale = fMin(*qmfScale, hParametricStereo->qmfDelayScale); + hParametricStereo->qmfDelayScale = scale; + } + + } /* valid handle */ + + return error; +} + +INT FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitstream) { + return ( + (hParametricStereo != NULL) + ? FDKsbrEnc_WritePSBitstream(&hParametricStereo->psOut[0], hBitstream) + : 0); +} + +FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing( + HANDLE_PARAMETRIC_STEREO hParametricStereo, INT_PCM *samples[2], + UINT samplesBufSize, QMF_FILTER_BANK **hQmfAnalysis, + FIXP_DBL **RESTRICT downmixedRealQmfData, + FIXP_DBL **RESTRICT downmixedImagQmfData, INT_PCM *downsampledOutSignal, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, SCHAR *qmfScale, const int sendHeader) { + FDK_PSENC_ERROR error = PSENC_OK; + INT psQmfScale[MAX_PS_CHANNELS] = {0}; + int psCh, i; + C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 4 * 64) + + for (psCh = 0; psCh < MAX_PS_CHANNELS; psCh++) { + for (i = 0; i < hQmfAnalysis[psCh]->no_col; i++) { + qmfAnalysisFilteringSlot( + hQmfAnalysis[psCh], &pWorkBuffer[2 * 64], /* qmfReal[64] */ + &pWorkBuffer[3 * 64], /* qmfImag[64] */ + samples[psCh] + i * hQmfAnalysis[psCh]->no_channels, 1, + &pWorkBuffer[0 * 64] /* qmf workbuffer 2*64 */ + ); + + FDKhybridAnalysisApply( + &hParametricStereo->fdkHybAnaFilter[psCh], + &pWorkBuffer[2 * 64], /* qmfReal[64] */ + &pWorkBuffer[3 * 64], /* qmfImag[64] */ + hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][psCh][0], + hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][psCh][1]); + + } /* no_col loop i */ + + psQmfScale[psCh] = hQmfAnalysis[psCh]->outScalefactor; + + } /* for psCh */ + + C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 4 * 64) + + /* find best scaling in new QMF and Hybrid data */ + psFindBestScaling( + hParametricStereo, &hParametricStereo->pHybridData[HYBRID_READ_OFFSET], + hParametricStereo->dynBandScale, hParametricStereo->maxBandValue, + &hParametricStereo->dmxScale); + + /* extract the ps parameters */ + if (PSENC_OK != + (error = ExtractPSParameters(hParametricStereo, sendHeader, + &hParametricStereo->pHybridData[0]))) { + goto bail; + } + + /* save hybrid date for next frame */ + for (i = 0; i < HYBRID_READ_OFFSET; i++) { + FDKmemcpy( + hParametricStereo->pHybridData[i][0][0], + hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][0][0], + MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* left, real */ + FDKmemcpy( + hParametricStereo->pHybridData[i][0][1], + hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][0][1], + MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* left, imag */ + FDKmemcpy( + hParametricStereo->pHybridData[i][1][0], + hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][1][0], + MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* right, real */ + FDKmemcpy( + hParametricStereo->pHybridData[i][1][1], + hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][1][1], + MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* right, imag */ + } + + /* downmix and hybrid synthesis */ + if (PSENC_OK != + (error = DownmixPSQmfData( + hParametricStereo, sbrSynthQmf, downmixedRealQmfData, + downmixedImagQmfData, downsampledOutSignal, samplesBufSize, + &hParametricStereo->pHybridData[HYBRID_READ_OFFSET], + hParametricStereo->noQmfSlots, psQmfScale, qmfScale))) { + goto bail; + } + +bail: + + return error; +} + +static void psFindBestScaling( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + UCHAR *dynBandScale, FIXP_DBL *maxBandValue, SCHAR *dmxScale) { + HANDLE_PS_ENCODE hPsEncode = hParametricStereo->hPsEncode; + + INT group, bin, col, band; + const INT frameSize = hParametricStereo->noQmfSlots; + const INT psBands = (INT)hPsEncode->psEncMode; + const INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; + + /* group wise scaling */ + FIXP_DBL maxVal[2][PS_MAX_BANDS]; + FIXP_DBL maxValue = FL2FXCONST_DBL(0.f); + + FDKmemclear(maxVal, sizeof(maxVal)); + + /* start with hybrid data */ + for (group = 0; group < nIidGroups; group++) { + /* Translate group to bin */ + bin = hPsEncode->subband2parameterIndex[group]; + + /* Translate from 20 bins to 10 bins */ + if (hPsEncode->psEncMode == PS_BANDS_COARSE) { + bin >>= 1; + } + + /* QMF downmix scaling */ + for (col = 0; col < frameSize; col++) { + int i, section = (col < frameSize - HYBRID_READ_OFFSET) ? 0 : 1; + FIXP_DBL tmp = maxVal[section][bin]; + for (i = hPsEncode->iidGroupBorders[group]; + i < hPsEncode->iidGroupBorders[group + 1]; i++) { + tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][0][0][i])); + tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][0][1][i])); + tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][1][0][i])); + tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][1][1][i])); + } + maxVal[section][bin] = tmp; + } + } /* nIidGroups */ + + /* convert maxSpec to maxScaling, find scaling space */ + for (band = 0; band < psBands; band++) { +#ifndef MULT_16x16 + dynBandScale[band] = + CountLeadingBits(fixMax(maxVal[0][band], maxBandValue[band])); +#else + dynBandScale[band] = fixMax( + 0, CountLeadingBits(fixMax(maxVal[0][band], maxBandValue[band])) - + FRACT_BITS); +#endif + maxValue = fixMax(maxValue, fixMax(maxVal[0][band], maxVal[1][band])); + maxBandValue[band] = fixMax(maxVal[0][band], maxVal[1][band]); + } + + /* calculate maximal scaling for QMF downmix */ +#ifndef MULT_16x16 + *dmxScale = fixMin(DFRACT_BITS, CountLeadingBits(maxValue)); +#else + *dmxScale = fixMax(0, fixMin(FRACT_BITS, CountLeadingBits((maxValue)))); +#endif +} diff --git a/fdk-aac/libSBRenc/src/ps_main.h b/fdk-aac/libSBRenc/src/ps_main.h new file mode 100644 index 0000000..88b2993 --- /dev/null +++ b/fdk-aac/libSBRenc/src/ps_main.h @@ -0,0 +1,270 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): Markus Multrus + + Description: PS Wrapper, Downmix header file + +*******************************************************************************/ + +#ifndef PS_MAIN_H +#define PS_MAIN_H + +/* Includes ******************************************************************/ + +#include "sbr_def.h" +#include "qmf.h" +#include "ps_encode.h" +#include "FDK_bitstream.h" +#include "FDK_hybrid.h" + +/* Data Types ****************************************************************/ +typedef enum { + PSENC_STEREO_BANDS_INVALID = 0, + PSENC_STEREO_BANDS_10 = 10, + PSENC_STEREO_BANDS_20 = 20 + +} PSENC_STEREO_BANDS_CONFIG; + +typedef enum { + PSENC_NENV_1 = 1, + PSENC_NENV_2 = 2, + PSENC_NENV_4 = 4, + PSENC_NENV_DEFAULT = PSENC_NENV_2, + PSENC_NENV_MAX = PSENC_NENV_4 + +} PSENC_NENV_CONFIG; + +typedef struct { + UINT bitrateFrom; /* inclusive */ + UINT bitrateTo; /* exclusive */ + PSENC_STEREO_BANDS_CONFIG nStereoBands; + PSENC_NENV_CONFIG nEnvelopes; + LONG iidQuantErrorThreshold; /* quantization threshold to switch between + coarse and fine iid quantization */ + +} psTuningTable_t; + +/* Function / Class Declarations *********************************************/ + +typedef struct T_PARAMETRIC_STEREO { + HANDLE_PS_ENCODE hPsEncode; + PS_OUT psOut[2]; + + FIXP_DBL __staticHybridData[HYBRID_READ_OFFSET][MAX_PS_CHANNELS][2] + [MAX_HYBRID_BANDS]; + FIXP_DBL + *pHybridData[HYBRID_READ_OFFSET + HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2]; + + FIXP_DBL qmfDelayLines[2][32 >> 1][64]; + int qmfDelayScale; + + INT psDelay; + UINT maxEnvelopes; + UCHAR dynBandScale[PS_MAX_BANDS]; + FIXP_DBL maxBandValue[PS_MAX_BANDS]; + SCHAR dmxScale; + INT initPS; + INT noQmfSlots; + INT noQmfBands; + + FIXP_DBL __staticHybAnaStatesLF[MAX_PS_CHANNELS][2 * HYBRID_FILTER_LENGTH * + HYBRID_MAX_QMF_BANDS]; + FIXP_DBL __staticHybAnaStatesHF[MAX_PS_CHANNELS][2 * HYBRID_FILTER_DELAY * + (64 - HYBRID_MAX_QMF_BANDS)]; + FDK_ANA_HYB_FILTER fdkHybAnaFilter[MAX_PS_CHANNELS]; + FDK_SYN_HYB_FILTER fdkHybSynFilter; + +} PARAMETRIC_STEREO; + +typedef struct T_PSENC_CONFIG { + INT frameSize; + INT qmfFilterMode; + INT sbrPsDelay; + PSENC_STEREO_BANDS_CONFIG nStereoBands; + PSENC_NENV_CONFIG maxEnvelopes; + FIXP_DBL iidQuantErrorThreshold; + +} PSENC_CONFIG, *HANDLE_PSENC_CONFIG; + +typedef struct T_PARAMETRIC_STEREO *HANDLE_PARAMETRIC_STEREO; + +/** + * \brief Create a parametric stereo encoder instance. + * + * \param phParametricStereo A pointer to a parametric stereo handle to be + * allocated. Initialized on return. + * + * \return + * - PSENC_OK, on succes. + * - PSENC_INVALID_HANDLE, PSENC_MEMORY_ERROR, on failure. + */ +FDK_PSENC_ERROR PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo); + +/** + * \brief Initialize a parametric stereo encoder instance. + * + * \param hParametricStereo Meta Data handle. + * \param hPsEncConfig Filled parametric stereo configuration + * structure. + * \param noQmfSlots Number of slots within one audio frame. + * \param noQmfBands Number of QMF bands. + * \param dynamic_RAM Pointer to preallocated workbuffer. + * + * \return + * - PSENC_OK, on succes. + * - PSENC_INVALID_HANDLE, PSENC_INIT_ERROR, on failure. + */ +FDK_PSENC_ERROR PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo, + const HANDLE_PSENC_CONFIG hPsEncConfig, + INT noQmfSlots, INT noQmfBands, UCHAR *dynamic_RAM); + +/** + * \brief Destroy parametric stereo encoder instance. + * + * Deallocate instance and free whole memory. + * + * \param phParametricStereo Pointer to the parametric stereo handle to be + * deallocated. + * + * \return + * - PSENC_OK, on succes. + * - PSENC_INVALID_HANDLE, on failure. + */ +FDK_PSENC_ERROR PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *phParametricStereo); + +/** + * \brief Apply parametric stereo processing. + * + * \param hParametricStereo Meta Data handle. + * \param samples Pointer to 2 channel audio input signal. + * \param timeInStride, Stride factor of input buffer. + * \param hQmfAnalysis, Pointer to QMF analysis filterbanks. + * \param downmixedRealQmfData Pointer to real QMF buffer to be written to. + * \param downmixedImagQmfData Pointer to imag QMF buffer to be written to. + * \param downsampledOutSignal Pointer to buffer where to write downmixed + * timesignal. + * \param sbrSynthQmf Pointer to QMF synthesis filterbank. + * \param qmfScale Return scaling factor of the qmf data. + * \param sendHeader Signal whether to write header data. + * + * \return + * - PSENC_OK, on succes. + * - PSENC_INVALID_HANDLE, PSENC_ENCODE_ERROR, on failure. + */ +FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing( + HANDLE_PARAMETRIC_STEREO hParametricStereo, INT_PCM *samples[2], + UINT timeInStride, QMF_FILTER_BANK **hQmfAnalysis, + FIXP_DBL **RESTRICT downmixedRealQmfData, + FIXP_DBL **RESTRICT downmixedImagQmfData, INT_PCM *downsampledOutSignal, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, SCHAR *qmfScale, const int sendHeader); + +/** + * \brief Write parametric stereo bitstream. + * + * Write ps_data() element to bitstream and return number of written bits. + * Returns number of written bits only, if hBitstream == NULL. + * + * \param hParametricStereo Meta Data handle. + * \param hBitstream Bitstream buffer handle. + * + * \return + * - number of written bits. + */ +INT FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitstream); + +#endif /* PS_MAIN_H */ diff --git a/fdk-aac/libSBRenc/src/resampler.cpp b/fdk-aac/libSBRenc/src/resampler.cpp new file mode 100644 index 0000000..b1781a7 --- /dev/null +++ b/fdk-aac/libSBRenc/src/resampler.cpp @@ -0,0 +1,444 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief FDK resampler tool box:$Revision: 91655 $ + \author M. Werner +*/ + +#include "resampler.h" + +#include "genericStds.h" + +/**************************************************************************/ +/* BIQUAD Filter Specifications */ +/**************************************************************************/ + +#define B1 0 +#define B2 1 +#define A1 2 +#define A2 3 + +#define BQC(x) FL2FXCONST_SGL(x / 2) + +struct FILTER_PARAM { + const FIXP_SGL *coeffa; /*! SOS matrix One row/section. Scaled using BQC(). + Order of coefficients: B1,B2,A1,A2. B0=A0=1.0 */ + FIXP_DBL g; /*! overall gain */ + int Wc; /*! normalized passband bandwidth at input samplerate * 1000 */ + int noCoeffs; /*! number of filter coeffs */ + int delay; /*! delay in samples at input samplerate */ +}; + +#define BIQUAD_COEFSTEP 4 + +/** + *\brief Low Pass + Wc = 0,5, order 30, Stop Band -96dB. Wc criteria is "almost 0dB passband", not + the usual -3db gain point. [b,a]=cheby2(30,96,0.505) [sos,g]=tf2sos(b,a) + bandwidth 0.48 + */ +static const FIXP_SGL sos48[] = { + BQC(1.98941075681938), BQC(0.999999996890811), + BQC(0.863264527201963), BQC(0.189553799960663), + BQC(1.90733804822445), BQC(1.00000001736189), + BQC(0.836321575841691), BQC(0.203505809266564), + BQC(1.75616665495325), BQC(0.999999946079721), + BQC(0.784699225121588), BQC(0.230471265506986), + BQC(1.55727745512726), BQC(1.00000011737815), + BQC(0.712515423588351), BQC(0.268752723900498), + BQC(1.33407591943643), BQC(0.999999795953228), + BQC(0.625059117330989), BQC(0.316194685288965), + BQC(1.10689898412458), BQC(1.00000035057114), + BQC(0.52803514366398), BQC(0.370517843224669), + BQC(0.89060371078454), BQC(0.999999343962822), + BQC(0.426920462165257), BQC(0.429608200207746), + BQC(0.694438261209433), BQC(1.0000008629792), + BQC(0.326530699561716), BQC(0.491714450654174), + BQC(0.523237800935322), BQC(1.00000101349782), + BQC(0.230829556274851), BQC(0.555559034843281), + BQC(0.378631165929563), BQC(0.99998986482665), + BQC(0.142906422036095), BQC(0.620338874442411), + BQC(0.260786911308437), BQC(1.00003261460178), + BQC(0.0651008576256505), BQC(0.685759923926262), + BQC(0.168409429188098), BQC(0.999933049695828), + BQC(-0.000790067789975562), BQC(0.751905896602325), + BQC(0.100724533818628), BQC(1.00009472669872), + BQC(-0.0533772830257041), BQC(0.81930744384525), + BQC(0.0561434357867363), BQC(0.999911636304276), + BQC(-0.0913550299236405), BQC(0.88883625875915), + BQC(0.0341680678662057), BQC(1.00003667508676), + BQC(-0.113405185536697), BQC(0.961756638268446)}; + +static const FIXP_DBL g48 = + FL2FXCONST_DBL(0.002712866530047) - (FIXP_DBL)0x8000; + +static const struct FILTER_PARAM param_set48 = { + sos48, g48, 480, 15, 4 /* LF 2 */ +}; + +/** + *\brief Low Pass + Wc = 0,5, order 24, Stop Band -96dB. Wc criteria is "almost 0dB passband", not + the usual -3db gain point. [b,a]=cheby2(24,96,0.5) [sos,g]=tf2sos(b,a) + bandwidth 0.45 + */ +static const FIXP_SGL sos45[] = { + BQC(1.982962601444), BQC(1.00000000007504), BQC(0.646113303737836), + BQC(0.10851149979981), BQC(1.85334094281111), BQC(0.999999999677192), + BQC(0.612073220102006), BQC(0.130022141698044), BQC(1.62541051415425), + BQC(1.00000000080398), BQC(0.547879702855959), BQC(0.171165825133192), + BQC(1.34554656923247), BQC(0.9999999980169), BQC(0.460373914508491), + BQC(0.228677463376354), BQC(1.05656568503116), BQC(1.00000000569363), + BQC(0.357891894038287), BQC(0.298676843912185), BQC(0.787967587877312), + BQC(0.999999984415017), BQC(0.248826893211877), BQC(0.377441803512978), + BQC(0.555480971120497), BQC(1.00000003583307), BQC(0.140614263345315), + BQC(0.461979302213679), BQC(0.364986207070964), BQC(0.999999932084303), + BQC(0.0392669446074516), BQC(0.55033451180825), BQC(0.216827267631558), + BQC(1.00000010534682), BQC(-0.0506232228865103), BQC(0.641691581560946), + BQC(0.108951672277119), BQC(0.999999871167516), BQC(-0.125584840183225), + BQC(0.736367748771803), BQC(0.0387988607229035), BQC(1.00000011205574), + BQC(-0.182814849097974), BQC(0.835802108714964), BQC(0.0042866175809225), + BQC(0.999999954830813), BQC(-0.21965740617151), BQC(0.942623047782363)}; + +static const FIXP_DBL g45 = + FL2FXCONST_DBL(0.00242743980909524) - (FIXP_DBL)0x8000; + +static const struct FILTER_PARAM param_set45 = { + sos45, g45, 450, 12, 4 /* LF 2 */ +}; + +/* + Created by Octave 2.1.73, Mon Oct 13 17:31:32 2008 CEST + Wc = 0,5, order 16, Stop Band -96dB damping. + [b,a]=cheby2(16,96,0.5) + [sos,g]=tf2sos(b,a) + bandwidth = 0.41 + */ + +static const FIXP_SGL sos41[] = { + BQC(1.96193625292), BQC(0.999999999999964), BQC(0.169266178786789), + BQC(0.0128823300475907), BQC(1.68913437662092), BQC(1.00000000000053), + BQC(0.124751503206552), BQC(0.0537472273950989), BQC(1.27274692366017), + BQC(0.999999999995674), BQC(0.0433108625178357), BQC(0.131015753236317), + BQC(0.85214175088395), BQC(1.00000000001813), BQC(-0.0625658152550408), + BQC(0.237763778993806), BQC(0.503841579939009), BQC(0.999999999953223), + BQC(-0.179176128722865), BQC(0.367475236424474), BQC(0.249990711986162), + BQC(1.00000000007952), BQC(-0.294425165824676), BQC(0.516594857170212), + BQC(0.087971668680286), BQC(0.999999999915528), BQC(-0.398956566777928), + BQC(0.686417767801123), BQC(0.00965373325350294), BQC(1.00000000003744), + BQC(-0.48579173764817), BQC(0.884931534239068)}; + +static const FIXP_DBL g41 = FL2FXCONST_DBL(0.00155956951169248); + +static const struct FILTER_PARAM param_set41 = { + sos41, g41, 410, 8, 5 /* LF 3 */ +}; + +/* + # Created by Octave 2.1.73, Mon Oct 13 17:55:33 2008 CEST + Wc = 0,5, order 12, Stop Band -96dB damping. + [b,a]=cheby2(12,96,0.5); + [sos,g]=tf2sos(b,a) +*/ +static const FIXP_SGL sos35[] = { + BQC(1.93299325235762), BQC(0.999999999999985), BQC(-0.140733187246596), + BQC(0.0124139497836062), BQC(1.4890416764109), BQC(1.00000000000011), + BQC(-0.198215402588504), BQC(0.0746730616584138), BQC(0.918450161309795), + BQC(0.999999999999619), BQC(-0.30133912791941), BQC(0.192276468839529), + BQC(0.454877024246818), BQC(1.00000000000086), BQC(-0.432337328809815), + BQC(0.356852933642815), BQC(0.158017147118507), BQC(0.999999999998876), + BQC(-0.574817494249777), BQC(0.566380436970833), BQC(0.0171834649478749), + BQC(1.00000000000055), BQC(-0.718581178041165), BQC(0.83367484487889)}; + +static const FIXP_DBL g35 = FL2FXCONST_DBL(0.00162580994125131); + +static const struct FILTER_PARAM param_set35 = {sos35, g35, 350, 6, 4}; + +/* + # Created by Octave 2.1.73, Mon Oct 13 18:15:38 2008 CEST + Wc = 0,5, order 8, Stop Band -96dB damping. + [b,a]=cheby2(8,96,0.5); + [sos,g]=tf2sos(b,a) +*/ +static const FIXP_SGL sos25[] = { + BQC(1.85334094301225), BQC(1.0), + BQC(-0.702127214212663), BQC(0.132452403998767), + BQC(1.056565682167), BQC(0.999999999999997), + BQC(-0.789503667880785), BQC(0.236328693569128), + BQC(0.364986307455489), BQC(0.999999999999996), + BQC(-0.955191189843375), BQC(0.442966457936379), + BQC(0.0387985751642125), BQC(1.0), + BQC(-1.19817786088084), BQC(0.770493895456328)}; + +static const FIXP_DBL g25 = FL2FXCONST_DBL(0.000945182835294559); + +static const struct FILTER_PARAM param_set25 = {sos25, g25, 250, 4, 5}; + +/* Must be sorted in descending order */ +static const struct FILTER_PARAM *const filter_paramSet[] = { + ¶m_set48, ¶m_set45, ¶m_set41, ¶m_set35, ¶m_set25}; + +/**************************************************************************/ +/* Resampler Functions */ +/**************************************************************************/ + +/*! + \brief Reset downsampler instance and clear delay lines + + \return success of operation +*/ + +INT FDKaacEnc_InitDownsampler( + DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + int Wc, /*!< normalized cutoff freq * 1000* */ + int ratio) /*!< downsampler ratio */ + +{ + UINT i; + const struct FILTER_PARAM *currentSet = NULL; + + FDKmemclear(DownSampler->downFilter.states, + sizeof(DownSampler->downFilter.states)); + DownSampler->downFilter.ptr = 0; + + /* + find applicable parameter set + */ + currentSet = filter_paramSet[0]; + for (i = 1; i < sizeof(filter_paramSet) / sizeof(struct FILTER_PARAM *); + i++) { + if (filter_paramSet[i]->Wc <= Wc) { + break; + } + currentSet = filter_paramSet[i]; + } + + DownSampler->downFilter.coeffa = currentSet->coeffa; + + DownSampler->downFilter.gain = currentSet->g; + FDK_ASSERT(currentSet->noCoeffs <= MAXNR_SECTIONS * 2); + + DownSampler->downFilter.noCoeffs = currentSet->noCoeffs; + DownSampler->delay = currentSet->delay; + DownSampler->downFilter.Wc = currentSet->Wc; + + DownSampler->ratio = ratio; + DownSampler->pending = ratio - 1; + return (1); +} + +/*! + \brief faster simple folding operation + Filter: + H(z) = A(z)/B(z) + with + A(z) = a[0]*z^0 + a[1]*z^1 + a[2]*z^2 ... a[n]*z^n + + \return filtered value +*/ + +static inline INT_PCM AdvanceFilter( + LP_FILTER *downFilter, /*!< pointer to iir filter instance */ + INT_PCM *pInput, /*!< input of filter */ + int downRatio) { + INT_PCM output; + int i, n; + +#define BIQUAD_SCALE 12 + + FIXP_DBL y = FL2FXCONST_DBL(0.0f); + FIXP_DBL input; + + for (n = 0; n < downRatio; n++) { + FIXP_BQS(*states)[2] = downFilter->states; + const FIXP_SGL *coeff = downFilter->coeffa; + int s1, s2; + + s1 = downFilter->ptr; + s2 = s1 ^ 1; + +#if (SAMPLE_BITS == 16) + input = ((FIXP_DBL)pInput[n]) << (DFRACT_BITS - SAMPLE_BITS - BIQUAD_SCALE); +#elif (SAMPLE_BITS == 32) + input = pInput[n] >> BIQUAD_SCALE; +#else +#error NOT IMPLEMENTED +#endif + + FIXP_BQS state1, state2, state1b, state2b; + + state1 = states[0][s1]; + state2 = states[0][s2]; + + /* Loop over sections */ + for (i = 0; i < downFilter->noCoeffs; i++) { + FIXP_DBL state0; + + /* Load merged states (from next section) */ + state1b = states[i + 1][s1]; + state2b = states[i + 1][s2]; + + state0 = input + fMult(state1, coeff[B1]) + fMult(state2, coeff[B2]); + y = state0 - fMult(state1b, coeff[A1]) - fMult(state2b, coeff[A2]); + + /* Store new feed forward merge state */ + states[i + 1][s2] = y << 1; + /* Store new feed backward state */ + states[i][s2] = input << 1; + + /* Feedback output to next section. */ + input = y; + + /* Transfer merged states */ + state1 = state1b; + state2 = state2b; + + /* Step to next coef set */ + coeff += BIQUAD_COEFSTEP; + } + downFilter->ptr ^= 1; + } + /* Apply global gain */ + y = fMult(y, downFilter->gain); + + /* Apply final gain/scaling to output */ +#if (SAMPLE_BITS == 16) + output = (INT_PCM)SATURATE_RIGHT_SHIFT( + y + (FIXP_DBL)(1 << (DFRACT_BITS - SAMPLE_BITS - BIQUAD_SCALE - 1)), + DFRACT_BITS - SAMPLE_BITS - BIQUAD_SCALE, SAMPLE_BITS); + // output = (INT_PCM) SATURATE_RIGHT_SHIFT(y, + // DFRACT_BITS-SAMPLE_BITS-BIQUAD_SCALE, SAMPLE_BITS); +#else + output = SATURATE_LEFT_SHIFT(y, BIQUAD_SCALE, SAMPLE_BITS); +#endif + + return output; +} + +/*! + \brief FDKaacEnc_Downsample numInSamples of type INT_PCM + Returns number of output samples in numOutSamples + + \return success of operation +*/ + +INT FDKaacEnc_Downsample( + DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + INT_PCM *inSamples, /*!< pointer to input samples */ + INT numInSamples, /*!< number of input samples */ + INT_PCM *outSamples, /*!< pointer to output samples */ + INT *numOutSamples /*!< pointer tp number of output samples */ +) { + INT i; + *numOutSamples = 0; + + for (i = 0; i < numInSamples; i += DownSampler->ratio) { + *outSamples = AdvanceFilter(&(DownSampler->downFilter), &inSamples[i], + DownSampler->ratio); + outSamples++; + } + *numOutSamples = numInSamples / DownSampler->ratio; + + return 0; +} diff --git a/fdk-aac/libSBRenc/src/resampler.h b/fdk-aac/libSBRenc/src/resampler.h new file mode 100644 index 0000000..7aa1cae --- /dev/null +++ b/fdk-aac/libSBRenc/src/resampler.h @@ -0,0 +1,159 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef RESAMPLER_H +#define RESAMPLER_H +/*! + \file + \brief Fixed Point Resampler Tool Box $Revision: 92790 $ +*/ + +#include "common_fix.h" + +/**************************************************************************/ +/* BIQUAD Filter Structure */ +/**************************************************************************/ + +#define MAXNR_SECTIONS (15) + +typedef FIXP_DBL FIXP_BQS; + +typedef struct { + FIXP_BQS states[MAXNR_SECTIONS + 1][2]; /*! state buffer */ + const FIXP_SGL *coeffa; /*! pointer to filter coeffs */ + FIXP_DBL gain; /*! overall gain factor */ + int Wc; /*! normalized cutoff freq * 1000 */ + int noCoeffs; /*! number of filter coeffs sets */ + int ptr; /*! index to rinbuffers */ +} LP_FILTER; + +/**************************************************************************/ +/* Downsampler Structure */ +/**************************************************************************/ + +typedef struct { + LP_FILTER downFilter; /*! filter instance */ + int ratio; /*! downsampling ration */ + int delay; /*! downsampling delay (source fs) */ + int pending; /*! number of pending output samples */ +} DOWNSAMPLER; + +/** + * \brief Initialized a given downsampler structure. + */ +INT FDKaacEnc_InitDownsampler( + DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + INT Wc, /*!< normalized cutoff freq * 1000 */ + INT ratio); /*!< downsampler ratio */ + +/** + * \brief Downsample a set of audio samples. numInSamples must be at least equal + * to the downsampler ratio. + */ +INT FDKaacEnc_Downsample( + DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + INT_PCM *inSamples, /*!< pointer to input samples */ + INT numInSamples, /*!< number of input samples */ + INT_PCM *outSamples, /*!< pointer to output samples */ + INT *numOutSamples); /*!< pointer tp number of output samples */ + +#endif /* RESAMPLER_H */ diff --git a/fdk-aac/libSBRenc/src/sbr.h b/fdk-aac/libSBRenc/src/sbr.h new file mode 100644 index 0000000..341dcab --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbr.h @@ -0,0 +1,194 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Main SBR structs definitions $Revision: 92790 $ +*/ + +#ifndef SBR_H +#define SBR_H + +#include "fram_gen.h" +#include "bit_sbr.h" +#include "tran_det.h" +#include "code_env.h" +#include "env_est.h" +#include "cmondata.h" + +#include "qmf.h" +#include "resampler.h" + +#include "ton_corr.h" + +/* SBR bitstream delay */ +#define MAX_DELAY_FRAMES 2 + +/* sbr encoder downsampling type */ +typedef enum { SBRENC_DS_NONE, SBRENC_DS_TIME, SBRENC_DS_QMF } SBRENC_DS_TYPE; + +typedef struct SBR_CHANNEL { + struct ENV_CHANNEL hEnvChannel; + // INT_PCM *pDSOutBuffer; /**< Pointer to + // downsampled audio output of SBR encoder */ + DOWNSAMPLER downSampler; + +} SBR_CHANNEL; +typedef SBR_CHANNEL* HANDLE_SBR_CHANNEL; + +typedef struct SBR_ELEMENT { + HANDLE_SBR_CHANNEL sbrChannel[2]; + QMF_FILTER_BANK* hQmfAnalysis[2]; + SBR_CONFIG_DATA sbrConfigData; + SBR_HEADER_DATA sbrHeaderData; + SBR_BITSTREAM_DATA sbrBitstreamData; + COMMON_DATA CmonData; + INT dynXOverFreqDelay[5]; /**< to delay a frame (I don't like it that much + that way - hrc) */ + SBR_ELEMENT_INFO elInfo; + + UCHAR payloadDelayLine[1 + MAX_DELAY_FRAMES][MAX_PAYLOAD_SIZE]; + UINT payloadDelayLineSize[1 + MAX_DELAY_FRAMES]; /* Sizes in bits */ + +} SBR_ELEMENT, *HANDLE_SBR_ELEMENT; + +typedef struct SBR_ENCODER { + HANDLE_SBR_ELEMENT sbrElement[(8)]; + HANDLE_SBR_CHANNEL pSbrChannel[(8)]; + QMF_FILTER_BANK QmfAnalysis[(8)]; + DOWNSAMPLER lfeDownSampler; + int lfeChIdx; /* -1 default for no lfe, else assign channel index. */ + int noElements; /* Number of elements. */ + int nChannels; /* Total channel count across all elements. */ + int frameSize; /* SBR framelength. */ + int bufferOffset; /* Offset for SBR parameter extraction in time domain input + buffer. */ + int downsampledOffset; /* Offset of downsampled/mixed output for core encoder. + */ + int downmixSize; /* Size in samples of downsampled/mixed output for core + encoder. */ + INT downSampleFactor; /* Sampling rate relation between the SBR and the core + encoder. */ + SBRENC_DS_TYPE + downsamplingMethod; /* Method of downsmapling, time-domain, QMF or none. + */ + int nBitstrDelay; /* Amount of SBR frames to be delayed in bitstream domain. + */ + int sbrDecDelay; /* SBR decoder delay in samples */ + INT estimateBitrate; /* Estimate bitrate of SBR encoder. */ + INT inputDataDelay; /* Delay caused by downsampler, in/out buffer at + sbrEncoder_EncodeFrame. */ + + UCHAR* dynamicRam; + UCHAR* pSBRdynamic_RAM; + + HANDLE_PARAMETRIC_STEREO hParametricStereo; + QMF_FILTER_BANK qmfSynthesisPS; + + /* parameters describing allocation volume of present instance */ + INT maxElements; + INT maxChannels; + INT supportPS; + +} SBR_ENCODER; + +#endif /* SBR_H */ diff --git a/fdk-aac/libSBRenc/src/sbr_def.h b/fdk-aac/libSBRenc/src/sbr_def.h new file mode 100644 index 0000000..53eba71 --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbr_def.h @@ -0,0 +1,276 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief SBR main definitions $Revision: 92790 $ +*/ +#ifndef SBR_DEF_H +#define SBR_DEF_H + +#include "common_fix.h" + +#define noError 0 +#define HANDLE_ERROR_INFO INT +#define ERROR(a, b) 1 + +/* #define SBR_ENV_STATISTICS_BITRATE */ +#undef SBR_ENV_STATISTICS_BITRATE + +/* #define SBR_ENV_STATISTICS */ +#undef SBR_ENV_STATISTICS + +/* #define SBR_PAYLOAD_MONITOR */ +#undef SBR_PAYLOAD_MONITOR + +#define SWAP(a, b) tempr = a, a = b, b = tempr +#define TRUE 1 +#define FALSE 0 + +/* Constants */ +#define EPS 1e-12 +#define LOG2 0.69314718056f /* natural logarithm of 2 */ +#define ILOG2 1.442695041f /* 1/LOG2 */ +#define RELAXATION_FLOAT (1e-6f) +#define RELAXATION (FL2FXCONST_DBL(RELAXATION_FLOAT)) +#define RELAXATION_FRACT \ + (FL2FXCONST_DBL(0.524288f)) /* 0.524288f is fractional part of RELAXATION */ +#define RELAXATION_SHIFT (19) +#define RELAXATION_LD64 \ + (FL2FXCONST_DBL(0.31143075889f)) /* (ld64(RELAXATION) \ + */ + +/************ Definitions ***************/ +#define SBR_COMP_MODE_DELTA 0 +#define SBR_COMP_MODE_CTS 1 +#define SBR_MAX_ENERGY_VALUES 5 +#define SBR_GLOBAL_TONALITY_VALUES 2 + +#define MAX_NUM_CHANNELS 2 + +#define MAX_NOISE_ENVELOPES 2 +#define MAX_NUM_NOISE_COEFFS 5 +#define MAX_NUM_NOISE_VALUES (MAX_NUM_NOISE_COEFFS * MAX_NOISE_ENVELOPES) + +#define MAX_NUM_ENVELOPE_VALUES (MAX_ENVELOPES * MAX_FREQ_COEFFS) +#define MAX_ENVELOPES 5 +#define MAX_FREQ_COEFFS 48 + +#define MAX_FREQ_COEFFS_FS44100 35 +#define MAX_FREQ_COEFFS_FS48000 32 + +#define NO_OF_ESTIMATES_LC 4 +#define NO_OF_ESTIMATES_LD 3 +#define MAX_NO_OF_ESTIMATES 4 + +#define NOISE_FLOOR_OFFSET 6 +#define NOISE_FLOOR_OFFSET_64 (FL2FXCONST_DBL(0.09375f)) + +#define LOW_RES 0 +#define HIGH_RES 1 + +#define LO 0 +#define HI 1 + +#define LENGTH_SBR_FRAME_INFO 35 /* 19 */ + +#define SBR_NSFB_LOW_RES 9 /* 8 */ +#define SBR_NSFB_HIGH_RES 18 /* 16 */ + +#define SBR_XPOS_CTRL_DEFAULT 2 + +#define SBR_FREQ_SCALE_DEFAULT 2 +#define SBR_ALTER_SCALE_DEFAULT 1 +#define SBR_NOISE_BANDS_DEFAULT 2 + +#define SBR_LIMITER_BANDS_DEFAULT 2 +#define SBR_LIMITER_GAINS_DEFAULT 2 +#define SBR_LIMITER_GAINS_INFINITE 3 +#define SBR_INTERPOL_FREQ_DEFAULT 1 +#define SBR_SMOOTHING_LENGTH_DEFAULT 0 + +/* sbr_header */ +#define SI_SBR_AMP_RES_BITS 1 +#define SI_SBR_COUPLING_BITS 1 +#define SI_SBR_START_FREQ_BITS 4 +#define SI_SBR_STOP_FREQ_BITS 4 +#define SI_SBR_XOVER_BAND_BITS 3 +#define SI_SBR_RESERVED_BITS 2 +#define SI_SBR_DATA_EXTRA_BITS 1 +#define SI_SBR_HEADER_EXTRA_1_BITS 1 +#define SI_SBR_HEADER_EXTRA_2_BITS 1 + +/* sbr_header extra 1 */ +#define SI_SBR_FREQ_SCALE_BITS 2 +#define SI_SBR_ALTER_SCALE_BITS 1 +#define SI_SBR_NOISE_BANDS_BITS 2 + +/* sbr_header extra 2 */ +#define SI_SBR_LIMITER_BANDS_BITS 2 +#define SI_SBR_LIMITER_GAINS_BITS 2 +#define SI_SBR_INTERPOL_FREQ_BITS 1 +#define SI_SBR_SMOOTHING_LENGTH_BITS 1 + +/* sbr_grid */ +#define SBR_CLA_BITS 2 /*!< size of bs_frame_class */ +#define SBR_CLA_BITS_LD 1 /*!< size of bs_frame_class */ +#define SBR_ENV_BITS 2 /*!< size of bs_num_env_raw */ +#define SBR_ABS_BITS 2 /*!< size of bs_abs_bord_raw for HE-AAC */ +#define SBR_NUM_BITS 2 /*!< size of bs_num_rel */ +#define SBR_REL_BITS 2 /*!< size of bs_rel_bord_raw */ +#define SBR_RES_BITS 1 /*!< size of bs_freq_res_flag */ +#define SBR_DIR_BITS 1 /*!< size of bs_df_flag */ + +/* sbr_data */ +#define SI_SBR_INVF_MODE_BITS 2 + +#define SI_SBR_START_ENV_BITS_AMP_RES_3_0 6 +#define SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_3_0 5 +#define SI_SBR_START_NOISE_BITS_AMP_RES_3_0 5 +#define SI_SBR_START_NOISE_BITS_BALANCE_AMP_RES_3_0 5 + +#define SI_SBR_START_ENV_BITS_AMP_RES_1_5 7 +#define SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_1_5 6 + +#define SI_SBR_EXTENDED_DATA_BITS 1 +#define SI_SBR_EXTENSION_SIZE_BITS 4 +#define SI_SBR_EXTENSION_ESC_COUNT_BITS 8 +#define SI_SBR_EXTENSION_ID_BITS 2 + +#define SBR_EXTENDED_DATA_MAX_CNT (15 + 255) + +#define EXTENSION_ID_PS_CODING 2 + +/* Envelope coding constants */ +#define FREQ 0 +#define TIME 1 + +/* qmf data scaling */ +#define QMF_SCALE_OFFSET 7 + +/* huffman tables */ +#define CODE_BOOK_SCF_LAV00 60 +#define CODE_BOOK_SCF_LAV01 31 +#define CODE_BOOK_SCF_LAV10 60 +#define CODE_BOOK_SCF_LAV11 31 +#define CODE_BOOK_SCF_LAV_BALANCE11 12 +#define CODE_BOOK_SCF_LAV_BALANCE10 24 + +typedef enum { SBR_AMP_RES_1_5 = 0, SBR_AMP_RES_3_0 } AMP_RES; + +typedef enum { + XPOS_MDCT, + XPOS_MDCT_CROSS, + XPOS_LC, + XPOS_RESERVED, + XPOS_SWITCHED /* not a real choice but used here to control behaviour */ +} XPOS_MODE; + +typedef enum { + INVF_OFF = 0, + INVF_LOW_LEVEL, + INVF_MID_LEVEL, + INVF_HIGH_LEVEL, + INVF_SWITCHED /* not a real choice but used here to control behaviour */ +} INVF_MODE; + +#endif diff --git a/fdk-aac/libSBRenc/src/sbr_encoder.cpp b/fdk-aac/libSBRenc/src/sbr_encoder.cpp new file mode 100644 index 0000000..26257a1 --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbr_encoder.cpp @@ -0,0 +1,2577 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): Andreas Ehret, Tobias Chalupka + + Description: SBR encoder top level processing. + +*******************************************************************************/ + +#include "sbr_encoder.h" + +#include "sbrenc_ram.h" +#include "sbrenc_rom.h" +#include "sbrenc_freq_sca.h" +#include "env_bit.h" +#include "cmondata.h" +#include "sbr_misc.h" +#include "sbr.h" +#include "qmf.h" + +#include "ps_main.h" + +#define SBRENCODER_LIB_VL0 4 +#define SBRENCODER_LIB_VL1 0 +#define SBRENCODER_LIB_VL2 0 + +/***************************************************************************/ +/* + * SBR Delay balancing definitions. + */ + +/* + input buffer (1ch) + + |------------ 1537 -------------|-----|---------- 2048 -------------| + (core2sbr delay ) ds (read, core and ds area) +*/ + +#define SFB(dwnsmp) \ + (32 << (dwnsmp - \ + 1)) /* SBR Frequency bands: 64 for dual-rate, 32 for single-rate */ +#define STS(fl) \ + (((fl) == 1024) ? 32 \ + : 30) /* SBR Time Slots: 32 for core frame length 1024, 30 \ + for core frame length 960 */ + +#define DELAY_QMF_ANA(dwnsmp) \ + ((320 << ((dwnsmp)-1)) - (32 << ((dwnsmp)-1))) /* Full bandwidth */ +#define DELAY_HYB_ANA (10 * 64) /* + 0.5 */ /* */ +#define DELAY_HYB_SYN (6 * 64 - 32) /* */ +#define DELAY_QMF_POSTPROC(dwnsmp) \ + (32 * (dwnsmp)) /* QMF postprocessing delay */ +#define DELAY_DEC_QMF(dwnsmp) (6 * SFB(dwnsmp)) /* Decoder QMF overlap */ +#define DELAY_QMF_SYN(dwnsmp) \ + (1 << (dwnsmp - \ + 1)) /* QMF_NO_POLY/2=2.5, rounded down to 2, half for single-rate */ +#define DELAY_QMF_DS (32) /* QMF synthesis for downsampled time signal */ + +/* Delay in QMF paths */ +#define DELAY_SBR(fl, dwnsmp) \ + (DELAY_QMF_ANA(dwnsmp) + (SFB(dwnsmp) * STS(fl) - 1) + DELAY_QMF_SYN(dwnsmp)) +#define DELAY_PS(fl, dwnsmp) \ + (DELAY_QMF_ANA(dwnsmp) + DELAY_HYB_ANA + DELAY_DEC_QMF(dwnsmp) + \ + (SFB(dwnsmp) * STS(fl) - 1) + DELAY_HYB_SYN + DELAY_QMF_SYN(dwnsmp)) +#define DELAY_ELDSBR(fl, dwnsmp) \ + ((((fl) / 2) * (dwnsmp)) - 1 + DELAY_QMF_POSTPROC(dwnsmp)) +#define DELAY_ELDv2SBR(fl, dwnsmp) \ + ((((fl) / 2) * (dwnsmp)) - 1 + 80 * (dwnsmp)) /* 80 is the delay caused \ + by the sum of the CLD \ + analysis and the MPSLD \ + synthesis filterbank */ + +/* Delay in core path (core and downsampler not taken into account) */ +#define DELAY_COREPATH_SBR(fl, dwnsmp) \ + ((DELAY_QMF_ANA(dwnsmp) + DELAY_DEC_QMF(dwnsmp) + DELAY_QMF_SYN(dwnsmp))) +#define DELAY_COREPATH_ELDSBR(fl, dwnsmp) ((DELAY_QMF_POSTPROC(dwnsmp))) +#define DELAY_COREPATH_ELDv2SBR(fl, dwnsmp) (128 * (dwnsmp)) /* 4 slots */ +#define DELAY_COREPATH_PS(fl, dwnsmp) \ + ((DELAY_QMF_ANA(dwnsmp) + DELAY_QMF_DS + \ + /*(DELAY_AAC(fl)*2) + */ DELAY_QMF_ANA(dwnsmp) + DELAY_DEC_QMF(dwnsmp) + \ + DELAY_HYB_SYN + DELAY_QMF_SYN(dwnsmp))) /* 2048 - 463*2 */ + +/* Delay differences between SBR- and downsampled path for SBR and SBR+PS */ +#define DELAY_AAC2SBR(fl, dwnsmp) \ + ((DELAY_COREPATH_SBR(fl, dwnsmp)) - DELAY_SBR((fl), (dwnsmp))) +#define DELAY_ELD2SBR(fl, dwnsmp) \ + ((DELAY_COREPATH_ELDSBR(fl, dwnsmp)) - DELAY_ELDSBR(fl, dwnsmp)) +#define DELAY_AAC2PS(fl, dwnsmp) \ + ((DELAY_COREPATH_PS(fl, dwnsmp)) - DELAY_PS(fl, dwnsmp)) /* 2048 - 463*2 */ + +/* Assumption: The sample delay resulting of of DELAY_AAC2PS is always smaller + * than the sample delay implied by DELAY_AAC2SBR */ +#define MAX_DS_FILTER_DELAY \ + (5) /* the additional max downsampler filter delay (source fs) */ +#define MAX_SAMPLE_DELAY \ + (DELAY_AAC2SBR(1024, 2) + MAX_DS_FILTER_DELAY) /* maximum delay: frame \ + length of 1024 and \ + dual-rate sbr */ + +/***************************************************************************/ + +/*************** Delay parameters for sbrEncoder_Init_delay() **************/ +typedef struct { + int dsDelay; /* the delay of the (time-domain) downsampler itself */ + int delay; /* overall delay / samples */ + int sbrDecDelay; /* SBR decoder's delay */ + int corePathOffset; /* core path offset / samples; added by + sbrEncoder_Init_delay() */ + int sbrPathOffset; /* SBR path offset / samples; added by + sbrEncoder_Init_delay() */ + int bitstrDelay; /* bitstream delay / frames; added by sbrEncoder_Init_delay() + */ + int delayInput2Core; /* delay of the input to the core / samples */ +} DELAY_PARAM; +/***************************************************************************/ + +#define INVALID_TABLE_IDX -1 + +/***************************************************************************/ +/*! + + \brief Selects the SBR tuning settings to use dependent on number of + channels, bitrate, sample rate and core coder + + \return Index to the appropriate table + +****************************************************************************/ +#define DISTANCE_CEIL_VALUE 5000000 +static INT getSbrTuningTableIndex( + UINT bitrate, /*! the total bitrate in bits/sec */ + UINT numChannels, /*! the number of channels for the core coder */ + UINT sampleRate, /*! the sampling rate of the core coder */ + AUDIO_OBJECT_TYPE core, UINT *pBitRateClosest) { + int i, bitRateClosestLowerIndex = -1, bitRateClosestUpperIndex = -1, + found = 0; + UINT bitRateClosestUpper = 0, bitRateClosestLower = DISTANCE_CEIL_VALUE; + +#define isForThisCore(i) \ + ((sbrTuningTable[i].coreCoder == CODEC_AACLD && core == AOT_ER_AAC_ELD) || \ + (sbrTuningTable[i].coreCoder == CODEC_AAC && core != AOT_ER_AAC_ELD)) + + for (i = 0; i < sbrTuningTableSize; i++) { + if (isForThisCore(i)) /* tuning table is for this core codec */ + { + if (numChannels == sbrTuningTable[i].numChannels && + sampleRate == sbrTuningTable[i].sampleRate) { + found = 1; + if ((bitrate >= sbrTuningTable[i].bitrateFrom) && + (bitrate < sbrTuningTable[i].bitrateTo)) { + return i; + } else { + if (sbrTuningTable[i].bitrateFrom > bitrate) { + if (sbrTuningTable[i].bitrateFrom < bitRateClosestLower) { + bitRateClosestLower = sbrTuningTable[i].bitrateFrom; + bitRateClosestLowerIndex = i; + } + } + if (sbrTuningTable[i].bitrateTo <= bitrate) { + if (sbrTuningTable[i].bitrateTo > bitRateClosestUpper) { + bitRateClosestUpper = sbrTuningTable[i].bitrateTo - 1; + bitRateClosestUpperIndex = i; + } + } + } + } + } + } + + if (bitRateClosestUpperIndex >= 0) { + return bitRateClosestUpperIndex; + } + + if (pBitRateClosest != NULL) { + /* If there was at least one matching tuning entry pick the least distance + * bit rate */ + if (found) { + int distanceUpper = DISTANCE_CEIL_VALUE, + distanceLower = DISTANCE_CEIL_VALUE; + if (bitRateClosestLowerIndex >= 0) { + distanceLower = + sbrTuningTable[bitRateClosestLowerIndex].bitrateFrom - bitrate; + } + if (bitRateClosestUpperIndex >= 0) { + distanceUpper = + bitrate - sbrTuningTable[bitRateClosestUpperIndex].bitrateTo; + } + if (distanceUpper < distanceLower) { + *pBitRateClosest = bitRateClosestUpper; + } else { + *pBitRateClosest = bitRateClosestLower; + } + } else { + *pBitRateClosest = 0; + } + } + + return INVALID_TABLE_IDX; +} + +/***************************************************************************/ +/*! + + \brief Selects the PS tuning settings to use dependent on bitrate + and core coder + + \return Index to the appropriate table + +****************************************************************************/ +static INT getPsTuningTableIndex(UINT bitrate, UINT *pBitRateClosest) { + INT i, paramSets = sizeof(psTuningTable) / sizeof(psTuningTable[0]); + int bitRateClosestLowerIndex = -1, bitRateClosestUpperIndex = -1; + UINT bitRateClosestUpper = 0, bitRateClosestLower = DISTANCE_CEIL_VALUE; + + for (i = 0; i < paramSets; i++) { + if ((bitrate >= psTuningTable[i].bitrateFrom) && + (bitrate < psTuningTable[i].bitrateTo)) { + return i; + } else { + if (psTuningTable[i].bitrateFrom > bitrate) { + if (psTuningTable[i].bitrateFrom < bitRateClosestLower) { + bitRateClosestLower = psTuningTable[i].bitrateFrom; + bitRateClosestLowerIndex = i; + } + } + if (psTuningTable[i].bitrateTo <= bitrate) { + if (psTuningTable[i].bitrateTo > bitRateClosestUpper) { + bitRateClosestUpper = psTuningTable[i].bitrateTo - 1; + bitRateClosestUpperIndex = i; + } + } + } + } + + if (bitRateClosestUpperIndex >= 0) { + return bitRateClosestUpperIndex; + } + + if (pBitRateClosest != NULL) { + int distanceUpper = DISTANCE_CEIL_VALUE, + distanceLower = DISTANCE_CEIL_VALUE; + if (bitRateClosestLowerIndex >= 0) { + distanceLower = + sbrTuningTable[bitRateClosestLowerIndex].bitrateFrom - bitrate; + } + if (bitRateClosestUpperIndex >= 0) { + distanceUpper = + bitrate - sbrTuningTable[bitRateClosestUpperIndex].bitrateTo; + } + if (distanceUpper < distanceLower) { + *pBitRateClosest = bitRateClosestUpper; + } else { + *pBitRateClosest = bitRateClosestLower; + } + } + + return INVALID_TABLE_IDX; +} + +/***************************************************************************/ +/*! + + \brief In case of downsampled SBR we may need to lower the stop freq + of a tuning setting to fit into the lower half of the + spectrum ( which is sampleRate/4 ) + + \return the adapted stop frequency index (-1 -> error) + + \ingroup SbrEncCfg + +****************************************************************************/ +static INT FDKsbrEnc_GetDownsampledStopFreq(const INT sampleRateCore, + const INT startFreq, INT stopFreq, + const INT downSampleFactor) { + INT maxStopFreqRaw = sampleRateCore / 2; + INT startBand, stopBand; + HANDLE_ERROR_INFO err; + + while (stopFreq > 0 && FDKsbrEnc_getSbrStopFreqRAW(stopFreq, sampleRateCore) > + maxStopFreqRaw) { + stopFreq--; + } + + if (FDKsbrEnc_getSbrStopFreqRAW(stopFreq, sampleRateCore) > maxStopFreqRaw) + return -1; + + err = FDKsbrEnc_FindStartAndStopBand( + sampleRateCore << (downSampleFactor - 1), sampleRateCore, + 32 << (downSampleFactor - 1), startFreq, stopFreq, &startBand, &stopBand); + if (err) return -1; + + return stopFreq; +} + +/***************************************************************************/ +/*! + + \brief tells us, if for the given coreCoder, bitrate, number of channels + and input sampling rate an SBR setting is available. If yes, it + tells us also the core sampling rate we would need to run with + + \return a flag indicating success: yes (1) or no (0) + +****************************************************************************/ +static UINT FDKsbrEnc_IsSbrSettingAvail( + UINT bitrate, /*! the total bitrate in bits/sec */ + UINT vbrMode, /*! the vbr paramter, 0 means constant bitrate */ + UINT numOutputChannels, /*! the number of channels for the core coder */ + UINT sampleRateInput, /*! the input sample rate [in Hz] */ + UINT sampleRateCore, /*! the core's sampling rate */ + AUDIO_OBJECT_TYPE core) { + INT idx = INVALID_TABLE_IDX; + + if (sampleRateInput < 16000) return 0; + + if (bitrate == 0) { + /* map vbr quality to bitrate */ + if (vbrMode < 30) + bitrate = 24000; + else if (vbrMode < 40) + bitrate = 28000; + else if (vbrMode < 60) + bitrate = 32000; + else if (vbrMode < 75) + bitrate = 40000; + else + bitrate = 48000; + bitrate *= numOutputChannels; + } + + idx = getSbrTuningTableIndex(bitrate, numOutputChannels, sampleRateCore, core, + NULL); + + return (idx == INVALID_TABLE_IDX ? 0 : 1); +} + +/***************************************************************************/ +/*! + + \brief Adjusts the SBR settings according to the chosen core coder + settings which are accessible via config->codecSettings + + \return A flag indicating success: yes (1) or no (0) + +****************************************************************************/ +static UINT FDKsbrEnc_AdjustSbrSettings( + const sbrConfigurationPtr config, /*! output, modified */ + UINT bitRate, /*! the total bitrate in bits/sec */ + UINT numChannels, /*! the core coder number of channels */ + UINT sampleRateCore, /*! the core coder sampling rate in Hz */ + UINT sampleRateSbr, /*! the sbr coder sampling rate in Hz */ + UINT transFac, /*! the short block to long block ratio */ + UINT standardBitrate, /*! the standard bitrate per channel in bits/sec */ + UINT vbrMode, /*! the vbr paramter, 0 poor quality .. 100 high quality*/ + UINT useSpeechConfig, /*!< adapt tuning parameters for speech ? */ + UINT lcsMode, /*! the low complexity stereo mode */ + UINT bParametricStereo, /*!< use parametric stereo */ + AUDIO_OBJECT_TYPE core) /* Core audio codec object type */ +{ + INT idx = INVALID_TABLE_IDX; + /* set the core codec settings */ + config->codecSettings.bitRate = bitRate; + config->codecSettings.nChannels = numChannels; + config->codecSettings.sampleFreq = sampleRateCore; + config->codecSettings.transFac = transFac; + config->codecSettings.standardBitrate = standardBitrate; + + if (bitRate < 28000) { + config->threshold_AmpRes_FF_m = (FIXP_DBL)MAXVAL_DBL; + config->threshold_AmpRes_FF_e = 7; + } else if (bitRate >= 28000 && bitRate <= 48000) { + /* The float threshold is 75 + 0.524288f is fractional part of RELAXATION, the quotaMatrix and therefore + tonality are scaled by this 2/3 is because the original implementation + divides the tonality values by 3, here it's divided by 2 128 compensates + the necessary shiftfactor of 7 */ + config->threshold_AmpRes_FF_m = + FL2FXCONST_DBL(75.0f * 0.524288f / (2.0f / 3.0f) / 128.0f); + config->threshold_AmpRes_FF_e = 7; + } else if (bitRate > 48000) { + config->threshold_AmpRes_FF_m = FL2FXCONST_DBL(0); + config->threshold_AmpRes_FF_e = 0; + } + + if (bitRate == 0) { + /* map vbr quality to bitrate */ + if (vbrMode < 30) + bitRate = 24000; + else if (vbrMode < 40) + bitRate = 28000; + else if (vbrMode < 60) + bitRate = 32000; + else if (vbrMode < 75) + bitRate = 40000; + else + bitRate = 48000; + bitRate *= numChannels; + /* fix to enable mono vbrMode<40 @ 44.1 of 48kHz */ + if (numChannels == 1) { + if (sampleRateSbr == 44100 || sampleRateSbr == 48000) { + if (vbrMode < 40) bitRate = 32000; + } + } + } + + idx = + getSbrTuningTableIndex(bitRate, numChannels, sampleRateCore, core, NULL); + + if (idx != INVALID_TABLE_IDX) { + config->startFreq = sbrTuningTable[idx].startFreq; + config->stopFreq = sbrTuningTable[idx].stopFreq; + if (useSpeechConfig) { + config->startFreq = sbrTuningTable[idx].startFreqSpeech; + config->stopFreq = sbrTuningTable[idx].stopFreqSpeech; + } + + /* Adapt stop frequency in case of downsampled SBR - only 32 bands then */ + if (1 == config->downSampleFactor) { + INT dsStopFreq = FDKsbrEnc_GetDownsampledStopFreq( + sampleRateCore, config->startFreq, config->stopFreq, + config->downSampleFactor); + if (dsStopFreq < 0) { + return 0; + } + + config->stopFreq = dsStopFreq; + } + + config->sbr_noise_bands = sbrTuningTable[idx].numNoiseBands; + if (core == AOT_ER_AAC_ELD) config->init_amp_res_FF = SBR_AMP_RES_1_5; + config->noiseFloorOffset = sbrTuningTable[idx].noiseFloorOffset; + + config->ana_max_level = sbrTuningTable[idx].noiseMaxLevel; + config->stereoMode = sbrTuningTable[idx].stereoMode; + config->freqScale = sbrTuningTable[idx].freqScale; + + if (numChannels == 1) { + /* stereo case */ + switch (core) { + case AOT_AAC_LC: + if (bitRate <= (useSpeechConfig ? 24000U : 20000U)) { + config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency + resolution for + non-split frames */ + config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency + resolution for split + frames */ + } + break; + case AOT_ER_AAC_ELD: + if (bitRate < 36000) + config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency + resolution for split + frames */ + if (bitRate < 26000) { + config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency + resolution for + non-split frames */ + config->fResTransIsLow = + 1; /* for transient frames, set low frequency resolution */ + } + break; + default: + break; + } + } else { + /* stereo case */ + switch (core) { + case AOT_AAC_LC: + if (bitRate <= 28000) { + config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency + resolution for + non-split frames */ + config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency + resolution for split + frames */ + } + break; + case AOT_ER_AAC_ELD: + if (bitRate < 72000) { + config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency + resolution for split + frames */ + } + if (bitRate < 52000) { + config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency + resolution for + non-split frames */ + config->fResTransIsLow = + 1; /* for transient frames, set low frequency resolution */ + } + break; + default: + break; + } + if (bitRate <= 28000) { + /* + additionally restrict frequency resolution in FIXFIX frames + to further reduce SBR payload size */ + config->freq_res_fixfix[0] = FREQ_RES_LOW; + config->freq_res_fixfix[1] = FREQ_RES_LOW; + } + } + + /* adjust usage of parametric coding dependent on bitrate and speech config + * flag */ + if (useSpeechConfig) config->parametricCoding = 0; + + if (core == AOT_ER_AAC_ELD) { + if (bitRate < 28000) config->init_amp_res_FF = SBR_AMP_RES_3_0; + config->SendHeaderDataTime = -1; + } + + if (numChannels == 1) { + if (bitRate < 16000) { + config->parametricCoding = 0; + } + } else { + if (bitRate < 20000) { + config->parametricCoding = 0; + } + } + + config->useSpeechConfig = useSpeechConfig; + + /* PS settings */ + config->bParametricStereo = bParametricStereo; + + return 1; + } else { + return 0; + } +} + +/***************************************************************************** + + functionname: FDKsbrEnc_InitializeSbrDefaults + description: initializes the SBR configuration + returns: error status + input: - core codec type, + - factor of SBR to core frame length, + - core frame length + output: initialized SBR configuration + +*****************************************************************************/ +static UINT FDKsbrEnc_InitializeSbrDefaults(sbrConfigurationPtr config, + INT downSampleFactor, + UINT codecGranuleLen, + const INT isLowDelay) { + if ((downSampleFactor < 1 || downSampleFactor > 2) || + (codecGranuleLen * downSampleFactor > 64 * 32)) + return (0); /* error */ + + config->SendHeaderDataTime = 1000; + config->useWaveCoding = 0; + config->crcSbr = 0; + config->dynBwSupported = 1; + if (isLowDelay) + config->tran_thr = 6000; + else + config->tran_thr = 13000; + + config->parametricCoding = 1; + + config->sbrFrameSize = codecGranuleLen * downSampleFactor; + config->downSampleFactor = downSampleFactor; + + /* sbr default parameters */ + config->sbr_data_extra = 0; + config->amp_res = SBR_AMP_RES_3_0; + config->tran_fc = 0; + config->tran_det_mode = 1; + config->spread = 1; + config->stat = 0; + config->e = 1; + config->deltaTAcrossFrames = 1; + config->dF_edge_1stEnv = FL2FXCONST_DBL(0.3f); + config->dF_edge_incr = FL2FXCONST_DBL(0.3f); + + config->sbr_invf_mode = INVF_SWITCHED; + config->sbr_xpos_mode = XPOS_LC; + config->sbr_xpos_ctrl = SBR_XPOS_CTRL_DEFAULT; + config->sbr_xpos_level = 0; + config->useSaPan = 0; + config->dynBwEnabled = 0; + + /* the following parameters are overwritten by the + FDKsbrEnc_AdjustSbrSettings() function since they are included in the + tuning table */ + config->stereoMode = SBR_SWITCH_LRC; + config->ana_max_level = 6; + config->noiseFloorOffset = 0; + config->startFreq = 5; /* 5.9 respectively 6.0 kHz at fs = 44.1/48 kHz */ + config->stopFreq = 9; /* 16.2 respectively 16.8 kHz at fs = 44.1/48 kHz */ + config->freq_res_fixfix[0] = FREQ_RES_HIGH; /* non-split case */ + config->freq_res_fixfix[1] = FREQ_RES_HIGH; /* split case */ + config->fResTransIsLow = 0; /* for transient frames, set variable frequency + resolution according to freqResTable */ + + /* header_extra_1 */ + config->freqScale = SBR_FREQ_SCALE_DEFAULT; + config->alterScale = SBR_ALTER_SCALE_DEFAULT; + config->sbr_noise_bands = SBR_NOISE_BANDS_DEFAULT; + + /* header_extra_2 */ + config->sbr_limiter_bands = SBR_LIMITER_BANDS_DEFAULT; + config->sbr_limiter_gains = SBR_LIMITER_GAINS_DEFAULT; + config->sbr_interpol_freq = SBR_INTERPOL_FREQ_DEFAULT; + config->sbr_smoothing_length = SBR_SMOOTHING_LENGTH_DEFAULT; + + return 1; +} + +/***************************************************************************** + + functionname: DeleteEnvChannel + description: frees memory of one SBR channel + returns: - + input: handle of channel + output: released handle + +*****************************************************************************/ +static void deleteEnvChannel(HANDLE_ENV_CHANNEL hEnvCut) { + if (hEnvCut) { + FDKsbrEnc_DeleteTonCorrParamExtr(&hEnvCut->TonCorr); + + FDKsbrEnc_deleteExtractSbrEnvelope(&hEnvCut->sbrExtractEnvelope); + } +} + +/***************************************************************************** + + functionname: sbrEncoder_ChannelClose + description: close the channel coding handle + returns: + input: phSbrChannel + output: + +*****************************************************************************/ +static void sbrEncoder_ChannelClose(HANDLE_SBR_CHANNEL hSbrChannel) { + if (hSbrChannel != NULL) { + deleteEnvChannel(&hSbrChannel->hEnvChannel); + } +} + +/***************************************************************************** + + functionname: sbrEncoder_ElementClose + description: close the channel coding handle + returns: + input: phSbrChannel + output: + +*****************************************************************************/ +static void sbrEncoder_ElementClose(HANDLE_SBR_ELEMENT *phSbrElement) { + HANDLE_SBR_ELEMENT hSbrElement = *phSbrElement; + + if (hSbrElement != NULL) { + if (hSbrElement->sbrConfigData.v_k_master) + FreeRam_Sbr_v_k_master(&hSbrElement->sbrConfigData.v_k_master); + if (hSbrElement->sbrConfigData.freqBandTable[LO]) + FreeRam_Sbr_freqBandTableLO( + &hSbrElement->sbrConfigData.freqBandTable[LO]); + if (hSbrElement->sbrConfigData.freqBandTable[HI]) + FreeRam_Sbr_freqBandTableHI( + &hSbrElement->sbrConfigData.freqBandTable[HI]); + + FreeRam_SbrElement(phSbrElement); + } + return; +} + +void sbrEncoder_Close(HANDLE_SBR_ENCODER *phSbrEncoder) { + HANDLE_SBR_ENCODER hSbrEncoder = *phSbrEncoder; + + if (hSbrEncoder != NULL) { + int el, ch; + + for (el = 0; el < (8); el++) { + if (hSbrEncoder->sbrElement[el] != NULL) { + sbrEncoder_ElementClose(&hSbrEncoder->sbrElement[el]); + } + } + + /* Close sbr Channels */ + for (ch = 0; ch < (8); ch++) { + if (hSbrEncoder->pSbrChannel[ch]) { + sbrEncoder_ChannelClose(hSbrEncoder->pSbrChannel[ch]); + FreeRam_SbrChannel(&hSbrEncoder->pSbrChannel[ch]); + } + + if (hSbrEncoder->QmfAnalysis[ch].FilterStates) + FreeRam_Sbr_QmfStatesAnalysis( + (FIXP_QAS **)&hSbrEncoder->QmfAnalysis[ch].FilterStates); + } + + if (hSbrEncoder->hParametricStereo) + PSEnc_Destroy(&hSbrEncoder->hParametricStereo); + if (hSbrEncoder->qmfSynthesisPS.FilterStates) + FreeRam_PsQmfStatesSynthesis( + (FIXP_DBL **)&hSbrEncoder->qmfSynthesisPS.FilterStates); + + /* Release Overlay */ + if (hSbrEncoder->pSBRdynamic_RAM) + FreeRam_SbrDynamic_RAM((FIXP_DBL **)&hSbrEncoder->pSBRdynamic_RAM); + + FreeRam_SbrEncoder(phSbrEncoder); + } +} + +/***************************************************************************** + + functionname: updateFreqBandTable + description: updates vk_master + returns: - + input: config handle + output: error info + +*****************************************************************************/ +static INT updateFreqBandTable(HANDLE_SBR_CONFIG_DATA sbrConfigData, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + const INT downSampleFactor) { + INT k0, k2; + + if (FDKsbrEnc_FindStartAndStopBand( + sbrConfigData->sampleFreq, + sbrConfigData->sampleFreq >> (downSampleFactor - 1), + sbrConfigData->noQmfBands, sbrHeaderData->sbr_start_frequency, + sbrHeaderData->sbr_stop_frequency, &k0, &k2)) + return (1); + + if (FDKsbrEnc_UpdateFreqScale( + sbrConfigData->v_k_master, &sbrConfigData->num_Master, k0, k2, + sbrHeaderData->freqScale, sbrHeaderData->alterScale)) + return (1); + + sbrHeaderData->sbr_xover_band = 0; + + if (FDKsbrEnc_UpdateHiRes(sbrConfigData->freqBandTable[HI], + &sbrConfigData->nSfb[HI], sbrConfigData->v_k_master, + sbrConfigData->num_Master, + &sbrHeaderData->sbr_xover_band)) + return (1); + + FDKsbrEnc_UpdateLoRes( + sbrConfigData->freqBandTable[LO], &sbrConfigData->nSfb[LO], + sbrConfigData->freqBandTable[HI], sbrConfigData->nSfb[HI]); + + sbrConfigData->xOverFreq = + (sbrConfigData->freqBandTable[LOW_RES][0] * sbrConfigData->sampleFreq / + sbrConfigData->noQmfBands + + 1) >> + 1; + + return (0); +} + +/***************************************************************************** + + functionname: resetEnvChannel + description: resets parameters and allocates memory + returns: error status + input: + output: hEnv + +*****************************************************************************/ +static INT resetEnvChannel(HANDLE_SBR_CONFIG_DATA sbrConfigData, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_ENV_CHANNEL hEnv) { + /* note !!! hEnv->encEnvData.noOfnoisebands will be updated later in function + * FDKsbrEnc_extractSbrEnvelope !!!*/ + hEnv->TonCorr.sbrNoiseFloorEstimate.noiseBands = + sbrHeaderData->sbr_noise_bands; + + if (FDKsbrEnc_ResetTonCorrParamExtr( + &hEnv->TonCorr, sbrConfigData->xposCtrlSwitch, + sbrConfigData->freqBandTable[HI][0], sbrConfigData->v_k_master, + sbrConfigData->num_Master, sbrConfigData->sampleFreq, + sbrConfigData->freqBandTable, sbrConfigData->nSfb, + sbrConfigData->noQmfBands)) + return (1); + + hEnv->sbrCodeNoiseFloor.nSfb[LO] = + hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + hEnv->sbrCodeNoiseFloor.nSfb[HI] = + hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + hEnv->sbrCodeEnvelope.nSfb[LO] = sbrConfigData->nSfb[LO]; + hEnv->sbrCodeEnvelope.nSfb[HI] = sbrConfigData->nSfb[HI]; + + hEnv->encEnvData.noHarmonics = sbrConfigData->nSfb[HI]; + + hEnv->sbrCodeEnvelope.upDate = 0; + hEnv->sbrCodeNoiseFloor.upDate = 0; + + return (0); +} + +/* ****************************** FDKsbrEnc_SbrGetXOverFreq + * ******************************/ +/** + * @fn + * @brief calculates the closest possible crossover frequency + * @return the crossover frequency SBR accepts + * + */ +static INT FDKsbrEnc_SbrGetXOverFreq( + HANDLE_SBR_ELEMENT hEnv, /*!< handle to SBR encoder instance */ + INT xoverFreq) /*!< from core coder suggested crossover frequency */ +{ + INT band; + INT lastDiff, newDiff; + INT cutoffSb; + + UCHAR *RESTRICT pVKMaster = hEnv->sbrConfigData.v_k_master; + + /* Check if there is a matching cutoff frequency in the master table */ + cutoffSb = (4 * xoverFreq * hEnv->sbrConfigData.noQmfBands / + hEnv->sbrConfigData.sampleFreq + + 1) >> + 1; + lastDiff = cutoffSb; + for (band = 0; band < hEnv->sbrConfigData.num_Master; band++) { + newDiff = fixp_abs((INT)pVKMaster[band] - cutoffSb); + + if (newDiff >= lastDiff) { + band--; + break; + } + + lastDiff = newDiff; + } + + return ((pVKMaster[band] * hEnv->sbrConfigData.sampleFreq / + hEnv->sbrConfigData.noQmfBands + + 1) >> + 1); +} + +/***************************************************************************** + + functionname: FDKsbrEnc_EnvEncodeFrame + description: performs the sbr envelope calculation for one element + returns: + input: + output: + +*****************************************************************************/ +INT FDKsbrEnc_EnvEncodeFrame( + HANDLE_SBR_ENCODER hEnvEncoder, int iElement, + INT_PCM *samples, /*!< time samples, always deinterleaved */ + UINT samplesBufSize, /*!< time buffer channel stride */ + UINT *sbrDataBits, /*!< Size of SBR payload */ + UCHAR *sbrData, /*!< SBR payload */ + int clearOutput /*!< Do not consider any input signal */ +) { + HANDLE_SBR_ELEMENT hSbrElement = NULL; + FDK_CRCINFO crcInfo; + INT crcReg; + INT ch; + INT band; + INT cutoffSb; + INT newXOver; + + if (hEnvEncoder == NULL) return -1; + + hSbrElement = hEnvEncoder->sbrElement[iElement]; + + if (hSbrElement == NULL) return -1; + + /* header bitstream handling */ + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData = &hSbrElement->sbrBitstreamData; + + INT psHeaderActive = 0; + sbrBitstreamData->HeaderActive = 0; + + /* Anticipate PS header because of internal PS bitstream delay in order to be + * in sync with SBR header. */ + if (sbrBitstreamData->CountSendHeaderData == + (sbrBitstreamData->NrSendHeaderData - 1)) { + psHeaderActive = 1; + } + + /* Signal SBR header to be written into bitstream */ + if (sbrBitstreamData->CountSendHeaderData == 0) { + sbrBitstreamData->HeaderActive = 1; + } + + /* Increment header interval counter */ + if (sbrBitstreamData->NrSendHeaderData == 0) { + sbrBitstreamData->CountSendHeaderData = 1; + } else { + if (sbrBitstreamData->CountSendHeaderData >= 0) { + sbrBitstreamData->CountSendHeaderData++; + sbrBitstreamData->CountSendHeaderData %= + sbrBitstreamData->NrSendHeaderData; + } + } + + if (hSbrElement->CmonData.dynBwEnabled) { + INT i; + for (i = 4; i > 0; i--) + hSbrElement->dynXOverFreqDelay[i] = hSbrElement->dynXOverFreqDelay[i - 1]; + + hSbrElement->dynXOverFreqDelay[0] = hSbrElement->CmonData.dynXOverFreqEnc; + if (hSbrElement->dynXOverFreqDelay[1] > hSbrElement->dynXOverFreqDelay[2]) + newXOver = hSbrElement->dynXOverFreqDelay[2]; + else + newXOver = hSbrElement->dynXOverFreqDelay[1]; + + /* has the crossover frequency changed? */ + if (hSbrElement->sbrConfigData.dynXOverFreq != newXOver) { + /* get corresponding master band */ + cutoffSb = ((4 * newXOver * hSbrElement->sbrConfigData.noQmfBands / + hSbrElement->sbrConfigData.sampleFreq) + + 1) >> + 1; + + for (band = 0; band < hSbrElement->sbrConfigData.num_Master; band++) { + if (cutoffSb == hSbrElement->sbrConfigData.v_k_master[band]) break; + } + FDK_ASSERT(band < hSbrElement->sbrConfigData.num_Master); + + hSbrElement->sbrConfigData.dynXOverFreq = newXOver; + hSbrElement->sbrHeaderData.sbr_xover_band = band; + hSbrElement->sbrBitstreamData.HeaderActive = 1; + psHeaderActive = 1; /* ps header is one frame delayed */ + + /* + update vk_master table + */ + if (updateFreqBandTable(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + hEnvEncoder->downSampleFactor)) + return (1); + + /* reset SBR channels */ + INT nEnvCh = hSbrElement->sbrConfigData.nChannels; + for (ch = 0; ch < nEnvCh; ch++) { + if (resetEnvChannel(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + &hSbrElement->sbrChannel[ch]->hEnvChannel)) + return (1); + } + } + } + + /* + allocate space for dummy header and crc + */ + crcReg = FDKsbrEnc_InitSbrBitstream( + &hSbrElement->CmonData, + hSbrElement->payloadDelayLine[hEnvEncoder->nBitstrDelay], + MAX_PAYLOAD_SIZE * sizeof(UCHAR), &crcInfo, + hSbrElement->sbrConfigData.sbrSyntaxFlags); + + /* Temporal Envelope Data */ + SBR_FRAME_TEMP_DATA _fData; + SBR_FRAME_TEMP_DATA *fData = &_fData; + SBR_ENV_TEMP_DATA eData[MAX_NUM_CHANNELS]; + + /* Init Temporal Envelope Data */ + { + int i; + + FDKmemclear(&eData[0], sizeof(SBR_ENV_TEMP_DATA)); + FDKmemclear(&eData[1], sizeof(SBR_ENV_TEMP_DATA)); + FDKmemclear(fData, sizeof(SBR_FRAME_TEMP_DATA)); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) fData->res[i] = FREQ_RES_HIGH; + } + + if (!clearOutput) { + /* + * Transform audio data into QMF domain + */ + for (ch = 0; ch < hSbrElement->sbrConfigData.nChannels; ch++) { + HANDLE_ENV_CHANNEL h_envChan = &hSbrElement->sbrChannel[ch]->hEnvChannel; + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &h_envChan->sbrExtractEnvelope; + + if (hSbrElement->elInfo.fParametricStereo == 0) { + QMF_SCALE_FACTOR tmpScale; + FIXP_DBL **pQmfReal, **pQmfImag; + C_AALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, 64 * 2) + + /* Obtain pointers to QMF buffers. */ + pQmfReal = sbrExtrEnv->rBuffer; + pQmfImag = sbrExtrEnv->iBuffer; + + qmfAnalysisFiltering( + hSbrElement->hQmfAnalysis[ch], pQmfReal, pQmfImag, &tmpScale, + samples + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize, 0, + 1, qmfWorkBuffer); + + h_envChan->qmfScale = tmpScale.lb_scale + 7; + + C_AALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, 64 * 2) + + } /* fParametricStereo == 0 */ + + /* + Parametric Stereo processing + */ + if (hSbrElement->elInfo.fParametricStereo) { + INT error = noError; + + /* Limit Parametric Stereo to one instance */ + FDK_ASSERT(ch == 0); + + if (error == noError) { + /* parametric stereo processing: + - input: + o left and right time domain samples + - processing: + o stereo qmf analysis + o stereo hybrid analysis + o ps parameter extraction + o downmix + hybrid synthesis + - output: + o downmixed qmf data is written to sbrExtrEnv->rBuffer and + sbrExtrEnv->iBuffer + */ + SCHAR qmfScale; + INT_PCM *pSamples[2] = { + samples + hSbrElement->elInfo.ChannelIndex[0] * samplesBufSize, + samples + hSbrElement->elInfo.ChannelIndex[1] * samplesBufSize}; + error = FDKsbrEnc_PSEnc_ParametricStereoProcessing( + hEnvEncoder->hParametricStereo, pSamples, samplesBufSize, + hSbrElement->hQmfAnalysis, sbrExtrEnv->rBuffer, + sbrExtrEnv->iBuffer, + samples + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize, + &hEnvEncoder->qmfSynthesisPS, &qmfScale, psHeaderActive); + h_envChan->qmfScale = (int)qmfScale; + } + + } /* if (hEnvEncoder->hParametricStereo) */ + + /* + + Extract Envelope relevant things from QMF data + + */ + FDKsbrEnc_extractSbrEnvelope1(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + &hSbrElement->sbrBitstreamData, h_envChan, + &hSbrElement->CmonData, &eData[ch], fData); + + } /* hEnvEncoder->sbrConfigData.nChannels */ + } + + /* + Process Envelope relevant things and calculate envelope data and write + payload + */ + FDKsbrEnc_extractSbrEnvelope2( + &hSbrElement->sbrConfigData, &hSbrElement->sbrHeaderData, + (hSbrElement->elInfo.fParametricStereo) ? hEnvEncoder->hParametricStereo + : NULL, + &hSbrElement->sbrBitstreamData, &hSbrElement->sbrChannel[0]->hEnvChannel, + (hSbrElement->sbrConfigData.stereoMode != SBR_MONO) + ? &hSbrElement->sbrChannel[1]->hEnvChannel + : NULL, + &hSbrElement->CmonData, eData, fData, clearOutput); + + hSbrElement->sbrBitstreamData.rightBorderFIX = 0; + + /* + format payload, calculate crc + */ + FDKsbrEnc_AssembleSbrBitstream(&hSbrElement->CmonData, &crcInfo, crcReg, + hSbrElement->sbrConfigData.sbrSyntaxFlags); + + /* + save new payload, set to zero length if greater than MAX_PAYLOAD_SIZE + */ + hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] = + FDKgetValidBits(&hSbrElement->CmonData.sbrBitbuf); + + if (hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] > + (MAX_PAYLOAD_SIZE << 3)) + hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] = 0; + + /* While filling the Delay lines, sbrData is NULL */ + if (sbrData) { + *sbrDataBits = hSbrElement->payloadDelayLineSize[0]; + FDKmemcpy(sbrData, hSbrElement->payloadDelayLine[0], + (hSbrElement->payloadDelayLineSize[0] + 7) >> 3); + } + + /* delay header active flag */ + if (hSbrElement->sbrBitstreamData.HeaderActive == 1) { + hSbrElement->sbrBitstreamData.HeaderActiveDelay = + 1 + hEnvEncoder->nBitstrDelay; + } else { + if (hSbrElement->sbrBitstreamData.HeaderActiveDelay > 0) { + hSbrElement->sbrBitstreamData.HeaderActiveDelay--; + } + } + + return (0); +} + +/***************************************************************************** + + functionname: FDKsbrEnc_Downsample + description: performs downsampling and delay compensation of the core path + returns: + input: + output: + +*****************************************************************************/ +INT FDKsbrEnc_Downsample( + HANDLE_SBR_ENCODER hSbrEncoder, + INT_PCM *samples, /*!< time samples, always deinterleaved */ + UINT samplesBufSize, /*!< time buffer size per channel */ + UINT numChannels, /*!< number of channels */ + UINT *sbrDataBits, /*!< Size of SBR payload */ + UCHAR *sbrData, /*!< SBR payload */ + int clearOutput /*!< Do not consider any input signal */ +) { + HANDLE_SBR_ELEMENT hSbrElement = NULL; + INT nOutSamples; + int el; + if (hSbrEncoder->downSampleFactor > 1) { + /* Do downsampling */ + + /* Loop over elements (LFE is handled later) */ + for (el = 0; el < hSbrEncoder->noElements; el++) { + hSbrElement = hSbrEncoder->sbrElement[el]; + if (hSbrEncoder->sbrElement[el] != NULL) { + if (hSbrEncoder->downsamplingMethod == SBRENC_DS_TIME) { + int ch; + int nChannels = hSbrElement->sbrConfigData.nChannels; + + for (ch = 0; ch < nChannels; ch++) { + FDKaacEnc_Downsample( + &hSbrElement->sbrChannel[ch]->downSampler, + samples + + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize + + hSbrEncoder->bufferOffset / numChannels, + hSbrElement->sbrConfigData.frameSize, + samples + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize, + &nOutSamples); + } + } + } + } + + /* Handle LFE (if existing) */ + if (hSbrEncoder->lfeChIdx != -1) { /* lfe downsampler */ + FDKaacEnc_Downsample(&hSbrEncoder->lfeDownSampler, + samples + hSbrEncoder->lfeChIdx * samplesBufSize + + hSbrEncoder->bufferOffset / numChannels, + hSbrEncoder->frameSize, + samples + hSbrEncoder->lfeChIdx * samplesBufSize, + &nOutSamples); + } + } else { + /* No downsampling. Still, some buffer shifting for correct delay */ + int samples2Copy = hSbrEncoder->frameSize; + if (hSbrEncoder->bufferOffset / (int)numChannels < samples2Copy) { + for (int c = 0; c < (int)numChannels; c++) { + /* Do memmove while taking care of overlapping memory areas. (memcpy + does not necessarily take care) Distinguish between oeverlapping and + non overlapping version due to reasons of complexity. */ + FDKmemmove(samples + c * samplesBufSize, + samples + c * samplesBufSize + + hSbrEncoder->bufferOffset / numChannels, + samples2Copy * sizeof(INT_PCM)); + } + } else { + for (int c = 0; c < (int)numChannels; c++) { + /* Simple memcpy since the memory areas are not overlapping */ + FDKmemcpy(samples + c * samplesBufSize, + samples + c * samplesBufSize + + hSbrEncoder->bufferOffset / numChannels, + samples2Copy * sizeof(INT_PCM)); + } + } + } + + return 0; +} + +/***************************************************************************** + + functionname: createEnvChannel + description: initializes parameters and allocates memory + returns: error status + input: + output: hEnv + +*****************************************************************************/ + +static INT createEnvChannel(HANDLE_ENV_CHANNEL hEnv, INT channel, + UCHAR *dynamic_RAM) { + FDKmemclear(hEnv, sizeof(struct ENV_CHANNEL)); + + if (FDKsbrEnc_CreateTonCorrParamExtr(&hEnv->TonCorr, channel)) { + return (1); + } + + if (FDKsbrEnc_CreateExtractSbrEnvelope(&hEnv->sbrExtractEnvelope, channel, + /*chan*/ 0, dynamic_RAM)) { + return (1); + } + + return 0; +} + +/***************************************************************************** + + functionname: initEnvChannel + description: initializes parameters + returns: error status + input: + output: + +*****************************************************************************/ +static INT initEnvChannel(HANDLE_SBR_CONFIG_DATA sbrConfigData, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_ENV_CHANNEL hEnv, sbrConfigurationPtr params, + ULONG statesInitFlag, INT chanInEl, + UCHAR *dynamic_RAM) { + int frameShift, tran_off = 0; + INT e; + INT tran_fc; + INT timeSlots, timeStep, startIndex; + INT noiseBands[2] = {3, 3}; + + e = 1 << params->e; + + FDK_ASSERT(params->e >= 0); + + hEnv->encEnvData.freq_res_fixfix[0] = params->freq_res_fixfix[0]; + hEnv->encEnvData.freq_res_fixfix[1] = params->freq_res_fixfix[1]; + hEnv->encEnvData.fResTransIsLow = params->fResTransIsLow; + + hEnv->fLevelProtect = 0; + + hEnv->encEnvData.ldGrid = + (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) ? 1 : 0; + + hEnv->encEnvData.sbr_xpos_mode = (XPOS_MODE)params->sbr_xpos_mode; + + if (hEnv->encEnvData.sbr_xpos_mode == XPOS_SWITCHED) { + /* + no other type than XPOS_MDCT or XPOS_SPEECH allowed, + but enable switching + */ + sbrConfigData->switchTransposers = TRUE; + hEnv->encEnvData.sbr_xpos_mode = XPOS_MDCT; + } else { + sbrConfigData->switchTransposers = FALSE; + } + + hEnv->encEnvData.sbr_xpos_ctrl = params->sbr_xpos_ctrl; + + /* extended data */ + if (params->parametricCoding) { + hEnv->encEnvData.extended_data = 1; + } else { + hEnv->encEnvData.extended_data = 0; + } + + hEnv->encEnvData.extension_size = 0; + + startIndex = QMF_FILTER_PROTOTYPE_SIZE - sbrConfigData->noQmfBands; + + switch (params->sbrFrameSize) { + case 2304: + timeSlots = 18; + break; + case 2048: + case 1024: + case 512: + timeSlots = 16; + break; + case 1920: + case 960: + case 480: + timeSlots = 15; + break; + case 1152: + timeSlots = 9; + break; + default: + return (1); /* Illegal frame size */ + } + + timeStep = sbrConfigData->noQmfSlots / timeSlots; + + if (FDKsbrEnc_InitTonCorrParamExtr( + params->sbrFrameSize, &hEnv->TonCorr, sbrConfigData, timeSlots, + params->sbr_xpos_ctrl, params->ana_max_level, + sbrHeaderData->sbr_noise_bands, params->noiseFloorOffset, + params->useSpeechConfig)) + return (1); + + hEnv->encEnvData.noOfnoisebands = + hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + noiseBands[0] = hEnv->encEnvData.noOfnoisebands; + noiseBands[1] = hEnv->encEnvData.noOfnoisebands; + + hEnv->encEnvData.sbr_invf_mode = (INVF_MODE)params->sbr_invf_mode; + + if (hEnv->encEnvData.sbr_invf_mode == INVF_SWITCHED) { + hEnv->encEnvData.sbr_invf_mode = INVF_MID_LEVEL; + hEnv->TonCorr.switchInverseFilt = TRUE; + } else { + hEnv->TonCorr.switchInverseFilt = FALSE; + } + + tran_fc = params->tran_fc; + + if (tran_fc == 0) { + tran_fc = fixMin( + 5000, FDKsbrEnc_getSbrStartFreqRAW(sbrHeaderData->sbr_start_frequency, + params->codecSettings.sampleFreq)); + } + + tran_fc = + (tran_fc * 4 * sbrConfigData->noQmfBands / sbrConfigData->sampleFreq + + 1) >> + 1; + + if (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + frameShift = LD_PRETRAN_OFF; + tran_off = LD_PRETRAN_OFF + FRAME_MIDDLE_SLOT_512LD * timeStep; + } else { + frameShift = 0; + switch (timeSlots) { + /* The factor of 2 is by definition. */ + case NUMBER_TIME_SLOTS_2048: + tran_off = 8 + FRAME_MIDDLE_SLOT_2048 * timeStep; + break; + case NUMBER_TIME_SLOTS_1920: + tran_off = 7 + FRAME_MIDDLE_SLOT_1920 * timeStep; + break; + default: + return 1; + } + } + if (FDKsbrEnc_InitExtractSbrEnvelope( + &hEnv->sbrExtractEnvelope, sbrConfigData->noQmfSlots, + sbrConfigData->noQmfBands, startIndex, timeSlots, timeStep, tran_off, + statesInitFlag, chanInEl, dynamic_RAM, sbrConfigData->sbrSyntaxFlags)) + return (1); + + if (FDKsbrEnc_InitSbrCodeEnvelope(&hEnv->sbrCodeEnvelope, sbrConfigData->nSfb, + params->deltaTAcrossFrames, + params->dF_edge_1stEnv, + params->dF_edge_incr)) + return (1); + + if (FDKsbrEnc_InitSbrCodeEnvelope(&hEnv->sbrCodeNoiseFloor, noiseBands, + params->deltaTAcrossFrames, 0, 0)) + return (1); + + sbrConfigData->initAmpResFF = params->init_amp_res_FF; + + if (FDKsbrEnc_InitSbrHuffmanTables(&hEnv->encEnvData, &hEnv->sbrCodeEnvelope, + &hEnv->sbrCodeNoiseFloor, + sbrHeaderData->sbr_amp_res)) + return (1); + + FDKsbrEnc_initFrameInfoGenerator( + &hEnv->SbrEnvFrame, params->spread, e, params->stat, timeSlots, + hEnv->encEnvData.freq_res_fixfix, hEnv->encEnvData.fResTransIsLow, + hEnv->encEnvData.ldGrid); + + if (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) + + { + INT bandwidth_qmf_slot = + (sbrConfigData->sampleFreq >> 1) / (sbrConfigData->noQmfBands); + if (FDKsbrEnc_InitSbrFastTransientDetector( + &hEnv->sbrFastTransientDetector, sbrConfigData->noQmfSlots, + bandwidth_qmf_slot, sbrConfigData->noQmfBands, + sbrConfigData->freqBandTable[0][0])) + return (1); + } + + /* The transient detector has to be initialized also if the fast transient + detector was active, because the values from the transient detector + structure are used. */ + if (FDKsbrEnc_InitSbrTransientDetector( + &hEnv->sbrTransientDetector, sbrConfigData->sbrSyntaxFlags, + sbrConfigData->frameSize, sbrConfigData->sampleFreq, params, tran_fc, + sbrConfigData->noQmfSlots, sbrConfigData->noQmfBands, + hEnv->sbrExtractEnvelope.YBufferWriteOffset, + hEnv->sbrExtractEnvelope.YBufferSzShift, frameShift, tran_off)) + return (1); + + sbrConfigData->xposCtrlSwitch = params->sbr_xpos_ctrl; + + hEnv->encEnvData.noHarmonics = sbrConfigData->nSfb[HI]; + hEnv->encEnvData.addHarmonicFlag = 0; + + return (0); +} + +INT sbrEncoder_Open(HANDLE_SBR_ENCODER *phSbrEncoder, INT nElements, + INT nChannels, INT supportPS) { + INT i; + INT errorStatus = 1; + HANDLE_SBR_ENCODER hSbrEncoder = NULL; + + if (phSbrEncoder == NULL) { + goto bail; + } + + hSbrEncoder = GetRam_SbrEncoder(); + if (hSbrEncoder == NULL) { + goto bail; + } + FDKmemclear(hSbrEncoder, sizeof(SBR_ENCODER)); + + if (NULL == + (hSbrEncoder->pSBRdynamic_RAM = (UCHAR *)GetRam_SbrDynamic_RAM())) { + goto bail; + } + hSbrEncoder->dynamicRam = hSbrEncoder->pSBRdynamic_RAM; + + /* Create SBR elements */ + for (i = 0; i < nElements; i++) { + hSbrEncoder->sbrElement[i] = GetRam_SbrElement(i); + if (hSbrEncoder->sbrElement[i] == NULL) { + goto bail; + } + FDKmemclear(hSbrEncoder->sbrElement[i], sizeof(SBR_ELEMENT)); + hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[LO] = + GetRam_Sbr_freqBandTableLO(i); + hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[HI] = + GetRam_Sbr_freqBandTableHI(i); + hSbrEncoder->sbrElement[i]->sbrConfigData.v_k_master = + GetRam_Sbr_v_k_master(i); + if ((hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[LO] == NULL) || + (hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[HI] == NULL) || + (hSbrEncoder->sbrElement[i]->sbrConfigData.v_k_master == NULL)) { + goto bail; + } + } + + /* Create SBR channels */ + for (i = 0; i < nChannels; i++) { + hSbrEncoder->pSbrChannel[i] = GetRam_SbrChannel(i); + if (hSbrEncoder->pSbrChannel[i] == NULL) { + goto bail; + } + + if (createEnvChannel(&hSbrEncoder->pSbrChannel[i]->hEnvChannel, i, + hSbrEncoder->dynamicRam)) { + goto bail; + } + } + + /* Create QMF States */ + for (i = 0; i < fixMax(nChannels, (supportPS) ? 2 : 0); i++) { + hSbrEncoder->QmfAnalysis[i].FilterStates = GetRam_Sbr_QmfStatesAnalysis(i); + if (hSbrEncoder->QmfAnalysis[i].FilterStates == NULL) { + goto bail; + } + } + + /* Create Parametric Stereo handle */ + if (supportPS) { + if (PSEnc_Create(&hSbrEncoder->hParametricStereo)) { + goto bail; + } + + hSbrEncoder->qmfSynthesisPS.FilterStates = GetRam_PsQmfStatesSynthesis(); + if (hSbrEncoder->qmfSynthesisPS.FilterStates == NULL) { + goto bail; + } + } /* supportPS */ + + *phSbrEncoder = hSbrEncoder; + + errorStatus = 0; + return errorStatus; + +bail: + /* Close SBR encoder instance */ + sbrEncoder_Close(&hSbrEncoder); + return errorStatus; +} + +static INT FDKsbrEnc_Reallocate(HANDLE_SBR_ENCODER hSbrEncoder, + SBR_ELEMENT_INFO elInfo[(8)], + const INT noElements) { + INT totalCh = 0; + INT totalQmf = 0; + INT coreEl; + INT el = -1; + + hSbrEncoder->lfeChIdx = -1; /* default value, until lfe found */ + + for (coreEl = 0; coreEl < noElements; coreEl++) { + /* SBR only handles SCE and CPE's */ + if (elInfo[coreEl].elType == ID_SCE || elInfo[coreEl].elType == ID_CPE) { + el++; + } else { + if (elInfo[coreEl].elType == ID_LFE) { + hSbrEncoder->lfeChIdx = elInfo[coreEl].ChannelIndex[0]; + } + continue; + } + + SBR_ELEMENT_INFO *pelInfo = &elInfo[coreEl]; + HANDLE_SBR_ELEMENT hSbrElement = hSbrEncoder->sbrElement[el]; + + int ch; + for (ch = 0; ch < pelInfo->nChannelsInEl; ch++) { + hSbrElement->sbrChannel[ch] = hSbrEncoder->pSbrChannel[totalCh]; + totalCh++; + } + /* analysis QMF */ + for (ch = 0; + ch < ((pelInfo->fParametricStereo) ? 2 : pelInfo->nChannelsInEl); + ch++) { + hSbrElement->elInfo.ChannelIndex[ch] = pelInfo->ChannelIndex[ch]; + hSbrElement->hQmfAnalysis[ch] = &hSbrEncoder->QmfAnalysis[totalQmf++]; + } + + /* Copy Element info */ + hSbrElement->elInfo.elType = pelInfo->elType; + hSbrElement->elInfo.instanceTag = pelInfo->instanceTag; + hSbrElement->elInfo.nChannelsInEl = pelInfo->nChannelsInEl; + hSbrElement->elInfo.fParametricStereo = pelInfo->fParametricStereo; + hSbrElement->elInfo.fDualMono = pelInfo->fDualMono; + } /* coreEl */ + + return 0; +} + +/***************************************************************************** + + functionname: FDKsbrEnc_bsBufInit + description: initializes bitstream buffer + returns: initialized bitstream buffer in env encoder + input: + output: hEnv + +*****************************************************************************/ +static INT FDKsbrEnc_bsBufInit(HANDLE_SBR_ELEMENT hSbrElement, + int nBitstrDelay) { + UCHAR *bitstreamBuffer; + + /* initialize the bitstream buffer */ + bitstreamBuffer = hSbrElement->payloadDelayLine[nBitstrDelay]; + FDKinitBitStream(&hSbrElement->CmonData.sbrBitbuf, bitstreamBuffer, + MAX_PAYLOAD_SIZE * sizeof(UCHAR), 0, BS_WRITER); + + return (0); +} + +/***************************************************************************** + + functionname: FDKsbrEnc_EnvInit + description: initializes parameters + returns: error status + input: + output: hEnv + +*****************************************************************************/ +static INT FDKsbrEnc_EnvInit(HANDLE_SBR_ELEMENT hSbrElement, + sbrConfigurationPtr params, INT *coreBandWith, + AUDIO_OBJECT_TYPE aot, int nElement, + const int headerPeriod, ULONG statesInitFlag, + const SBRENC_DS_TYPE downsamplingMethod, + UCHAR *dynamic_RAM) { + int ch, i; + + if ((params->codecSettings.nChannels < 1) || + (params->codecSettings.nChannels > MAX_NUM_CHANNELS)) { + return (1); + } + + /* init and set syntax flags */ + hSbrElement->sbrConfigData.sbrSyntaxFlags = 0; + + switch (aot) { + case AOT_ER_AAC_ELD: + hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_LOW_DELAY; + break; + default: + break; + } + if (params->crcSbr) { + hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_CRC; + } + + hSbrElement->sbrConfigData.noQmfBands = 64 >> (2 - params->downSampleFactor); + switch (hSbrElement->sbrConfigData.noQmfBands) { + case 64: + hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize >> 6; + break; + case 32: + hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize >> 5; + break; + default: + hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize >> 6; + return (2); + } + + /* + now initialize sbrConfigData, sbrHeaderData and sbrBitstreamData, + */ + hSbrElement->sbrConfigData.nChannels = params->codecSettings.nChannels; + + if (params->codecSettings.nChannels == 2) { + if ((hSbrElement->elInfo.elType == ID_CPE) && + ((hSbrElement->elInfo.fDualMono == 1))) { + hSbrElement->sbrConfigData.stereoMode = SBR_LEFT_RIGHT; + } else { + hSbrElement->sbrConfigData.stereoMode = params->stereoMode; + } + } else { + hSbrElement->sbrConfigData.stereoMode = SBR_MONO; + } + + hSbrElement->sbrConfigData.frameSize = params->sbrFrameSize; + + hSbrElement->sbrConfigData.sampleFreq = + params->downSampleFactor * params->codecSettings.sampleFreq; + + hSbrElement->sbrBitstreamData.CountSendHeaderData = 0; + if (params->SendHeaderDataTime > 0) { + if (headerPeriod == -1) { + hSbrElement->sbrBitstreamData.NrSendHeaderData = (INT)( + params->SendHeaderDataTime * hSbrElement->sbrConfigData.sampleFreq / + (1000 * hSbrElement->sbrConfigData.frameSize)); + hSbrElement->sbrBitstreamData.NrSendHeaderData = + fixMax(hSbrElement->sbrBitstreamData.NrSendHeaderData, 1); + } else { + /* assure header period at least once per second */ + hSbrElement->sbrBitstreamData.NrSendHeaderData = fixMin( + fixMax(headerPeriod, 1), (hSbrElement->sbrConfigData.sampleFreq / + hSbrElement->sbrConfigData.frameSize)); + } + } else { + hSbrElement->sbrBitstreamData.NrSendHeaderData = 0; + } + + hSbrElement->sbrHeaderData.sbr_data_extra = params->sbr_data_extra; + hSbrElement->sbrBitstreamData.HeaderActive = 0; + hSbrElement->sbrBitstreamData.rightBorderFIX = 0; + hSbrElement->sbrHeaderData.sbr_start_frequency = params->startFreq; + hSbrElement->sbrHeaderData.sbr_stop_frequency = params->stopFreq; + hSbrElement->sbrHeaderData.sbr_xover_band = 0; + hSbrElement->sbrHeaderData.sbr_lc_stereo_mode = 0; + + /* data_extra */ + if (params->sbr_xpos_ctrl != SBR_XPOS_CTRL_DEFAULT) + hSbrElement->sbrHeaderData.sbr_data_extra = 1; + + hSbrElement->sbrHeaderData.sbr_amp_res = (AMP_RES)params->amp_res; + + /* header_extra_1 */ + hSbrElement->sbrHeaderData.freqScale = params->freqScale; + hSbrElement->sbrHeaderData.alterScale = params->alterScale; + hSbrElement->sbrHeaderData.sbr_noise_bands = params->sbr_noise_bands; + hSbrElement->sbrHeaderData.header_extra_1 = 0; + + if ((params->freqScale != SBR_FREQ_SCALE_DEFAULT) || + (params->alterScale != SBR_ALTER_SCALE_DEFAULT) || + (params->sbr_noise_bands != SBR_NOISE_BANDS_DEFAULT)) { + hSbrElement->sbrHeaderData.header_extra_1 = 1; + } + + /* header_extra_2 */ + hSbrElement->sbrHeaderData.sbr_limiter_bands = params->sbr_limiter_bands; + hSbrElement->sbrHeaderData.sbr_limiter_gains = params->sbr_limiter_gains; + + if ((hSbrElement->sbrConfigData.sampleFreq > 48000) && + (hSbrElement->sbrHeaderData.sbr_start_frequency >= 9)) { + hSbrElement->sbrHeaderData.sbr_limiter_gains = SBR_LIMITER_GAINS_INFINITE; + } + + hSbrElement->sbrHeaderData.sbr_interpol_freq = params->sbr_interpol_freq; + hSbrElement->sbrHeaderData.sbr_smoothing_length = + params->sbr_smoothing_length; + hSbrElement->sbrHeaderData.header_extra_2 = 0; + + if ((params->sbr_limiter_bands != SBR_LIMITER_BANDS_DEFAULT) || + (params->sbr_limiter_gains != SBR_LIMITER_GAINS_DEFAULT) || + (params->sbr_interpol_freq != SBR_INTERPOL_FREQ_DEFAULT) || + (params->sbr_smoothing_length != SBR_SMOOTHING_LENGTH_DEFAULT)) { + hSbrElement->sbrHeaderData.header_extra_2 = 1; + } + + /* other switches */ + hSbrElement->sbrConfigData.useWaveCoding = params->useWaveCoding; + hSbrElement->sbrConfigData.useParametricCoding = params->parametricCoding; + hSbrElement->sbrConfigData.thresholdAmpResFF_m = + params->threshold_AmpRes_FF_m; + hSbrElement->sbrConfigData.thresholdAmpResFF_e = + params->threshold_AmpRes_FF_e; + + /* init freq band table */ + if (updateFreqBandTable(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + params->downSampleFactor)) { + return (1); + } + + /* now create envelope ext and QMF for each available channel */ + for (ch = 0; ch < hSbrElement->sbrConfigData.nChannels; ch++) { + if (initEnvChannel(&hSbrElement->sbrConfigData, &hSbrElement->sbrHeaderData, + &hSbrElement->sbrChannel[ch]->hEnvChannel, params, + statesInitFlag, ch, dynamic_RAM)) { + return (1); + } + + } /* nChannels */ + + /* reset and intialize analysis qmf */ + for (ch = 0; ch < ((hSbrElement->elInfo.fParametricStereo) + ? 2 + : hSbrElement->sbrConfigData.nChannels); + ch++) { + int err; + UINT qmfFlags = + (hSbrElement->sbrConfigData.sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) + ? QMF_FLAG_CLDFB + : 0; + if (statesInitFlag) + qmfFlags &= ~QMF_FLAG_KEEP_STATES; + else + qmfFlags |= QMF_FLAG_KEEP_STATES; + + err = qmfInitAnalysisFilterBank( + hSbrElement->hQmfAnalysis[ch], + (FIXP_QAS *)hSbrElement->hQmfAnalysis[ch]->FilterStates, + hSbrElement->sbrConfigData.noQmfSlots, + hSbrElement->sbrConfigData.noQmfBands, + hSbrElement->sbrConfigData.noQmfBands, + hSbrElement->sbrConfigData.noQmfBands, qmfFlags); + if (0 != err) { + return err; + } + } + + /* */ + hSbrElement->CmonData.xOverFreq = hSbrElement->sbrConfigData.xOverFreq; + hSbrElement->CmonData.dynBwEnabled = + (params->dynBwSupported && params->dynBwEnabled); + hSbrElement->CmonData.dynXOverFreqEnc = + FDKsbrEnc_SbrGetXOverFreq(hSbrElement, hSbrElement->CmonData.xOverFreq); + for (i = 0; i < 5; i++) + hSbrElement->dynXOverFreqDelay[i] = hSbrElement->CmonData.dynXOverFreqEnc; + hSbrElement->CmonData.sbrNumChannels = hSbrElement->sbrConfigData.nChannels; + hSbrElement->sbrConfigData.dynXOverFreq = hSbrElement->CmonData.xOverFreq; + + /* Update Bandwith to be passed to the core encoder */ + *coreBandWith = hSbrElement->CmonData.xOverFreq; + + return (0); +} + +INT sbrEncoder_GetInBufferSize(int noChannels) { + INT temp; + + temp = (2048); + temp += 1024 + MAX_SAMPLE_DELAY; + temp *= noChannels; + temp *= sizeof(INT_PCM); + return temp; +} + +/* + * Encode Dummy SBR payload frames to fill the delay lines. + */ +static INT FDKsbrEnc_DelayCompensation(HANDLE_SBR_ENCODER hEnvEnc, + INT_PCM *timeBuffer, + UINT timeBufferBufSize) { + int n, el; + + for (n = hEnvEnc->nBitstrDelay; n > 0; n--) { + for (el = 0; el < hEnvEnc->noElements; el++) { + if (FDKsbrEnc_EnvEncodeFrame( + hEnvEnc, el, + timeBuffer + hEnvEnc->downsampledOffset / hEnvEnc->nChannels, + timeBufferBufSize, NULL, NULL, 1)) + return -1; + } + sbrEncoder_UpdateBuffers(hEnvEnc, timeBuffer, timeBufferBufSize); + } + return 0; +} + +UINT sbrEncoder_LimitBitRate(UINT bitRate, UINT numChannels, + UINT coreSampleRate, AUDIO_OBJECT_TYPE aot) { + UINT newBitRate = bitRate; + INT index; + + FDK_ASSERT(numChannels > 0 && numChannels <= 2); + if (aot == AOT_PS) { + if (numChannels == 1) { + index = getPsTuningTableIndex(bitRate, &newBitRate); + if (index == INVALID_TABLE_IDX) { + bitRate = newBitRate; + } + } else { + return 0; + } + } + index = getSbrTuningTableIndex(bitRate, numChannels, coreSampleRate, aot, + &newBitRate); + if (index != INVALID_TABLE_IDX) { + newBitRate = bitRate; + } + + return newBitRate; +} + +UINT sbrEncoder_IsSingleRatePossible(AUDIO_OBJECT_TYPE aot) { + UINT isPossible = (AOT_PS == aot) ? 0 : 1; + return isPossible; +} + +/*****************************************************************************/ +/* */ +/*functionname: sbrEncoder_Init_delay */ +/*description: Determine Delay balancing and new encoder delay */ +/* */ +/*returns: - error status */ +/*input: - frame length of the core (i.e. e.g. AAC) */ +/* - number of channels */ +/* - downsample factor (1 for downsampled, 2 for dual-rate SBR) */ +/* - low delay presence */ +/* - ps presence */ +/* - downsampling method: QMF-, time domain or no downsampling */ +/* - various delay values (see DELAY_PARAM struct description) */ +/* */ +/*Example: Delay balancing for a HE-AACv1 encoder (time-domain downsampling) */ +/*========================================================================== */ +/* */ +/* +--------+ +--------+ +--------+ +--------+ +--------+ */ +/* |core | |ds 2:1 | |AAC | |QMF | |QMF | */ +/* +-+path +------------+ +-+core +-+analysis+-+overlap +-+ */ +/* | |offset | | | | | |32 bands| | | | */ +/* | +--------+ +--------+ +--------+ +--------+ +--------+ | */ +/* | core path +-------++ */ +/* | |QMF | */ +/*->+ +synth. +-> */ +/* | |64 bands| */ +/* | +-------++ */ +/* | +--------+ +--------+ +--------+ +--------+ | */ +/* | |SBR path| |QMF | |subband | |bs delay| | */ +/* +-+offset +-+analysis+-+sample +-+(full +-----------------------+ */ +/* | | |64 bands| |buffer | | frames)| */ +/* +--------+ +--------+ +--------+ +--------+ */ +/* SBR path */ +/* */ +/*****************************************************************************/ +static INT sbrEncoder_Init_delay( + const int coreFrameLength, /* input */ + const int numChannels, /* input */ + const int downSampleFactor, /* input */ + const int lowDelay, /* input */ + const int usePs, /* input */ + const int is212, /* input */ + const SBRENC_DS_TYPE downsamplingMethod, /* input */ + DELAY_PARAM *hDelayParam /* input/output */ +) { + int delayCorePath = 0; /* delay in core path */ + int delaySbrPath = 0; /* delay difference in QMF aka SBR path */ + int delayInput2Core = 0; /* delay from the input to the core */ + int delaySbrDec = 0; /* delay of the decoder's SBR module */ + + int delayCore = hDelayParam->delay; /* delay of the core */ + + /* Added delay by the SBR delay initialization */ + int corePathOffset = 0; /* core path */ + int sbrPathOffset = 0; /* sbr path */ + int bitstreamDelay = 0; /* sbr path, framewise */ + + int flCore = coreFrameLength; /* core frame length */ + + int returnValue = 0; /* return value - 0 means: no error */ + + /* 1) Calculate actual delay for core and SBR path */ + if (is212) { + delayCorePath = DELAY_COREPATH_ELDv2SBR(flCore, downSampleFactor); + delaySbrPath = DELAY_ELDv2SBR(flCore, downSampleFactor); + delaySbrDec = ((flCore) / 2) * (downSampleFactor); + } else if (lowDelay) { + delayCorePath = DELAY_COREPATH_ELDSBR(flCore, downSampleFactor); + delaySbrPath = DELAY_ELDSBR(flCore, downSampleFactor); + delaySbrDec = DELAY_QMF_POSTPROC(downSampleFactor); + } else if (usePs) { + delayCorePath = DELAY_COREPATH_PS(flCore, downSampleFactor); + delaySbrPath = DELAY_PS(flCore, downSampleFactor); + delaySbrDec = DELAY_COREPATH_SBR(flCore, downSampleFactor); + } else { + delayCorePath = DELAY_COREPATH_SBR(flCore, downSampleFactor); + delaySbrPath = DELAY_SBR(flCore, downSampleFactor); + delaySbrDec = DELAY_COREPATH_SBR(flCore, downSampleFactor); + } + delayCorePath += delayCore * downSampleFactor; + delayCorePath += + (downsamplingMethod == SBRENC_DS_TIME) ? hDelayParam->dsDelay : 0; + + /* 2) Manage coupling of paths */ + if (downsamplingMethod == SBRENC_DS_QMF && delayCorePath > delaySbrPath) { + /* In case of QMF downsampling, both paths are coupled, i.e. the SBR path + offset would be added to both the SBR path and to the core path + as well, thus making it impossible to achieve delay balancing. + To overcome that problem, a framewise delay is added to the SBR path + first, until the overall delay of the core path is shorter than + the delay of the SBR path. When this is achieved, the missing delay + difference can be added as downsampled offset to the core path. + */ + while (delayCorePath > delaySbrPath) { + /* Add one frame delay to SBR path */ + delaySbrPath += flCore * downSampleFactor; + bitstreamDelay += 1; + } + } + + /* 3) Calculate necessary additional delay to balance the paths */ + if (delayCorePath > delaySbrPath) { + /* Delay QMF input */ + while (delayCorePath > delaySbrPath + (int)flCore * (int)downSampleFactor) { + /* Do bitstream frame-wise delay balancing if there are + more than SBR framelength samples delay difference */ + delaySbrPath += flCore * downSampleFactor; + bitstreamDelay += 1; + } + /* Multiply input offset by input channels */ + corePathOffset = 0; + sbrPathOffset = (delayCorePath - delaySbrPath) * numChannels; + } else { + /* Delay AAC data */ + /* Multiply downsampled offset by AAC core channels. Divide by 2 because of + half samplerate of downsampled data. */ + corePathOffset = ((delaySbrPath - delayCorePath) * numChannels) >> + (downSampleFactor - 1); + sbrPathOffset = 0; + } + + /* 4) Calculate delay from input to core */ + if (usePs) { + delayInput2Core = + (DELAY_QMF_ANA(downSampleFactor) + DELAY_QMF_DS + DELAY_HYB_SYN) + + (downSampleFactor * corePathOffset) + 1; + } else if (downsamplingMethod == SBRENC_DS_TIME) { + delayInput2Core = corePathOffset + hDelayParam->dsDelay; + } else { + delayInput2Core = corePathOffset; + } + + /* 6) Set output parameters */ + hDelayParam->delay = FDKmax(delayCorePath, delaySbrPath); /* overall delay */ + hDelayParam->sbrDecDelay = delaySbrDec; /* SBR decoder delay */ + hDelayParam->delayInput2Core = delayInput2Core; /* delay input - core */ + hDelayParam->bitstrDelay = bitstreamDelay; /* bitstream delay, in frames */ + hDelayParam->corePathOffset = corePathOffset; /* offset added to core path */ + hDelayParam->sbrPathOffset = sbrPathOffset; /* offset added to SBR path */ + + return returnValue; +} + +/***************************************************************************** + + functionname: sbrEncoder_Init + description: initializes the SBR encoder + returns: error status + +*****************************************************************************/ +INT sbrEncoder_Init(HANDLE_SBR_ENCODER hSbrEncoder, + SBR_ELEMENT_INFO elInfo[(8)], int noElements, + INT_PCM *inputBuffer, UINT inputBufferBufSize, + INT *coreBandwidth, INT *inputBufferOffset, + INT *numChannels, const UINT syntaxFlags, + INT *coreSampleRate, UINT *downSampleFactor, + INT *frameLength, AUDIO_OBJECT_TYPE aot, int *delay, + int transformFactor, const int headerPeriod, + ULONG statesInitFlag) { + HANDLE_ERROR_INFO errorInfo = noError; + sbrConfiguration sbrConfig[(8)]; + INT error = 0; + INT lowestBandwidth; + /* Save input parameters */ + INT inputSampleRate = *coreSampleRate; + int coreFrameLength = *frameLength; + int inputBandWidth = *coreBandwidth; + int inputChannels = *numChannels; + + SBRENC_DS_TYPE downsamplingMethod = SBRENC_DS_NONE; + int highestSbrStartFreq, highestSbrStopFreq; + int lowDelay = 0; + int usePs = 0; + int is212 = 0; + + DELAY_PARAM delayParam; + + /* check whether SBR setting is available for the current encoder + * configuration (bitrate, samplerate) */ + if (!sbrEncoder_IsSingleRatePossible(aot)) { + *downSampleFactor = 2; + } + + if (aot == AOT_PS || aot == AOT_DABPLUS_PS) { + usePs = 1; + } + if (aot == AOT_ER_AAC_ELD) { + lowDelay = 1; + } else if (aot == AOT_ER_AAC_LD) { + error = 1; + goto bail; + } + + /* Parametric Stereo */ + if (usePs) { + if (*numChannels == 2 && noElements == 1) { + /* Override Element type in case of Parametric stereo */ + elInfo[0].elType = ID_SCE; + elInfo[0].fParametricStereo = 1; + elInfo[0].nChannelsInEl = 1; + /* core encoder gets downmixed mono signal */ + *numChannels = 1; + } else { + error = 1; + goto bail; + } + } /* usePs */ + + /* set the core's sample rate */ + switch (*downSampleFactor) { + case 1: + *coreSampleRate = inputSampleRate; + downsamplingMethod = SBRENC_DS_NONE; + break; + case 2: + *coreSampleRate = inputSampleRate >> 1; + downsamplingMethod = usePs ? SBRENC_DS_QMF : SBRENC_DS_TIME; + break; + default: + *coreSampleRate = inputSampleRate >> 1; + return 0; /* return error */ + } + + /* check whether SBR setting is available for the current encoder + * configuration (bitrate, coreSampleRate) */ + { + int el, coreEl; + + /* Check if every element config is feasible */ + for (coreEl = 0; coreEl < noElements; coreEl++) { + /* SBR only handles SCE and CPE's */ + if (elInfo[coreEl].elType != ID_SCE && elInfo[coreEl].elType != ID_CPE) { + continue; + } + /* check if desired configuration is available */ + if (!FDKsbrEnc_IsSbrSettingAvail(elInfo[coreEl].bitRate, 0, + elInfo[coreEl].nChannelsInEl, + inputSampleRate, *coreSampleRate, aot)) { + error = 1; + goto bail; + } + } + + hSbrEncoder->nChannels = *numChannels; + hSbrEncoder->frameSize = coreFrameLength * *downSampleFactor; + hSbrEncoder->downsamplingMethod = downsamplingMethod; + hSbrEncoder->downSampleFactor = *downSampleFactor; + hSbrEncoder->estimateBitrate = 0; + hSbrEncoder->inputDataDelay = 0; + is212 = ((aot == AOT_ER_AAC_ELD) && (syntaxFlags & AC_LD_MPS)) ? 1 : 0; + + /* Open SBR elements */ + el = -1; + highestSbrStartFreq = highestSbrStopFreq = 0; + lowestBandwidth = 99999; + + /* Loop through each core encoder element and get a matching SBR element + * config */ + for (coreEl = 0; coreEl < noElements; coreEl++) { + /* SBR only handles SCE and CPE's */ + if (elInfo[coreEl].elType == ID_SCE || elInfo[coreEl].elType == ID_CPE) { + el++; + } else { + continue; + } + + /* Set parametric Stereo Flag. */ + if (usePs) { + elInfo[coreEl].fParametricStereo = 1; + } else { + elInfo[coreEl].fParametricStereo = 0; + } + + /* + * Init sbrConfig structure + */ + if (!FDKsbrEnc_InitializeSbrDefaults(&sbrConfig[el], *downSampleFactor, + coreFrameLength, IS_LOWDELAY(aot))) { + error = 1; + goto bail; + } + + /* + * Modify sbrConfig structure according to Element parameters + */ + if (!FDKsbrEnc_AdjustSbrSettings( + &sbrConfig[el], elInfo[coreEl].bitRate, + elInfo[coreEl].nChannelsInEl, *coreSampleRate, inputSampleRate, + transformFactor, 24000, 0, 0, /* useSpeechConfig */ + 0, /* lcsMode */ + usePs, /* bParametricStereo */ + aot)) { + error = 1; + goto bail; + } + + /* Find common frequency border for all SBR elements */ + highestSbrStartFreq = + fixMax(highestSbrStartFreq, sbrConfig[el].startFreq); + highestSbrStopFreq = fixMax(highestSbrStopFreq, sbrConfig[el].stopFreq); + + } /* first element loop */ + + /* Set element count (can be less than core encoder element count) */ + hSbrEncoder->noElements = el + 1; + + FDKsbrEnc_Reallocate(hSbrEncoder, elInfo, noElements); + + for (el = 0; el < hSbrEncoder->noElements; el++) { + int bandwidth = *coreBandwidth; + + /* Use lowest common bandwidth */ + sbrConfig[el].startFreq = highestSbrStartFreq; + sbrConfig[el].stopFreq = highestSbrStopFreq; + + /* initialize SBR element, and get core bandwidth */ + error = FDKsbrEnc_EnvInit(hSbrEncoder->sbrElement[el], &sbrConfig[el], + &bandwidth, aot, el, headerPeriod, + statesInitFlag, hSbrEncoder->downsamplingMethod, + hSbrEncoder->dynamicRam); + + if (error != 0) { + error = 2; + goto bail; + } + + /* Get lowest core encoder bandwidth to be returned later. */ + lowestBandwidth = fixMin(lowestBandwidth, bandwidth); + + } /* second element loop */ + + /* Initialize a downsampler for each channel in each SBR element */ + if (hSbrEncoder->downsamplingMethod == SBRENC_DS_TIME) { + for (el = 0; el < hSbrEncoder->noElements; el++) { + HANDLE_SBR_ELEMENT hSbrEl = hSbrEncoder->sbrElement[el]; + INT Wc, ch; + + Wc = 500; /* Cutoff frequency with full bandwidth */ + + for (ch = 0; ch < hSbrEl->elInfo.nChannelsInEl; ch++) { + FDKaacEnc_InitDownsampler(&hSbrEl->sbrChannel[ch]->downSampler, Wc, + *downSampleFactor); + FDK_ASSERT(hSbrEl->sbrChannel[ch]->downSampler.delay <= + MAX_DS_FILTER_DELAY); + } + } /* third element loop */ + + /* lfe */ + FDKaacEnc_InitDownsampler(&hSbrEncoder->lfeDownSampler, 0, + *downSampleFactor); + } + + /* Get delay information */ + delayParam.dsDelay = + hSbrEncoder->sbrElement[0]->sbrChannel[0]->downSampler.delay; + delayParam.delay = *delay; + + error = sbrEncoder_Init_delay(coreFrameLength, *numChannels, + *downSampleFactor, lowDelay, usePs, is212, + downsamplingMethod, &delayParam); + + if (error != 0) { + error = 3; + goto bail; + } + + hSbrEncoder->nBitstrDelay = delayParam.bitstrDelay; + hSbrEncoder->sbrDecDelay = delayParam.sbrDecDelay; + hSbrEncoder->inputDataDelay = delayParam.delayInput2Core; + + /* Assign core encoder Bandwidth */ + *coreBandwidth = lowestBandwidth; + + /* Estimate sbr bitrate, 2.5 kBit/s per sbr channel */ + hSbrEncoder->estimateBitrate += 2500 * (*numChannels); + + /* Initialize bitstream buffer for each element */ + for (el = 0; el < hSbrEncoder->noElements; el++) { + FDKsbrEnc_bsBufInit(hSbrEncoder->sbrElement[el], delayParam.bitstrDelay); + } + + /* initialize parametric stereo */ + if (usePs) { + PSENC_CONFIG psEncConfig; + FDK_ASSERT(hSbrEncoder->noElements == 1); + INT psTuningTableIdx = getPsTuningTableIndex(elInfo[0].bitRate, NULL); + + psEncConfig.frameSize = coreFrameLength; // sbrConfig.sbrFrameSize; + psEncConfig.qmfFilterMode = 0; + psEncConfig.sbrPsDelay = 0; + + /* tuning parameters */ + if (psTuningTableIdx != INVALID_TABLE_IDX) { + psEncConfig.nStereoBands = psTuningTable[psTuningTableIdx].nStereoBands; + psEncConfig.maxEnvelopes = psTuningTable[psTuningTableIdx].nEnvelopes; + psEncConfig.iidQuantErrorThreshold = + (FIXP_DBL)psTuningTable[psTuningTableIdx].iidQuantErrorThreshold; + + /* calculation is not quite linear, increased number of envelopes causes + * more bits */ + /* assume avg. 50 bits per frame for 10 stereo bands / 1 envelope + * configuration */ + hSbrEncoder->estimateBitrate += + ((((*coreSampleRate) * 5 * psEncConfig.nStereoBands * + psEncConfig.maxEnvelopes) / + hSbrEncoder->frameSize)); + + } else { + error = ERROR(CDI, "Invalid ps tuning table index."); + goto bail; + } + + qmfInitSynthesisFilterBank( + &hSbrEncoder->qmfSynthesisPS, + (FIXP_DBL *)hSbrEncoder->qmfSynthesisPS.FilterStates, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands >> 1, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands >> 1, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands >> 1, + (statesInitFlag) ? 0 : QMF_FLAG_KEEP_STATES); + + if (errorInfo == noError) { + /* update delay */ + psEncConfig.sbrPsDelay = + FDKsbrEnc_GetEnvEstDelay(&hSbrEncoder->sbrElement[0] + ->sbrChannel[0] + ->hEnvChannel.sbrExtractEnvelope); + + errorInfo = + PSEnc_Init(hSbrEncoder->hParametricStereo, &psEncConfig, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands, + hSbrEncoder->dynamicRam); + } + } + + hSbrEncoder->downsampledOffset = delayParam.corePathOffset; + hSbrEncoder->bufferOffset = delayParam.sbrPathOffset; + *delay = delayParam.delay; + + { hSbrEncoder->downmixSize = coreFrameLength * (*numChannels); } + + /* Delay Compensation: fill bitstream delay buffer with zero input signal */ + if (hSbrEncoder->nBitstrDelay > 0) { + error = FDKsbrEnc_DelayCompensation(hSbrEncoder, inputBuffer, + inputBufferBufSize); + if (error != 0) goto bail; + } + + /* Set Output frame length */ + *frameLength = coreFrameLength * *downSampleFactor; + /* Input buffer offset */ + *inputBufferOffset = + fixMax(delayParam.sbrPathOffset, delayParam.corePathOffset); + } + + return error; + +bail: + /* Restore input settings */ + *coreSampleRate = inputSampleRate; + *frameLength = coreFrameLength; + *numChannels = inputChannels; + *coreBandwidth = inputBandWidth; + + return error; +} + +INT sbrEncoder_EncodeFrame(HANDLE_SBR_ENCODER hSbrEncoder, INT_PCM *samples, + UINT samplesBufSize, UINT sbrDataBits[(8)], + UCHAR sbrData[(8)][MAX_PAYLOAD_SIZE]) { + INT error; + int el; + + for (el = 0; el < hSbrEncoder->noElements; el++) { + if (hSbrEncoder->sbrElement[el] != NULL) { + error = FDKsbrEnc_EnvEncodeFrame( + hSbrEncoder, el, + samples + hSbrEncoder->downsampledOffset / hSbrEncoder->nChannels, + samplesBufSize, &sbrDataBits[el], sbrData[el], 0); + if (error) return error; + } + } + + error = FDKsbrEnc_Downsample( + hSbrEncoder, + samples + hSbrEncoder->downsampledOffset / hSbrEncoder->nChannels, + samplesBufSize, hSbrEncoder->nChannels, &sbrDataBits[el], sbrData[el], 0); + if (error) return error; + + return 0; +} + +INT sbrEncoder_UpdateBuffers(HANDLE_SBR_ENCODER hSbrEncoder, + INT_PCM *timeBuffer, UINT timeBufferBufSize) { + if (hSbrEncoder->downsampledOffset > 0) { + int c; + int nd = hSbrEncoder->downmixSize / hSbrEncoder->nChannels; + + for (c = 0; c < hSbrEncoder->nChannels; c++) { + /* Move delayed downsampled data */ + FDKmemcpy(timeBuffer + timeBufferBufSize * c, + timeBuffer + timeBufferBufSize * c + nd, + sizeof(INT_PCM) * + (hSbrEncoder->downsampledOffset / hSbrEncoder->nChannels)); + } + } else { + int c; + + for (c = 0; c < hSbrEncoder->nChannels; c++) { + /* Move delayed input data */ + FDKmemcpy( + timeBuffer + timeBufferBufSize * c, + timeBuffer + timeBufferBufSize * c + hSbrEncoder->frameSize, + sizeof(INT_PCM) * hSbrEncoder->bufferOffset / hSbrEncoder->nChannels); + } + } + if (hSbrEncoder->nBitstrDelay > 0) { + int el; + + for (el = 0; el < hSbrEncoder->noElements; el++) { + FDKmemmove( + hSbrEncoder->sbrElement[el]->payloadDelayLine[0], + hSbrEncoder->sbrElement[el]->payloadDelayLine[1], + sizeof(UCHAR) * (hSbrEncoder->nBitstrDelay * MAX_PAYLOAD_SIZE)); + + FDKmemmove(&hSbrEncoder->sbrElement[el]->payloadDelayLineSize[0], + &hSbrEncoder->sbrElement[el]->payloadDelayLineSize[1], + sizeof(UINT) * (hSbrEncoder->nBitstrDelay)); + } + } + return 0; +} + +INT sbrEncoder_SendHeader(HANDLE_SBR_ENCODER hSbrEncoder) { + INT error = -1; + if (hSbrEncoder) { + int el; + for (el = 0; el < hSbrEncoder->noElements; el++) { + if ((hSbrEncoder->noElements == 1) && + (hSbrEncoder->sbrElement[0]->elInfo.fParametricStereo == 1)) { + hSbrEncoder->sbrElement[el]->sbrBitstreamData.CountSendHeaderData = + hSbrEncoder->sbrElement[el]->sbrBitstreamData.NrSendHeaderData - 1; + } else { + hSbrEncoder->sbrElement[el]->sbrBitstreamData.CountSendHeaderData = 0; + } + } + error = 0; + } + return error; +} + +INT sbrEncoder_ContainsHeader(HANDLE_SBR_ENCODER hSbrEncoder) { + INT sbrHeader = 1; + if (hSbrEncoder) { + int el; + for (el = 0; el < hSbrEncoder->noElements; el++) { + sbrHeader &= + (hSbrEncoder->sbrElement[el]->sbrBitstreamData.HeaderActiveDelay == 1) + ? 1 + : 0; + } + } + return sbrHeader; +} + +INT sbrEncoder_GetHeaderDelay(HANDLE_SBR_ENCODER hSbrEncoder) { + INT delay = -1; + + if (hSbrEncoder) { + if ((hSbrEncoder->noElements == 1) && + (hSbrEncoder->sbrElement[0]->elInfo.fParametricStereo == 1)) { + delay = hSbrEncoder->nBitstrDelay + 1; + } else { + delay = hSbrEncoder->nBitstrDelay; + } + } + return delay; +} +INT sbrEncoder_GetBsDelay(HANDLE_SBR_ENCODER hSbrEncoder) { + INT delay = -1; + + if (hSbrEncoder) { + delay = hSbrEncoder->nBitstrDelay; + } + return delay; +} + +INT sbrEncoder_SAPPrepare(HANDLE_SBR_ENCODER hSbrEncoder) { + INT error = -1; + if (hSbrEncoder) { + int el; + for (el = 0; el < hSbrEncoder->noElements; el++) { + hSbrEncoder->sbrElement[el]->sbrBitstreamData.rightBorderFIX = 1; + } + error = 0; + } + return error; +} + +INT sbrEncoder_GetEstimateBitrate(HANDLE_SBR_ENCODER hSbrEncoder) { + INT estimateBitrate = 0; + + if (hSbrEncoder) { + estimateBitrate += hSbrEncoder->estimateBitrate; + } + + return estimateBitrate; +} + +INT sbrEncoder_GetInputDataDelay(HANDLE_SBR_ENCODER hSbrEncoder) { + INT delay = -1; + + if (hSbrEncoder) { + delay = hSbrEncoder->inputDataDelay; + } + return delay; +} + +INT sbrEncoder_GetSbrDecDelay(HANDLE_SBR_ENCODER hSbrEncoder) { + INT delay = -1; + + if (hSbrEncoder) { + delay = hSbrEncoder->sbrDecDelay; + } + return delay; +} + +INT sbrEncoder_GetLibInfo(LIB_INFO *info) { + int i; + + if (info == NULL) { + return -1; + } + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) { + return -1; + } + info += i; + + info->module_id = FDK_SBRENC; + info->version = + LIB_VERSION(SBRENCODER_LIB_VL0, SBRENCODER_LIB_VL1, SBRENCODER_LIB_VL2); + LIB_VERSION_STRING(info); +#ifdef __ANDROID__ + info->build_date = ""; + info->build_time = ""; +#else + info->build_date = __DATE__; + info->build_time = __TIME__; +#endif + info->title = "SBR Encoder"; + + /* Set flags */ + info->flags = 0 | CAPF_SBR_HQ | CAPF_SBR_PS_MPEG; + /* End of flags */ + + return 0; +} diff --git a/fdk-aac/libSBRenc/src/sbr_misc.cpp b/fdk-aac/libSBRenc/src/sbr_misc.cpp new file mode 100644 index 0000000..83d7e36 --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbr_misc.cpp @@ -0,0 +1,265 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Sbr miscellaneous helper functions $Revision: 36750 $ +*/ +#include "sbr_misc.h" + +void FDKsbrEnc_Shellsort_fract(FIXP_DBL *in, INT n) { + FIXP_DBL v; + INT i, j; + INT inc = 1; + + do + inc = 3 * inc + 1; + while (inc <= n); + + do { + inc = inc / 3; + for (i = inc + 1; i <= n; i++) { + v = in[i - 1]; + j = i; + while (in[j - inc - 1] > v) { + in[j - 1] = in[j - inc - 1]; + j -= inc; + if (j <= inc) break; + } + in[j - 1] = v; + } + } while (inc > 1); +} + +/* Sorting routine */ +void FDKsbrEnc_Shellsort_int(INT *in, INT n) { + INT i, j, v; + INT inc = 1; + + do + inc = 3 * inc + 1; + while (inc <= n); + + do { + inc = inc / 3; + for (i = inc + 1; i <= n; i++) { + v = in[i - 1]; + j = i; + while (in[j - inc - 1] > v) { + in[j - 1] = in[j - inc - 1]; + j -= inc; + if (j <= inc) break; + } + in[j - 1] = v; + } + } while (inc > 1); +} + +/******************************************************************************* + Functionname: FDKsbrEnc_AddVecLeft + ******************************************************************************* + + Description: + + Arguments: INT* dst, INT* length_dst, INT* src, INT length_src + + Return: none + +*******************************************************************************/ +void FDKsbrEnc_AddVecLeft(INT *dst, INT *length_dst, INT *src, INT length_src) { + INT i; + + for (i = length_src - 1; i >= 0; i--) + FDKsbrEnc_AddLeft(dst, length_dst, src[i]); +} + +/******************************************************************************* + Functionname: FDKsbrEnc_AddLeft + ******************************************************************************* + + Description: + + Arguments: INT* vector, INT* length_vector, INT value + + Return: none + +*******************************************************************************/ +void FDKsbrEnc_AddLeft(INT *vector, INT *length_vector, INT value) { + INT i; + + for (i = *length_vector; i > 0; i--) vector[i] = vector[i - 1]; + vector[0] = value; + (*length_vector)++; +} + +/******************************************************************************* + Functionname: FDKsbrEnc_AddRight + ******************************************************************************* + + Description: + + Arguments: INT* vector, INT* length_vector, INT value + + Return: none + +*******************************************************************************/ +void FDKsbrEnc_AddRight(INT *vector, INT *length_vector, INT value) { + vector[*length_vector] = value; + (*length_vector)++; +} + +/******************************************************************************* + Functionname: FDKsbrEnc_AddVecRight + ******************************************************************************* + + Description: + + Arguments: INT* dst, INT* length_dst, INT* src, INT length_src) + + Return: none + +*******************************************************************************/ +void FDKsbrEnc_AddVecRight(INT *dst, INT *length_dst, INT *src, + INT length_src) { + INT i; + for (i = 0; i < length_src; i++) FDKsbrEnc_AddRight(dst, length_dst, src[i]); +} + +/***************************************************************************** + + functionname: FDKsbrEnc_LSI_divide_scale_fract + + description: Calculates division with best precision and scales the result. + + return: num*scale/denom + +*****************************************************************************/ +FIXP_DBL FDKsbrEnc_LSI_divide_scale_fract(FIXP_DBL num, FIXP_DBL denom, + FIXP_DBL scale) { + FIXP_DBL tmp = FL2FXCONST_DBL(0.0f); + if (num != FL2FXCONST_DBL(0.0f)) { + INT shiftCommon; + INT shiftNum = CountLeadingBits(num); + INT shiftDenom = CountLeadingBits(denom); + INT shiftScale = CountLeadingBits(scale); + + num = num << shiftNum; + scale = scale << shiftScale; + + tmp = fMultDiv2(num, scale); + + if (denom > (tmp >> fixMin(shiftNum + shiftScale - 1, (DFRACT_BITS - 1)))) { + denom = denom << shiftDenom; + tmp = schur_div(tmp, denom, 15); + shiftCommon = + fixMin((shiftNum - shiftDenom + shiftScale - 1), (DFRACT_BITS - 1)); + if (shiftCommon < 0) + tmp <<= -shiftCommon; + else + tmp >>= shiftCommon; + } else { + tmp = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL; + } + } + + return (tmp); +} diff --git a/fdk-aac/libSBRenc/src/sbr_misc.h b/fdk-aac/libSBRenc/src/sbr_misc.h new file mode 100644 index 0000000..fad853f --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbr_misc.h @@ -0,0 +1,127 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Sbr miscellaneous helper functions prototypes $Revision: 92790 $ + \author +*/ + +#ifndef SBR_MISC_H +#define SBR_MISC_H + +#include "sbr_encoder.h" + +/* Sorting routines */ +void FDKsbrEnc_Shellsort_fract(FIXP_DBL *in, INT n); +void FDKsbrEnc_Shellsort_int(INT *in, INT n); + +void FDKsbrEnc_AddLeft(INT *vector, INT *length_vector, INT value); +void FDKsbrEnc_AddRight(INT *vector, INT *length_vector, INT value); +void FDKsbrEnc_AddVecLeft(INT *dst, INT *length_dst, INT *src, INT length_src); +void FDKsbrEnc_AddVecRight(INT *dst, INT *length_vector_dst, INT *src, + INT length_src); + +FIXP_DBL FDKsbrEnc_LSI_divide_scale_fract(FIXP_DBL num, FIXP_DBL denom, + FIXP_DBL scale); + +#endif diff --git a/fdk-aac/libSBRenc/src/sbrenc_freq_sca.cpp b/fdk-aac/libSBRenc/src/sbrenc_freq_sca.cpp new file mode 100644 index 0000000..c86e047 --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbrenc_freq_sca.cpp @@ -0,0 +1,674 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief frequency scale $Revision: 95225 $ +*/ + +#include "sbrenc_freq_sca.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +/* StartFreq */ +static INT getStartFreq(INT fsCore, const INT start_freq); + +/* StopFreq */ +static INT getStopFreq(INT fsCore, const INT stop_freq); + +static INT numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor); +static void CalcBands(INT *diff, INT start, INT stop, INT num_bands); +static INT modifyBands(INT max_band, INT *diff, INT length); +static void cumSum(INT start_value, INT *diff, INT length, UCHAR *start_adress); + +/******************************************************************************* + Functionname: FDKsbrEnc_getSbrStartFreqRAW + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ + +INT FDKsbrEnc_getSbrStartFreqRAW(INT startFreq, INT fsCore) { + INT result; + + if (startFreq < 0 || startFreq > 15) { + return -1; + } + /* Update startFreq struct */ + result = getStartFreq(fsCore, startFreq); + + result = + (result * (fsCore >> 5) + 1) >> 1; /* (result*fsSBR/QMFbands+1)>>1; */ + + return (result); + +} /* End FDKsbrEnc_getSbrStartFreqRAW */ + +/******************************************************************************* + Functionname: getSbrStopFreq + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT FDKsbrEnc_getSbrStopFreqRAW(INT stopFreq, INT fsCore) { + INT result; + + if (stopFreq < 0 || stopFreq > 13) return -1; + + /* Uppdate stopFreq struct */ + result = getStopFreq(fsCore, stopFreq); + result = + (result * (fsCore >> 5) + 1) >> 1; /* (result*fsSBR/QMFbands+1)>>1; */ + + return (result); +} /* End getSbrStopFreq */ + +/******************************************************************************* + Functionname: getStartFreq + ******************************************************************************* + Description: + + Arguments: fsCore - core sampling rate + + + Return: + *******************************************************************************/ +static INT getStartFreq(INT fsCore, const INT start_freq) { + INT k0_min; + + switch (fsCore) { + case 8000: + k0_min = 24; /* (3000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + case 11025: + k0_min = 17; /* (3000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + case 12000: + k0_min = 16; /* (3000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + case 16000: + k0_min = 16; /* (4000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + case 22050: + k0_min = 12; /* (4000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + case 24000: + k0_min = 11; /* (4000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + case 32000: + k0_min = 10; /* (5000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + case 44100: + k0_min = 7; /* (5000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + case 48000: + k0_min = 7; /* (5000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + case 96000: + k0_min = 3; /* (5000 * nQmfChannels / fsSBR ) + 0.5 */ + break; + default: + k0_min = 11; /* illegal fs */ + } + + switch (fsCore) { + case 8000: { + INT v_offset[] = {-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}; + return (k0_min + v_offset[start_freq]); + } + case 11025: { + INT v_offset[] = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13}; + return (k0_min + v_offset[start_freq]); + } + case 12000: { + INT v_offset[] = {-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}; + return (k0_min + v_offset[start_freq]); + } + case 16000: { + INT v_offset[] = {-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}; + return (k0_min + v_offset[start_freq]); + } + case 22050: + case 24000: + case 32000: { + INT v_offset[] = {-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20}; + return (k0_min + v_offset[start_freq]); + } + case 44100: + case 48000: + case 96000: { + INT v_offset[] = {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24}; + return (k0_min + v_offset[start_freq]); + } + default: { + INT v_offset[] = {0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24, 28, 33}; + return (k0_min + v_offset[start_freq]); + } + } +} /* End getStartFreq */ + +/******************************************************************************* + Functionname: getStopFreq + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +static INT getStopFreq(INT fsCore, const INT stop_freq) { + INT result, i; + INT k1_min; + INT v_dstop[13]; + + INT *v_stop_freq = NULL; + INT v_stop_freq_16[14] = {48, 49, 50, 51, 52, 54, 55, + 56, 57, 59, 60, 61, 63, 64}; + INT v_stop_freq_22[14] = {35, 37, 38, 40, 42, 44, 46, + 48, 51, 53, 56, 58, 61, 64}; + INT v_stop_freq_24[14] = {32, 34, 36, 38, 40, 42, 44, + 46, 49, 52, 55, 58, 61, 64}; + INT v_stop_freq_32[14] = {32, 34, 36, 38, 40, 42, 44, + 46, 49, 52, 55, 58, 61, 64}; + INT v_stop_freq_44[14] = {23, 25, 27, 29, 32, 34, 37, + 40, 43, 47, 51, 55, 59, 64}; + INT v_stop_freq_48[14] = {21, 23, 25, 27, 30, 32, 35, + 38, 42, 45, 49, 54, 59, 64}; + INT v_stop_freq_64[14] = {20, 22, 24, 26, 29, 31, 34, + 37, 41, 45, 49, 54, 59, 64}; + INT v_stop_freq_88[14] = {15, 17, 19, 21, 23, 26, 29, + 33, 37, 41, 46, 51, 57, 64}; + INT v_stop_freq_96[14] = {13, 15, 17, 19, 21, 24, 27, + 31, 35, 39, 44, 50, 57, 64}; + INT v_stop_freq_192[14] = {7, 8, 10, 12, 14, 16, 19, + 23, 27, 32, 38, 46, 54, 64}; + + switch (fsCore) { + case 8000: + k1_min = 48; + v_stop_freq = v_stop_freq_16; + break; + case 11025: + k1_min = 35; + v_stop_freq = v_stop_freq_22; + break; + case 12000: + k1_min = 32; + v_stop_freq = v_stop_freq_24; + break; + case 16000: + k1_min = 32; + v_stop_freq = v_stop_freq_32; + break; + case 22050: + k1_min = 23; + v_stop_freq = v_stop_freq_44; + break; + case 24000: + k1_min = 21; + v_stop_freq = v_stop_freq_48; + break; + case 32000: + k1_min = 20; + v_stop_freq = v_stop_freq_64; + break; + case 44100: + k1_min = 15; + v_stop_freq = v_stop_freq_88; + break; + case 48000: + k1_min = 13; + v_stop_freq = v_stop_freq_96; + break; + case 96000: + k1_min = 7; + v_stop_freq = v_stop_freq_192; + break; + default: + k1_min = 21; /* illegal fs */ + } + + /* Ensure increasing bandwidth */ + for (i = 0; i <= 12; i++) { + v_dstop[i] = v_stop_freq[i + 1] - v_stop_freq[i]; + } + + FDKsbrEnc_Shellsort_int(v_dstop, 13); /* Sort bandwidth changes */ + + result = k1_min; + for (i = 0; i < stop_freq; i++) { + result = result + v_dstop[i]; + } + + return (result); + +} /* End getStopFreq */ + +/******************************************************************************* + Functionname: FDKsbrEnc_FindStartAndStopBand + ******************************************************************************* + Description: + + Arguments: srSbr SBR sampling freqency + srCore AAC core sampling freqency + noChannels Number of QMF channels + startFreq SBR start frequency in QMF bands + stopFreq SBR start frequency in QMF bands + + *k0 Output parameter + *k2 Output parameter + + Return: Error code (0 is OK) + *******************************************************************************/ +INT FDKsbrEnc_FindStartAndStopBand(const INT srSbr, const INT srCore, + const INT noChannels, const INT startFreq, + const INT stopFreq, INT *k0, INT *k2) { + /* Update startFreq struct */ + *k0 = getStartFreq(srCore, startFreq); + + /* Test if start freq is outside corecoder range */ + if (srSbr * noChannels < *k0 * srCore) { + return ( + 1); /* raise the cross-over frequency and/or lower the number + of target bands per octave (or lower the sampling frequency) */ + } + + /*Update stopFreq struct */ + if (stopFreq < 14) { + *k2 = getStopFreq(srCore, stopFreq); + } else if (stopFreq == 14) { + *k2 = 2 * *k0; + } else { + *k2 = 3 * *k0; + } + + /* limit to Nyqvist */ + if (*k2 > noChannels) { + *k2 = noChannels; + } + + /* Test for invalid k0 k2 combinations */ + if ((srCore == 22050) && ((*k2 - *k0) > MAX_FREQ_COEFFS_FS44100)) + return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for + fs=44.1kHz */ + + if ((srCore >= 24000) && ((*k2 - *k0) > MAX_FREQ_COEFFS_FS48000)) + return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for + fs>=48kHz */ + + if ((*k2 - *k0) > MAX_FREQ_COEFFS) + return (1); /*Number of bands exceeds valid range of MAX_FREQ_COEFFS */ + + if ((*k2 - *k0) < 0) return (1); /* Number of bands is negative */ + + return (0); +} + +/******************************************************************************* + Functionname: FDKsbrEnc_UpdateFreqScale + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT FDKsbrEnc_UpdateFreqScale(UCHAR *v_k_master, INT *h_num_bands, const INT k0, + const INT k2, const INT freqScale, + const INT alterScale) + +{ + INT b_p_o = 0; /* bands_per_octave */ + FIXP_DBL warp = FL2FXCONST_DBL(0.0f); + INT dk = 0; + + /* Internal variables */ + INT k1 = 0, i; + INT num_bands0; + INT num_bands1; + INT diff_tot[MAX_OCTAVE + MAX_SECOND_REGION]; + INT *diff0 = diff_tot; + INT *diff1 = diff_tot + MAX_OCTAVE; + INT k2_achived; + INT k2_diff; + INT incr = 0; + + /* Init */ + if (freqScale == 1) b_p_o = 12; + if (freqScale == 2) b_p_o = 10; + if (freqScale == 3) b_p_o = 8; + + if (freqScale > 0) /*Bark*/ + { + if (alterScale == 0) + warp = FL2FXCONST_DBL(0.5f); /* 1.0/(1.0*2.0) */ + else + warp = FL2FXCONST_DBL(1.0f / 2.6f); /* 1.0/(1.3*2.0); */ + + if (4 * k2 >= 9 * k0) /*two or more regions (how many times the basis band + is copied)*/ + { + k1 = 2 * k0; + + num_bands0 = numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f)); + num_bands1 = numberOfBands(b_p_o, k1, k2, warp); + + CalcBands(diff0, k0, k1, num_bands0); /*CalcBands1 => diff0 */ + FDKsbrEnc_Shellsort_int(diff0, num_bands0); /*SortBands sort diff0 */ + + if (diff0[0] == 0) /* too wide FB bands for target tuning */ + { + return (1); /* raise the cross-over frequency and/or lower the number + of target bands per octave (or lower the sampling + frequency */ + } + + cumSum(k0, diff0, num_bands0, v_k_master); /* cumsum */ + + CalcBands(diff1, k1, k2, num_bands1); /* CalcBands2 => diff1 */ + FDKsbrEnc_Shellsort_int(diff1, num_bands1); /* SortBands sort diff1 */ + if (diff0[num_bands0 - 1] > diff1[0]) /* max(1) > min(2) */ + { + if (modifyBands(diff0[num_bands0 - 1], diff1, num_bands1)) return (1); + } + + /* Add 2'nd region */ + cumSum(k1, diff1, num_bands1, &v_k_master[num_bands0]); + *h_num_bands = num_bands0 + num_bands1; /* Output nr of bands */ + + } else /* one region */ + { + k1 = k2; + + num_bands0 = numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f)); + CalcBands(diff0, k0, k1, num_bands0); /* CalcBands1 => diff0 */ + FDKsbrEnc_Shellsort_int(diff0, num_bands0); /* SortBands sort diff0 */ + + if (diff0[0] == 0) /* too wide FB bands for target tuning */ + { + return (1); /* raise the cross-over frequency and/or lower the number + of target bands per octave (or lower the sampling + frequency */ + } + + cumSum(k0, diff0, num_bands0, v_k_master); /* cumsum */ + *h_num_bands = num_bands0; /* Output nr of bands */ + } + } else /* Linear mode */ + { + if (alterScale == 0) { + dk = 1; + num_bands0 = 2 * ((k2 - k0) / 2); /* FLOOR to get to few number of bands*/ + } else { + dk = 2; + num_bands0 = + 2 * (((k2 - k0) / dk + 1) / 2); /* ROUND to get closest fit */ + } + + k2_achived = k0 + num_bands0 * dk; + k2_diff = k2 - k2_achived; + + for (i = 0; i < num_bands0; i++) diff_tot[i] = dk; + + /* If linear scale wasn't achived */ + /* and we got wide SBR are */ + if (k2_diff < 0) { + incr = 1; + i = 0; + } + + /* If linear scale wasn't achived */ + /* and we got small SBR are */ + if (k2_diff > 0) { + incr = -1; + i = num_bands0 - 1; + } + + /* Adjust diff vector to get sepc. SBR range */ + while (k2_diff != 0) { + diff_tot[i] = diff_tot[i] - incr; + i = i + incr; + k2_diff = k2_diff + incr; + } + + cumSum(k0, diff_tot, num_bands0, v_k_master); /* cumsum */ + *h_num_bands = num_bands0; /* Output nr of bands */ + } + + if (*h_num_bands < 1) return (1); /*To small sbr area */ + + return (0); +} /* End FDKsbrEnc_UpdateFreqScale */ + +static INT numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor) { + INT result = 0; + /* result = 2* (INT) ( (double)b_p_o * + * (double)(FDKlog((double)stop/(double)start)/FDKlog((double)2)) * + * (double)FX_DBL2FL(warp_factor) + 0.5); */ + result = ((b_p_o * fMult((CalcLdInt(stop) - CalcLdInt(start)), warp_factor) + + (FL2FX_DBL(0.5f) >> LD_DATA_SHIFT)) >> + ((DFRACT_BITS - 1) - LD_DATA_SHIFT)) + << 1; /* do not optimize anymore (rounding!!) */ + + return (result); +} + +static void CalcBands(INT *diff, INT start, INT stop, INT num_bands) { + INT i, qb, qe, qtmp; + INT previous; + INT current; + FIXP_DBL base, exp, tmp; + + previous = start; + for (i = 1; i <= num_bands; i++) { + base = fDivNorm((FIXP_DBL)stop, (FIXP_DBL)start, &qb); + exp = fDivNorm((FIXP_DBL)i, (FIXP_DBL)num_bands, &qe); + tmp = fPow(base, qb, exp, qe, &qtmp); + tmp = fMult(tmp, (FIXP_DBL)(start << 24)); + current = (INT)scaleValue(tmp, qtmp - 23); + current = (current + 1) >> 1; /* rounding*/ + diff[i - 1] = current - previous; + previous = current; + } + +} /* End CalcBands */ + +static void cumSum(INT start_value, INT *diff, INT length, + UCHAR *start_adress) { + INT i; + start_adress[0] = start_value; + for (i = 1; i <= length; i++) + start_adress[i] = start_adress[i - 1] + diff[i - 1]; +} /* End cumSum */ + +static INT modifyBands(INT max_band_previous, INT *diff, INT length) { + INT change = max_band_previous - diff[0]; + + /* Limit the change so that the last band cannot get narrower than the first + * one */ + if (change > (diff[length - 1] - diff[0]) / 2) + change = (diff[length - 1] - diff[0]) / 2; + + diff[0] += change; + diff[length - 1] -= change; + FDKsbrEnc_Shellsort_int(diff, length); + + return (0); +} /* End modifyBands */ + +/******************************************************************************* + Functionname: FDKsbrEnc_UpdateHiRes + ******************************************************************************* + Description: + + + Arguments: + + Return: + *******************************************************************************/ +INT FDKsbrEnc_UpdateHiRes(UCHAR *h_hires, INT *num_hires, UCHAR *v_k_master, + INT num_master, INT *xover_band) { + INT i; + INT max1, max2; + + if ((v_k_master[*xover_band] > + 32) || /* v_k_master[*xover_band] > noQMFChannels(dualRate)/divider */ + (*xover_band > num_master)) { + /* xover_band error, too big for this startFreq. Will be clipped */ + + /* Calculate maximum value for xover_band */ + max1 = 0; + max2 = num_master; + while ((v_k_master[max1 + 1] < 32) && /* noQMFChannels(dualRate)/divider */ + ((max1 + 1) < max2)) { + max1++; + } + + *xover_band = max1; + } + + *num_hires = num_master - *xover_band; + for (i = *xover_band; i <= num_master; i++) { + h_hires[i - *xover_band] = v_k_master[i]; + } + + return (0); +} /* End FDKsbrEnc_UpdateHiRes */ + +/******************************************************************************* + Functionname: FDKsbrEnc_UpdateLoRes + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +void FDKsbrEnc_UpdateLoRes(UCHAR *h_lores, INT *num_lores, UCHAR *h_hires, + INT num_hires) { + INT i; + + if (num_hires % 2 == 0) /* if even number of hires bands */ + { + *num_lores = num_hires / 2; + /* Use every second lores=hires[0,2,4...] */ + for (i = 0; i <= *num_lores; i++) h_lores[i] = h_hires[i * 2]; + + } else /* odd number of hires which means xover is odd */ + { + *num_lores = (num_hires + 1) / 2; + + /* Use lores=hires[0,1,3,5 ...] */ + h_lores[0] = h_hires[0]; + for (i = 1; i <= *num_lores; i++) { + h_lores[i] = h_hires[i * 2 - 1]; + } + } + +} /* End FDKsbrEnc_UpdateLoRes */ diff --git a/fdk-aac/libSBRenc/src/sbrenc_freq_sca.h b/fdk-aac/libSBRenc/src/sbrenc_freq_sca.h new file mode 100644 index 0000000..9b8d360 --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbrenc_freq_sca.h @@ -0,0 +1,132 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief frequency scale prototypes $Revision: 92790 $ +*/ +#ifndef SBRENC_FREQ_SCA_H +#define SBRENC_FREQ_SCA_H + +#include "sbr_encoder.h" +#include "sbr_def.h" + +#define MAX_OCTAVE 29 +#define MAX_SECOND_REGION 50 + +INT FDKsbrEnc_UpdateFreqScale(UCHAR *v_k_master, INT *h_num_bands, const INT k0, + const INT k2, const INT freq_scale, + const INT alter_scale); + +INT FDKsbrEnc_UpdateHiRes(UCHAR *h_hires, INT *num_hires, UCHAR *v_k_master, + INT num_master, INT *xover_band); + +void FDKsbrEnc_UpdateLoRes(UCHAR *v_lores, INT *num_lores, UCHAR *v_hires, + INT num_hires); + +INT FDKsbrEnc_FindStartAndStopBand(const INT srSbr, const INT srCore, + const INT noChannels, const INT startFreq, + const INT stop_freq, INT *k0, INT *k2); + +INT FDKsbrEnc_getSbrStartFreqRAW(INT startFreq, INT fsCore); +INT FDKsbrEnc_getSbrStopFreqRAW(INT stopFreq, INT fsCore); +#endif diff --git a/fdk-aac/libSBRenc/src/sbrenc_ram.cpp b/fdk-aac/libSBRenc/src/sbrenc_ram.cpp new file mode 100644 index 0000000..fb30fa2 --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbrenc_ram.cpp @@ -0,0 +1,249 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Memory layout + $Revision: 92864 $ + + This module declares all static and dynamic memory spaces +*/ +#include "sbrenc_ram.h" + +#include "sbr.h" +#include "genericStds.h" + +C_AALLOC_MEM(Ram_SbrDynamic_RAM, FIXP_DBL, + ((SBR_ENC_DYN_RAM_SIZE) / sizeof(FIXP_DBL))) + +/*! + \name StaticSbrData + + Static memory areas, must not be overwritten in other sections of the encoder +*/ +/* @{ */ + +/*! static sbr encoder instance for one encoder (2 channels) + all major static and dynamic memory areas are located + in module sbr_ram and sbr rom +*/ +C_ALLOC_MEM(Ram_SbrEncoder, SBR_ENCODER, 1) +C_ALLOC_MEM2(Ram_SbrChannel, SBR_CHANNEL, 1, (8)) +C_ALLOC_MEM2(Ram_SbrElement, SBR_ELEMENT, 1, (8)) + +/*! Filter states for QMF-analysis. <br> + Dimension: #MAXNRSBRCHANNELS * #SBR_QMF_FILTER_LENGTH +*/ +C_AALLOC_MEM2_L(Ram_Sbr_QmfStatesAnalysis, FIXP_QAS, 640, (8), SECT_DATA_L1) + +/*! Matrix holding the quota values for all estimates, all channels + Dimension #MAXNRSBRCHANNELS * +#SBR_QMF_CHANNELS* #MAX_NO_OF_ESTIMATES +*/ +C_ALLOC_MEM2_L(Ram_Sbr_quotaMatrix, FIXP_DBL, (MAX_NO_OF_ESTIMATES * 64), (8), + SECT_DATA_L1) + +/*! Matrix holding the sign values for all estimates, all channels + Dimension #MAXNRSBRCHANNELS * +#SBR_QMF_CHANNELS* #MAX_NO_OF_ESTIMATES +*/ +C_ALLOC_MEM2(Ram_Sbr_signMatrix, INT, (MAX_NO_OF_ESTIMATES * 64), (8)) + +/*! Frequency band table (low res) <br> + Dimension #MAX_FREQ_COEFFS/2+1 +*/ +C_ALLOC_MEM2(Ram_Sbr_freqBandTableLO, UCHAR, (MAX_FREQ_COEFFS / 2 + 1), (8)) + +/*! Frequency band table (high res) <br> + Dimension #MAX_FREQ_COEFFS +1 +*/ +C_ALLOC_MEM2(Ram_Sbr_freqBandTableHI, UCHAR, (MAX_FREQ_COEFFS + 1), (8)) + +/*! vk matser table <br> + Dimension #MAX_FREQ_COEFFS +1 +*/ +C_ALLOC_MEM2(Ram_Sbr_v_k_master, UCHAR, (MAX_FREQ_COEFFS + 1), (8)) + +/* + Missing harmonics detection +*/ + +/*! sbr_detectionVectors <br> + Dimension #MAX_NUM_CHANNELS*#MAX_NO_OF_ESTIMATES*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2(Ram_Sbr_detectionVectors, UCHAR, + (MAX_NO_OF_ESTIMATES * MAX_FREQ_COEFFS), (8)) + +/*! sbr_prevCompVec[ <br> + Dimension #MAX_NUM_CHANNELS*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2(Ram_Sbr_prevEnvelopeCompensation, UCHAR, MAX_FREQ_COEFFS, (8)) +/*! sbr_guideScfb[ <br> + Dimension #MAX_NUM_CHANNELS*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2(Ram_Sbr_guideScfb, UCHAR, MAX_FREQ_COEFFS, (8)) + +/*! sbr_guideVectorDetected <br> + Dimension #MAX_NUM_CHANNELS*#MAX_NO_OF_ESTIMATES*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2(Ram_Sbr_guideVectorDetected, UCHAR, + (MAX_NO_OF_ESTIMATES * MAX_FREQ_COEFFS), (8)) +C_ALLOC_MEM2(Ram_Sbr_guideVectorDiff, FIXP_DBL, + (MAX_NO_OF_ESTIMATES * MAX_FREQ_COEFFS), (8)) +C_ALLOC_MEM2(Ram_Sbr_guideVectorOrig, FIXP_DBL, + (MAX_NO_OF_ESTIMATES * MAX_FREQ_COEFFS), (8)) + +/* + Static Parametric Stereo memory +*/ +C_AALLOC_MEM_L(Ram_PsQmfStatesSynthesis, FIXP_DBL, 640 / 2, SECT_DATA_L1) + +C_ALLOC_MEM_L(Ram_PsEncode, PS_ENCODE, 1, SECT_DATA_L1) +C_ALLOC_MEM(Ram_ParamStereo, PARAMETRIC_STEREO, 1) + +/* @} */ + +/*! + \name DynamicSbrData + + Dynamic memory areas, might be reused in other algorithm sections, + e.g. the core encoder. +*/ +/* @{ */ + +/*! Energy buffer for envelope extraction <br> + Dimension #MAXNRSBRCHANNELS * +#SBR_QMF_SLOTS * #SBR_QMF_CHANNELS +*/ +C_ALLOC_MEM2(Ram_Sbr_envYBuffer, FIXP_DBL, (32 / 2 * 64), (8)) + +FIXP_DBL* GetRam_Sbr_envYBuffer(int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM != 0); + /* The reinterpret_cast is used to suppress a compiler warning. We know that + * (dynamic_RAM + OFFSET_NRG + (n*Y_2_BUF_BYTE)) is sufficiently aligned, so + * the cast is safe */ + return reinterpret_cast<FIXP_DBL*>( + reinterpret_cast<void*>(dynamic_RAM + OFFSET_NRG + (n * Y_2_BUF_BYTE))); +} + +/* + * QMF data + */ +/* The SBR encoder uses a single channel overlapping buffer set (always n=0), + * but PS does not. */ +FIXP_DBL* GetRam_Sbr_envRBuffer(int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM != 0); + /* The reinterpret_cast is used to suppress a compiler warning. We know that + * (dynamic_RAM + OFFSET_QMF + (n*(ENV_R_BUFF_BYTE+ENV_I_BUFF_BYTE))) is + * sufficiently aligned, so the cast is safe */ + return reinterpret_cast<FIXP_DBL*>(reinterpret_cast<void*>( + dynamic_RAM + OFFSET_QMF + (n * (ENV_R_BUFF_BYTE + ENV_I_BUFF_BYTE)))); +} +FIXP_DBL* GetRam_Sbr_envIBuffer(int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM != 0); + /* The reinterpret_cast is used to suppress a compiler warning. We know that + * (dynamic_RAM + OFFSET_QMF + (ENV_R_BUFF_BYTE) + + * (n*(ENV_R_BUFF_BYTE+ENV_I_BUFF_BYTE))) is sufficiently aligned, so the cast + * is safe */ + return reinterpret_cast<FIXP_DBL*>( + reinterpret_cast<void*>(dynamic_RAM + OFFSET_QMF + (ENV_R_BUFF_BYTE) + + (n * (ENV_R_BUFF_BYTE + ENV_I_BUFF_BYTE)))); +} + +/* @} */ diff --git a/fdk-aac/libSBRenc/src/sbrenc_ram.h b/fdk-aac/libSBRenc/src/sbrenc_ram.h new file mode 100644 index 0000000..cf23378 --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbrenc_ram.h @@ -0,0 +1,199 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! +\file +\brief Memory layout +$Revision: 92790 $ +*/ +#ifndef SBRENC_RAM_H +#define SBRENC_RAM_H + +#include "sbr_def.h" +#include "env_est.h" +#include "sbr_encoder.h" +#include "sbr.h" + +#include "ps_main.h" +#include "ps_encode.h" + +#define ENV_TRANSIENTS_BYTE ((sizeof(FIXP_DBL) * (MAX_NUM_CHANNELS * 3 * 32))) + +#define ENV_R_BUFF_BYTE ((sizeof(FIXP_DBL) * ((32) * MAX_HYBRID_BANDS))) +#define ENV_I_BUFF_BYTE ((sizeof(FIXP_DBL) * ((32) * MAX_HYBRID_BANDS))) +#define Y_BUF_CH_BYTE \ + ((2 * sizeof(FIXP_DBL) * (((32) - (32 / 2)) * MAX_HYBRID_BANDS))) + +#define ENV_R_BUF_PS_BYTE ((sizeof(FIXP_DBL) * 32 * 64 / 2)) +#define ENV_I_BUF_PS_BYTE ((sizeof(FIXP_DBL) * 32 * 64 / 2)) + +#define TON_BUF_CH_BYTE \ + ((sizeof(FIXP_DBL) * (MAX_NO_OF_ESTIMATES * MAX_FREQ_COEFFS))) + +#define Y_2_BUF_BYTE (Y_BUF_CH_BYTE) + +/* Workbuffer RAM - Allocation */ +/* + ++++++++++++++++++++++++++++++++++++++++++++++++++++ + | OFFSET_QMF | OFFSET_NRG | + ++++++++++++++++++++++++++++++++++++++++++++++++++++ + ------------------------- ------------------------- + | | 0.5 * | + | sbr_envRBuffer | sbr_envYBuffer_size | + | sbr_envIBuffer | | + ------------------------- ------------------------- + +*/ +#define BUF_NRG_SIZE ((MAX_NUM_CHANNELS * Y_2_BUF_BYTE)) +#define BUF_QMF_SIZE (ENV_R_BUFF_BYTE + ENV_I_BUFF_BYTE) + +/* Size of the shareable memory region than can be reused */ +#define SBR_ENC_DYN_RAM_SIZE (BUF_QMF_SIZE + BUF_NRG_SIZE) + +#define OFFSET_QMF (0) +#define OFFSET_NRG (OFFSET_QMF + BUF_QMF_SIZE) + +/* + ***************************************************************************************************** + */ + +H_ALLOC_MEM(Ram_SbrDynamic_RAM, FIXP_DBL) + +H_ALLOC_MEM(Ram_SbrEncoder, SBR_ENCODER) +H_ALLOC_MEM(Ram_SbrChannel, SBR_CHANNEL) +H_ALLOC_MEM(Ram_SbrElement, SBR_ELEMENT) + +H_ALLOC_MEM(Ram_Sbr_quotaMatrix, FIXP_DBL) +H_ALLOC_MEM(Ram_Sbr_signMatrix, INT) + +H_ALLOC_MEM(Ram_Sbr_QmfStatesAnalysis, FIXP_QAS) + +H_ALLOC_MEM(Ram_Sbr_freqBandTableLO, UCHAR) +H_ALLOC_MEM(Ram_Sbr_freqBandTableHI, UCHAR) +H_ALLOC_MEM(Ram_Sbr_v_k_master, UCHAR) + +H_ALLOC_MEM(Ram_Sbr_detectionVectors, UCHAR) +H_ALLOC_MEM(Ram_Sbr_prevEnvelopeCompensation, UCHAR) +H_ALLOC_MEM(Ram_Sbr_guideScfb, UCHAR) +H_ALLOC_MEM(Ram_Sbr_guideVectorDetected, UCHAR) + +/* Dynamic Memory Allocation */ + +H_ALLOC_MEM(Ram_Sbr_envYBuffer, FIXP_DBL) +FIXP_DBL* GetRam_Sbr_envYBuffer(int n, UCHAR* dynamic_RAM); +FIXP_DBL* GetRam_Sbr_envRBuffer(int n, UCHAR* dynamic_RAM); +FIXP_DBL* GetRam_Sbr_envIBuffer(int n, UCHAR* dynamic_RAM); + +H_ALLOC_MEM(Ram_Sbr_guideVectorDiff, FIXP_DBL) +H_ALLOC_MEM(Ram_Sbr_guideVectorOrig, FIXP_DBL) + +H_ALLOC_MEM(Ram_PsQmfStatesSynthesis, FIXP_DBL) + +H_ALLOC_MEM(Ram_PsEncode, PS_ENCODE) + +FIXP_DBL* FDKsbrEnc_SliceRam_PsRqmf(FIXP_DBL* rQmfData, UCHAR* dynamic_RAM, + int n, int i, int qmfSlots); +FIXP_DBL* FDKsbrEnc_SliceRam_PsIqmf(FIXP_DBL* iQmfData, UCHAR* dynamic_RAM, + int n, int i, int qmfSlots); + +H_ALLOC_MEM(Ram_ParamStereo, PARAMETRIC_STEREO) +#endif diff --git a/fdk-aac/libSBRenc/src/sbrenc_rom.cpp b/fdk-aac/libSBRenc/src/sbrenc_rom.cpp new file mode 100644 index 0000000..737afaf --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbrenc_rom.cpp @@ -0,0 +1,910 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): Tobias Chalupka + + Description: Definition of constant tables + +*******************************************************************************/ + +/*! + \file + \brief Definition of constant tables + $Revision: 95404 $ + + This module contains most of the constant data that can be stored in ROM. +*/ + +#include "sbrenc_rom.h" +#include "genericStds.h" + +//@{ +/******************************************************************************* + + Table Overview: + + o envelope level, 1.5 dB: + 1a) v_Huff_envelopeLevelC10T[121] + 1b) v_Huff_envelopeLevelL10T[121] + 2a) v_Huff_envelopeLevelC10F[121] + 2b) v_Huff_envelopeLevelL10F[121] + + o envelope balance, 1.5 dB: + 3a) bookSbrEnvBalanceC10T[49] + 3b) bookSbrEnvBalanceL10T[49] + 4a) bookSbrEnvBalanceC10F[49] + 4b) bookSbrEnvBalanceL10F[49] + + o envelope level, 3.0 dB: + 5a) v_Huff_envelopeLevelC11T[63] + 5b) v_Huff_envelopeLevelL11T[63] + 6a) v_Huff_envelopeLevelC11F[63] + 6b) v_Huff_envelopeLevelC11F[63] + + o envelope balance, 3.0 dB: + 7a) bookSbrEnvBalanceC11T[25] + 7b) bookSbrEnvBalanceL11T[25] + 8a) bookSbrEnvBalanceC11F[25] + 8b) bookSbrEnvBalanceL11F[25] + + o noise level, 3.0 dB: + 9a) v_Huff_NoiseLevelC11T[63] + 9b) v_Huff_NoiseLevelL11T[63] + - ) (v_Huff_envelopeLevelC11F[63] is used for freq dir) + - ) (v_Huff_envelopeLevelL11F[63] is used for freq dir) + + o noise balance, 3.0 dB: + 10a) bookSbrNoiseBalanceC11T[25] + 10b) bookSbrNoiseBalanceL11T[25] + - ) (bookSbrEnvBalanceC11F[25] is used for freq dir) + - ) (bookSbrEnvBalanceL11F[25] is used for freq dir) + + + (1.5 dB is never used for noise) + +********************************************************************************/ + +/*******************************************************************************/ +/* table : envelope level, 1.5 dB */ +/* theor range : [-58,58], CODE_BOOK_SCF_LAV = 58 */ +/* implem range: [-60,60], CODE_BOOK_SCF_LAV10 = 60 */ +/* raw stats : envelopeLevel_00 (yes, wrong suffix in name) KK 01-03-09 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C2FIX.m/envelopeLevel_00T_cF.mat/v_nChex_cF + built by : FH 01-07-05 */ + +const INT v_Huff_envelopeLevelC10T[121] = { + 0x0003FFD6, 0x0003FFD7, 0x0003FFD8, 0x0003FFD9, 0x0003FFDA, 0x0003FFDB, + 0x0007FFB8, 0x0007FFB9, 0x0007FFBA, 0x0007FFBB, 0x0007FFBC, 0x0007FFBD, + 0x0007FFBE, 0x0007FFBF, 0x0007FFC0, 0x0007FFC1, 0x0007FFC2, 0x0007FFC3, + 0x0007FFC4, 0x0007FFC5, 0x0007FFC6, 0x0007FFC7, 0x0007FFC8, 0x0007FFC9, + 0x0007FFCA, 0x0007FFCB, 0x0007FFCC, 0x0007FFCD, 0x0007FFCE, 0x0007FFCF, + 0x0007FFD0, 0x0007FFD1, 0x0007FFD2, 0x0007FFD3, 0x0001FFE6, 0x0003FFD4, + 0x0000FFF0, 0x0001FFE9, 0x0003FFD5, 0x0001FFE7, 0x0000FFF1, 0x0000FFEC, + 0x0000FFED, 0x0000FFEE, 0x00007FF4, 0x00003FF9, 0x00003FF7, 0x00001FFA, + 0x00001FF9, 0x00000FFB, 0x000007FC, 0x000003FC, 0x000001FD, 0x000000FD, + 0x0000007D, 0x0000003D, 0x0000001D, 0x0000000D, 0x00000005, 0x00000001, + 0x00000000, 0x00000004, 0x0000000C, 0x0000001C, 0x0000003C, 0x0000007C, + 0x000000FC, 0x000001FC, 0x000003FD, 0x00000FFA, 0x00001FF8, 0x00003FF6, + 0x00003FF8, 0x00007FF5, 0x0000FFEF, 0x0001FFE8, 0x0000FFF2, 0x0007FFD4, + 0x0007FFD5, 0x0007FFD6, 0x0007FFD7, 0x0007FFD8, 0x0007FFD9, 0x0007FFDA, + 0x0007FFDB, 0x0007FFDC, 0x0007FFDD, 0x0007FFDE, 0x0007FFDF, 0x0007FFE0, + 0x0007FFE1, 0x0007FFE2, 0x0007FFE3, 0x0007FFE4, 0x0007FFE5, 0x0007FFE6, + 0x0007FFE7, 0x0007FFE8, 0x0007FFE9, 0x0007FFEA, 0x0007FFEB, 0x0007FFEC, + 0x0007FFED, 0x0007FFEE, 0x0007FFEF, 0x0007FFF0, 0x0007FFF1, 0x0007FFF2, + 0x0007FFF3, 0x0007FFF4, 0x0007FFF5, 0x0007FFF6, 0x0007FFF7, 0x0007FFF8, + 0x0007FFF9, 0x0007FFFA, 0x0007FFFB, 0x0007FFFC, 0x0007FFFD, 0x0007FFFE, + 0x0007FFFF}; + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C2FIX.m/envelopeLevel_00T_cF.mat/v_nLhex_cF + built by : FH 01-07-05 */ + +const UCHAR v_Huff_envelopeLevelL10T[121] = { + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x11, 0x12, 0x10, 0x11, 0x12, 0x11, 0x10, 0x10, 0x10, 0x10, + 0x0F, 0x0E, 0x0E, 0x0D, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, + 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0C, 0x0D, 0x0E, 0x0E, 0x0F, 0x10, 0x11, 0x10, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13}; + +/* direction: freq + contents : codewords + raw table: HuffCode3C2FIX.m/envelopeLevel_00F_cF.mat/v_nChex_cF + built by : FH 01-07-05 */ + +const INT v_Huff_envelopeLevelC10F[121] = { + 0x0007FFE7, 0x0007FFE8, 0x000FFFD2, 0x000FFFD3, 0x000FFFD4, 0x000FFFD5, + 0x000FFFD6, 0x000FFFD7, 0x000FFFD8, 0x0007FFDA, 0x000FFFD9, 0x000FFFDA, + 0x000FFFDB, 0x000FFFDC, 0x0007FFDB, 0x000FFFDD, 0x0007FFDC, 0x0007FFDD, + 0x000FFFDE, 0x0003FFE4, 0x000FFFDF, 0x000FFFE0, 0x000FFFE1, 0x0007FFDE, + 0x000FFFE2, 0x000FFFE3, 0x000FFFE4, 0x0007FFDF, 0x000FFFE5, 0x0007FFE0, + 0x0003FFE8, 0x0007FFE1, 0x0003FFE0, 0x0003FFE9, 0x0001FFEF, 0x0003FFE5, + 0x0001FFEC, 0x0001FFED, 0x0001FFEE, 0x0000FFF4, 0x0000FFF3, 0x0000FFF0, + 0x00007FF7, 0x00007FF6, 0x00003FFA, 0x00001FFA, 0x00001FF9, 0x00000FFA, + 0x00000FF8, 0x000007F9, 0x000003FB, 0x000001FC, 0x000001FA, 0x000000FB, + 0x0000007C, 0x0000003C, 0x0000001C, 0x0000000C, 0x00000005, 0x00000001, + 0x00000000, 0x00000004, 0x0000000D, 0x0000001D, 0x0000003D, 0x000000FA, + 0x000000FC, 0x000001FB, 0x000003FA, 0x000007F8, 0x000007FA, 0x000007FB, + 0x00000FF9, 0x00000FFB, 0x00001FF8, 0x00001FFB, 0x00003FF8, 0x00003FF9, + 0x0000FFF1, 0x0000FFF2, 0x0001FFEA, 0x0001FFEB, 0x0003FFE1, 0x0003FFE2, + 0x0003FFEA, 0x0003FFE3, 0x0003FFE6, 0x0003FFE7, 0x0003FFEB, 0x000FFFE6, + 0x0007FFE2, 0x000FFFE7, 0x000FFFE8, 0x000FFFE9, 0x000FFFEA, 0x000FFFEB, + 0x000FFFEC, 0x0007FFE3, 0x000FFFED, 0x000FFFEE, 0x000FFFEF, 0x000FFFF0, + 0x0007FFE4, 0x000FFFF1, 0x0003FFEC, 0x000FFFF2, 0x000FFFF3, 0x0007FFE5, + 0x0007FFE6, 0x000FFFF4, 0x000FFFF5, 0x000FFFF6, 0x000FFFF7, 0x000FFFF8, + 0x000FFFF9, 0x000FFFFA, 0x000FFFFB, 0x000FFFFC, 0x000FFFFD, 0x000FFFFE, + 0x000FFFFF}; + +/* direction: freq + contents : codeword lengths + raw table: HuffCode3C2FIX.m/envelopeLevel_00F_cF.mat/v_nLhex_cF + built by : FH 01-07-05 */ + +const UCHAR v_Huff_envelopeLevelL10F[121] = { + 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, + 0x14, 0x14, 0x14, 0x13, 0x14, 0x13, 0x13, 0x14, 0x12, 0x14, 0x14, + 0x14, 0x13, 0x14, 0x14, 0x14, 0x13, 0x14, 0x13, 0x12, 0x13, 0x12, + 0x12, 0x11, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x0F, 0x0F, + 0x0E, 0x0D, 0x0D, 0x0C, 0x0C, 0x0B, 0x0A, 0x09, 0x09, 0x08, 0x07, + 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, + 0x08, 0x09, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, + 0x0E, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x14, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, + 0x14, 0x14, 0x14, 0x13, 0x14, 0x12, 0x14, 0x14, 0x13, 0x13, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14}; + +/*******************************************************************************/ +/* table : envelope balance, 1.5 dB */ +/* theor range : [-48,48], CODE_BOOK_SCF_LAV = 48 */ +/* implem range: same but mapped to [-24,24], CODE_BOOK_SCF_LAV_BALANCE10 = 24 + */ +/* raw stats : envelopePan_00 (yes, wrong suffix in name) KK 01-03-09 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C.m/envelopePan_00T.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC10T[49] = { + 0x0000FFE4, 0x0000FFE5, 0x0000FFE6, 0x0000FFE7, 0x0000FFE8, 0x0000FFE9, + 0x0000FFEA, 0x0000FFEB, 0x0000FFEC, 0x0000FFED, 0x0000FFEE, 0x0000FFEF, + 0x0000FFF0, 0x0000FFF1, 0x0000FFF2, 0x0000FFF3, 0x0000FFF4, 0x0000FFE2, + 0x00000FFC, 0x000007FC, 0x000001FE, 0x0000007E, 0x0000001E, 0x00000006, + 0x00000000, 0x00000002, 0x0000000E, 0x0000003E, 0x000000FE, 0x000007FD, + 0x00000FFD, 0x00007FF0, 0x0000FFE3, 0x0000FFF5, 0x0000FFF6, 0x0000FFF7, + 0x0000FFF8, 0x0000FFF9, 0x0000FFFA, 0x0001FFF6, 0x0001FFF7, 0x0001FFF8, + 0x0001FFF9, 0x0001FFFA, 0x0001FFFB, 0x0001FFFC, 0x0001FFFD, 0x0001FFFE, + 0x0001FFFF}; + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C.m/envelopePan_00T.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL10T[49] = { + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0C, 0x0B, + 0x09, 0x07, 0x05, 0x03, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0B, + 0x0C, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}; + +/* direction: freq + contents : codewords + raw table: HuffCode3C.m/envelopePan_00F.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC10F[49] = { + 0x0003FFE2, 0x0003FFE3, 0x0003FFE4, 0x0003FFE5, 0x0003FFE6, 0x0003FFE7, + 0x0003FFE8, 0x0003FFE9, 0x0003FFEA, 0x0003FFEB, 0x0003FFEC, 0x0003FFED, + 0x0003FFEE, 0x0003FFEF, 0x0003FFF0, 0x0000FFF7, 0x0001FFF0, 0x00003FFC, + 0x000007FE, 0x000007FC, 0x000000FE, 0x0000007E, 0x0000000E, 0x00000002, + 0x00000000, 0x00000006, 0x0000001E, 0x0000003E, 0x000001FE, 0x000007FD, + 0x00000FFE, 0x00007FFA, 0x0000FFF6, 0x0003FFF1, 0x0003FFF2, 0x0003FFF3, + 0x0003FFF4, 0x0003FFF5, 0x0003FFF6, 0x0003FFF7, 0x0003FFF8, 0x0003FFF9, + 0x0003FFFA, 0x0003FFFB, 0x0003FFFC, 0x0003FFFD, 0x0003FFFE, 0x0007FFFE, + 0x0007FFFF}; + +/* direction: freq + contents : codeword lengths + raw table: HuffCode3C.m/envelopePan_00F.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL10F[49] = { + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x10, 0x11, 0x0E, 0x0B, 0x0B, + 0x08, 0x07, 0x04, 0x02, 0x01, 0x03, 0x05, 0x06, 0x09, 0x0B, + 0x0C, 0x0F, 0x10, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13}; + +/*******************************************************************************/ +/* table : envelope level, 3.0 dB */ +/* theor range : [-29,29], CODE_BOOK_SCF_LAV = 29 */ +/* implem range: [-31,31], CODE_BOOK_SCF_LAV11 = 31 */ +/* raw stats : envelopeLevel_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const INT v_Huff_envelopeLevelC11T[63] = { + 0x0003FFED, 0x0003FFEE, 0x0007FFDE, 0x0007FFDF, 0x0007FFE0, 0x0007FFE1, + 0x0007FFE2, 0x0007FFE3, 0x0007FFE4, 0x0007FFE5, 0x0007FFE6, 0x0007FFE7, + 0x0007FFE8, 0x0007FFE9, 0x0007FFEA, 0x0007FFEB, 0x0007FFEC, 0x0001FFF4, + 0x0000FFF7, 0x0000FFF9, 0x0000FFF8, 0x00003FFB, 0x00003FFA, 0x00003FF8, + 0x00001FFA, 0x00000FFC, 0x000007FC, 0x000000FE, 0x0000003E, 0x0000000E, + 0x00000002, 0x00000000, 0x00000006, 0x0000001E, 0x0000007E, 0x000001FE, + 0x000007FD, 0x00001FFB, 0x00003FF9, 0x00003FFC, 0x00007FFA, 0x0000FFF6, + 0x0001FFF5, 0x0003FFEC, 0x0007FFED, 0x0007FFEE, 0x0007FFEF, 0x0007FFF0, + 0x0007FFF1, 0x0007FFF2, 0x0007FFF3, 0x0007FFF4, 0x0007FFF5, 0x0007FFF6, + 0x0007FFF7, 0x0007FFF8, 0x0007FFF9, 0x0007FFFA, 0x0007FFFB, 0x0007FFFC, + 0x0007FFFD, 0x0007FFFE, 0x0007FFFF}; + +/* direction: time + contents : codeword lengths + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const UCHAR v_Huff_envelopeLevelL11T[63] = { + 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x11, 0x10, 0x10, 0x10, 0x0E, + 0x0E, 0x0E, 0x0D, 0x0C, 0x0B, 0x08, 0x06, 0x04, 0x02, 0x01, 0x03, + 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 0x0E, 0x0F, 0x10, 0x11, 0x12, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13}; + +/* direction: freq + contents : codewords + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const INT v_Huff_envelopeLevelC11F[63] = { + 0x000FFFF0, 0x000FFFF1, 0x000FFFF2, 0x000FFFF3, 0x000FFFF4, 0x000FFFF5, + 0x000FFFF6, 0x0003FFF3, 0x0007FFF5, 0x0007FFEE, 0x0007FFEF, 0x0007FFF6, + 0x0003FFF4, 0x0003FFF2, 0x000FFFF7, 0x0007FFF0, 0x0001FFF5, 0x0003FFF0, + 0x0001FFF4, 0x0000FFF7, 0x0000FFF6, 0x00007FF8, 0x00003FFB, 0x00000FFD, + 0x000007FD, 0x000003FD, 0x000001FD, 0x000000FD, 0x0000003E, 0x0000000E, + 0x00000002, 0x00000000, 0x00000006, 0x0000001E, 0x000000FC, 0x000001FC, + 0x000003FC, 0x000007FC, 0x00000FFC, 0x00001FFC, 0x00003FFA, 0x00007FF9, + 0x00007FFA, 0x0000FFF8, 0x0000FFF9, 0x0001FFF6, 0x0001FFF7, 0x0003FFF5, + 0x0003FFF6, 0x0003FFF1, 0x000FFFF8, 0x0007FFF1, 0x0007FFF2, 0x0007FFF3, + 0x000FFFF9, 0x0007FFF7, 0x0007FFF4, 0x000FFFFA, 0x000FFFFB, 0x000FFFFC, + 0x000FFFFD, 0x000FFFFE, 0x000FFFFF}; + +/* direction: freq + contents : codeword lengths + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const UCHAR v_Huff_envelopeLevelL11F[63] = { + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x12, 0x13, 0x13, 0x13, + 0x13, 0x12, 0x12, 0x14, 0x13, 0x11, 0x12, 0x11, 0x10, 0x10, 0x0F, + 0x0E, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01, 0x03, + 0x05, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x0F, 0x10, + 0x10, 0x11, 0x11, 0x12, 0x12, 0x12, 0x14, 0x13, 0x13, 0x13, 0x14, + 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14}; + +/*******************************************************************************/ +/* table : envelope balance, 3.0 dB */ +/* theor range : [-24,24], CODE_BOOK_SCF_LAV = 24 */ +/* implem range: same but mapped to [-12,12], CODE_BOOK_SCF_LAV_BALANCE11 = 12 + */ +/* raw stats : envelopeBalance_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C.m/envelopeBalance_11T.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC11T[25] = { + 0x00001FF2, 0x00001FF3, 0x00001FF4, 0x00001FF5, 0x00001FF6, + 0x00001FF7, 0x00001FF8, 0x00000FF8, 0x000000FE, 0x0000007E, + 0x0000000E, 0x00000006, 0x00000000, 0x00000002, 0x0000001E, + 0x0000003E, 0x000001FE, 0x00001FF9, 0x00001FFA, 0x00001FFB, + 0x00001FFC, 0x00001FFD, 0x00001FFE, 0x00003FFE, 0x00003FFF}; + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C.m/envelopeBalance_11T.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL11T[25] = { + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x08, + 0x07, 0x04, 0x03, 0x01, 0x02, 0x05, 0x06, 0x09, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E}; + +/* direction: freq + contents : codewords + raw table: HuffCode3C.m/envelopeBalance_11F.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC11F[25] = { + 0x00001FF7, 0x00001FF8, 0x00001FF9, 0x00001FFA, 0x00001FFB, + 0x00003FF8, 0x00003FF9, 0x000007FC, 0x000000FE, 0x0000007E, + 0x0000000E, 0x00000002, 0x00000000, 0x00000006, 0x0000001E, + 0x0000003E, 0x000001FE, 0x00000FFA, 0x00001FF6, 0x00003FFA, + 0x00003FFB, 0x00003FFC, 0x00003FFD, 0x00003FFE, 0x00003FFF}; + +/* direction: freq + contents : codeword lengths + raw table: HuffCode3C.m/envelopeBalance_11F.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL11F[25] = { + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0B, 0x08, + 0x07, 0x04, 0x02, 0x01, 0x03, 0x05, 0x06, 0x09, 0x0C, + 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E}; + +/*******************************************************************************/ +/* table : noise level, 3.0 dB */ +/* theor range : [-29,29], CODE_BOOK_SCF_LAV = 29 */ +/* implem range: [-31,31], CODE_BOOK_SCF_LAV11 = 31 */ +/* raw stats : noiseLevel_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const INT v_Huff_NoiseLevelC11T[63] = { + 0x00001FCE, 0x00001FCF, 0x00001FD0, 0x00001FD1, 0x00001FD2, 0x00001FD3, + 0x00001FD4, 0x00001FD5, 0x00001FD6, 0x00001FD7, 0x00001FD8, 0x00001FD9, + 0x00001FDA, 0x00001FDB, 0x00001FDC, 0x00001FDD, 0x00001FDE, 0x00001FDF, + 0x00001FE0, 0x00001FE1, 0x00001FE2, 0x00001FE3, 0x00001FE4, 0x00001FE5, + 0x00001FE6, 0x00001FE7, 0x000007F2, 0x000000FD, 0x0000003E, 0x0000000E, + 0x00000006, 0x00000000, 0x00000002, 0x0000001E, 0x000000FC, 0x000003F8, + 0x00001FCC, 0x00001FE8, 0x00001FE9, 0x00001FEA, 0x00001FEB, 0x00001FEC, + 0x00001FCD, 0x00001FED, 0x00001FEE, 0x00001FEF, 0x00001FF0, 0x00001FF1, + 0x00001FF2, 0x00001FF3, 0x00001FF4, 0x00001FF5, 0x00001FF6, 0x00001FF7, + 0x00001FF8, 0x00001FF9, 0x00001FFA, 0x00001FFB, 0x00001FFC, 0x00001FFD, + 0x00001FFE, 0x00003FFE, 0x00003FFF}; + +/* direction: time + contents : codeword lengths + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const UCHAR v_Huff_NoiseLevelL11T[63] = { + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000B, 0x00000008, 0x00000006, 0x00000004, + 0x00000003, 0x00000001, 0x00000002, 0x00000005, 0x00000008, 0x0000000A, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000E, 0x0000000E}; + +/*******************************************************************************/ +/* table : noise balance, 3.0 dB */ +/* theor range : [-24,24], CODE_BOOK_SCF_LAV = 24 */ +/* implem range: same but mapped to [-12,12], CODE_BOOK_SCF_LAV_BALANCE11 = 12 + */ +/* raw stats : noiseBalance_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C.m/noiseBalance_11.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrNoiseBalanceC11T[25] = { + 0x000000EC, 0x000000ED, 0x000000EE, 0x000000EF, 0x000000F0, + 0x000000F1, 0x000000F2, 0x000000F3, 0x000000F4, 0x000000F5, + 0x0000001C, 0x00000002, 0x00000000, 0x00000006, 0x0000003A, + 0x000000F6, 0x000000F7, 0x000000F8, 0x000000F9, 0x000000FA, + 0x000000FB, 0x000000FC, 0x000000FD, 0x000000FE, 0x000000FF}; + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C.m/noiseBalance_11.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrNoiseBalanceL11T[25] = { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x05, 0x02, 0x01, 0x03, 0x06, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; + +/* + tuningTable +*/ +const sbrTuningTable_t sbrTuningTable[] = { + /* Some of the low bitrates are commented out here, this is because the + encoder could lose frames at those bitrates and throw an error + because it has insufficient bits to encode for some test items. + */ + + /*** HE-AAC section ***/ + /* sf,sfsp,sf,sfsp,nnb,nfo,saml,SM,FS*/ + + /*** mono ***/ + + /* 8/16 kHz dual rate */ + {CODEC_AAC, 8000, 10000, 8000, 1, 7, 6, 11, 10, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 10000, 12000, 8000, 1, 11, 7, 13, 12, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 12000, 16001, 8000, 1, 14, 10, 13, 13, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 16000, 24000, 8000, 1, 14, 10, 14, 14, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 24000, 32000, 8000, 1, 14, 10, 14, 14, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 32000, 48001, 8000, 1, 14, 11, 15, 15, 2, 0, 3, SBR_MONO, 2}, + + /* 11/22 kHz dual rate */ + {CODEC_AAC, 8000, 10000, 11025, 1, 5, 4, 6, 6, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 10000, 12000, 11025, 1, 8, 5, 12, 9, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 12000, 16000, 11025, 1, 12, 8, 13, 8, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 16000, 20000, 11025, 1, 12, 8, 13, 8, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 20000, 24001, 11025, 1, 13, 9, 13, 8, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 24000, 32000, 11025, 1, 14, 10, 14, 9, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 32000, 48000, 11025, 1, 15, 11, 15, 10, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 48000, 64001, 11025, 1, 15, 11, 15, 10, 2, 0, 3, SBR_MONO, 1}, + + /* 12/24 kHz dual rate */ + {CODEC_AAC, 8000, 10000, 12000, 1, 4, 3, 6, 6, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 10000, 12000, 12000, 1, 7, 4, 11, 8, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 12000, 16000, 12000, 1, 11, 7, 12, 8, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 16000, 20000, 12000, 1, 11, 7, 12, 8, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 20000, 24001, 12000, 1, 12, 8, 12, 8, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 24000, 32000, 12000, 1, 13, 9, 13, 9, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 32000, 48000, 12000, 1, 14, 10, 14, 10, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 48000, 64001, 12000, 1, 14, 11, 15, 11, 2, 0, 3, SBR_MONO, 1}, + + /* 16/32 kHz dual rate */ + {CODEC_AAC, 8000, 10000, 16000, 1, 1, 1, 0, 0, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 10000, 12000, 16000, 1, 2, 1, 6, 0, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 12000, 16000, 16000, 1, 4, 2, 6, 0, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 16000, 18000, 16000, 1, 4, 2, 8, 3, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 18000, 22000, 16000, 1, 6, 5, 11, 7, 2, 0, 6, SBR_MONO, 2}, + {CODEC_AAC, 22000, 28000, 16000, 1, 10, 9, 12, 8, 2, 0, 6, SBR_MONO, 2}, + {CODEC_AAC, 28000, 36000, 16000, 1, 12, 12, 13, 13, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 36000, 44000, 16000, 1, 14, 14, 13, 13, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AAC, 44000, 64001, 16000, 1, 14, 14, 13, 13, 2, 0, 3, SBR_MONO, 1}, + + /* 22.05/44.1 kHz dual rate */ + /* { CODEC_AAC, 8000, 11369, 22050, 1, 1, 1, 1, 1, 1, 0, 6, + SBR_MONO, 3 }, */ + {CODEC_AAC, 11369, 16000, 22050, 1, 3, 1, 4, 4, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 16000, 18000, 22050, 1, 3, 1, 5, 4, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 18000, 22000, 22050, 1, 4, 4, 8, 5, 2, 0, 6, SBR_MONO, 2}, + {CODEC_AAC, 22000, 28000, 22050, 1, 7, 6, 8, 6, 2, 0, 6, SBR_MONO, 2}, + {CODEC_AAC, 28000, 36000, 22050, 1, 10, 10, 9, 9, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 36000, 44000, 22050, 1, 11, 11, 10, 10, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AAC, 44000, 64001, 22050, 1, 13, 13, 12, 12, 2, 0, 3, SBR_MONO, 1}, + + /* 24/48 kHz dual rate */ + /* { CODEC_AAC, 8000, 12000, 24000, 1, 1, 1, 1, 1, 1, 0, 6, + SBR_MONO, 3 }, */ + {CODEC_AAC, 12000, 16000, 24000, 1, 3, 1, 4, 4, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 16000, 18000, 24000, 1, 3, 1, 5, 4, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AAC, 18000, 22000, 24000, 1, 4, 3, 8, 5, 2, 0, 6, SBR_MONO, 2}, + {CODEC_AAC, 22000, 28000, 24000, 1, 7, 6, 8, 6, 2, 0, 6, SBR_MONO, 2}, + {CODEC_AAC, 28000, 36000, 24000, 1, 10, 10, 9, 9, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 36000, 44000, 24000, 1, 11, 11, 10, 10, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AAC, 44000, 64001, 24000, 1, 13, 13, 11, 11, 2, 0, 3, SBR_MONO, 1}, + + /* 32/64 kHz dual rate */ + {CODEC_AAC, 24000, 36000, 32000, 1, 4, 4, 4, 4, 2, 0, 3, SBR_MONO, 3}, + {CODEC_AAC, 36000, 60000, 32000, 1, 7, 7, 6, 6, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 60000, 72000, 32000, 1, 9, 9, 8, 8, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AAC, 72000, 100000, 32000, 1, 11, 11, 10, 10, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AAC, 100000, 160001, 32000, 1, 13, 13, 11, 11, 2, 0, 3, SBR_MONO, 1}, + + /* 44.1/88.2 kHz dual rate */ + {CODEC_AAC, 24000, 36000, 44100, 1, 4, 4, 4, 4, 2, 0, 3, SBR_MONO, 3}, + {CODEC_AAC, 36000, 60000, 44100, 1, 7, 7, 6, 6, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 60000, 72000, 44100, 1, 9, 9, 8, 8, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AAC, 72000, 100000, 44100, 1, 11, 11, 10, 10, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AAC, 100000, 160001, 44100, 1, 13, 13, 11, 11, 2, 0, 3, SBR_MONO, 1}, + + /* 48/96 kHz dual rate */ + {CODEC_AAC, 32000, 36000, 48000, 1, 4, 4, 9, 9, 2, 0, 3, SBR_MONO, 3}, + {CODEC_AAC, 36000, 60000, 48000, 1, 7, 7, 10, 10, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AAC, 60000, 72000, 48000, 1, 9, 9, 10, 10, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AAC, 72000, 100000, 48000, 1, 11, 11, 11, 11, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AAC, 100000, 160001, 48000, 1, 13, 13, 11, 11, 2, 0, 3, SBR_MONO, 1}, + + /*** stereo ***/ + /* 08/16 kHz dual rate */ + {CODEC_AAC, 16000, 24000, 8000, 2, 6, 6, 9, 7, 1, 0, -3, SBR_SWITCH_LRC, 3}, + {CODEC_AAC, 24000, 28000, 8000, 2, 9, 9, 11, 9, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 28000, 36000, 8000, 2, 11, 9, 11, 9, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 36000, 44000, 8000, 2, 13, 11, 13, 11, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 44000, 52000, 8000, 2, 14, 12, 13, 12, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 52000, 60000, 8000, 2, 14, 14, 13, 13, 3, 0, -3, SBR_SWITCH_LRC, + 1}, + {CODEC_AAC, 60000, 76000, 8000, 2, 14, 14, 13, 13, 3, 0, -3, SBR_LEFT_RIGHT, + 1}, + {CODEC_AAC, 76000, 128001, 8000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 11/22 kHz dual rate */ + {CODEC_AAC, 16000, 24000, 11025, 2, 7, 5, 9, 7, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 24000, 28000, 11025, 2, 10, 8, 10, 8, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 28000, 36000, 11025, 2, 12, 8, 12, 8, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 36000, 44000, 11025, 2, 13, 9, 13, 9, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 44000, 52000, 11025, 2, 14, 11, 13, 11, 2, 0, -3, + SBR_SWITCH_LRC, 2}, + {CODEC_AAC, 52000, 60000, 11025, 2, 15, 15, 13, 13, 3, 0, -3, + SBR_SWITCH_LRC, 1}, + {CODEC_AAC, 60000, 76000, 11025, 2, 15, 15, 13, 13, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AAC, 76000, 128001, 11025, 2, 15, 15, 13, 13, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 12/24 kHz dual rate */ + {CODEC_AAC, 16000, 24000, 12000, 2, 6, 4, 9, 7, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 24000, 28000, 12000, 2, 9, 7, 10, 8, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 28000, 36000, 12000, 2, 11, 7, 12, 8, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 36000, 44000, 12000, 2, 12, 9, 12, 9, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 44000, 52000, 12000, 2, 13, 12, 13, 12, 2, 0, -3, + SBR_SWITCH_LRC, 2}, + {CODEC_AAC, 52000, 60000, 12000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_SWITCH_LRC, 1}, + {CODEC_AAC, 60000, 76000, 12000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AAC, 76000, 128001, 12000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 16/32 kHz dual rate */ + {CODEC_AAC, 16000, 24000, 16000, 2, 4, 2, 1, 0, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 24000, 28000, 16000, 2, 8, 7, 10, 8, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 28000, 36000, 16000, 2, 10, 9, 12, 11, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 36000, 44000, 16000, 2, 13, 13, 13, 13, 2, 0, -3, + SBR_SWITCH_LRC, 2}, + {CODEC_AAC, 44000, 52000, 16000, 2, 14, 14, 13, 13, 2, 0, -3, + SBR_SWITCH_LRC, 2}, + {CODEC_AAC, 52000, 60000, 16000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_SWITCH_LRC, 1}, + {CODEC_AAC, 60000, 76000, 16000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AAC, 76000, 128001, 16000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 22.05/44.1 kHz dual rate */ + {CODEC_AAC, 16000, 24000, 22050, 2, 2, 1, 1, 0, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 24000, 28000, 22050, 2, 5, 4, 6, 5, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 28000, 32000, 22050, 2, 5, 4, 8, 7, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 32000, 36000, 22050, 2, 7, 6, 8, 7, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 36000, 44000, 22050, 2, 10, 10, 9, 9, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 44000, 52000, 22050, 2, 12, 12, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 52000, 60000, 22050, 2, 13, 13, 10, 10, 3, 0, -3, + SBR_SWITCH_LRC, 1}, + {CODEC_AAC, 60000, 76000, 22050, 2, 14, 14, 12, 12, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AAC, 76000, 128001, 22050, 2, 14, 14, 12, 12, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 24/48 kHz dual rate */ + {CODEC_AAC, 16000, 24000, 24000, 2, 2, 1, 1, 0, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 24000, 28000, 24000, 2, 5, 5, 6, 6, 1, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 28000, 36000, 24000, 2, 7, 6, 8, 7, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 36000, 44000, 24000, 2, 10, 10, 9, 9, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 44000, 52000, 24000, 2, 12, 12, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 52000, 60000, 24000, 2, 13, 13, 10, 10, 3, 0, -3, + SBR_SWITCH_LRC, 1}, + {CODEC_AAC, 60000, 76000, 24000, 2, 14, 14, 12, 12, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AAC, 76000, 128001, 24000, 2, 14, 14, 12, 12, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 32/64 kHz dual rate */ + {CODEC_AAC, 32000, 60000, 32000, 2, 4, 4, 4, 4, 2, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 60000, 80000, 32000, 2, 7, 7, 6, 6, 3, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 80000, 112000, 32000, 2, 9, 9, 8, 8, 3, 0, -3, SBR_LEFT_RIGHT, + 1}, + {CODEC_AAC, 112000, 144000, 32000, 2, 11, 11, 10, 10, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AAC, 144000, 256001, 32000, 2, 13, 13, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 44.1/88.2 kHz dual rate */ + {CODEC_AAC, 32000, 60000, 44100, 2, 4, 4, 4, 4, 2, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 60000, 80000, 44100, 2, 7, 7, 6, 6, 3, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 80000, 112000, 44100, 2, 9, 9, 8, 8, 3, 0, -3, SBR_LEFT_RIGHT, + 1}, + {CODEC_AAC, 112000, 144000, 44100, 2, 11, 11, 10, 10, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AAC, 144000, 256001, 44100, 2, 13, 13, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 48/96 kHz dual rate */ + {CODEC_AAC, 36000, 60000, 48000, 2, 4, 4, 9, 9, 2, 0, -3, SBR_SWITCH_LRC, + 3}, + {CODEC_AAC, 60000, 80000, 48000, 2, 7, 7, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AAC, 80000, 112000, 48000, 2, 9, 9, 10, 10, 3, 0, -3, SBR_LEFT_RIGHT, + 1}, + {CODEC_AAC, 112000, 144000, 48000, 2, 11, 11, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AAC, 144000, 256001, 48000, 2, 13, 13, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /** AAC LOW DELAY SECTION **/ + + /* 24 kHz dual rate - 12kHz singlerate is not allowed (deactivated in + FDKsbrEnc_IsSbrSettingAvail()) */ + {CODEC_AACLD, 8000, 32000, 12000, 1, 1, 1, 0, 0, 1, 0, 6, SBR_MONO, 3}, + + /*** mono ***/ + /* 16/32 kHz dual rate */ + {CODEC_AACLD, 16000, 18000, 16000, 1, 4, 5, 9, 7, 1, 0, 6, SBR_MONO, 3}, + {CODEC_AACLD, 18000, 22000, 16000, 1, 7, 7, 12, 12, 1, 6, 9, SBR_MONO, 3}, + {CODEC_AACLD, 22000, 28000, 16000, 1, 6, 6, 9, 9, 2, 3, 6, SBR_MONO, 3}, + {CODEC_AACLD, 28000, 36000, 16000, 1, 8, 8, 12, 7, 2, 9, 12, SBR_MONO, 3}, + {CODEC_AACLD, 36000, 44000, 16000, 1, 10, 14, 12, 13, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AACLD, 44000, 64001, 16000, 1, 11, 14, 13, 13, 2, 0, 3, SBR_MONO, 1}, + + /* 22.05/44.1 kHz dual rate */ + {CODEC_AACLD, 18000, 22000, 22050, 1, 4, 4, 5, 5, 2, 0, 6, SBR_MONO, 3}, + {CODEC_AACLD, 22000, 28000, 22050, 1, 5, 5, 6, 6, 2, 0, 6, SBR_MONO, 2}, + {CODEC_AACLD, 28000, 36000, 22050, 1, 7, 8, 8, 8, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AACLD, 36000, 44000, 22050, 1, 9, 9, 9, 9, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AACLD, 44000, 52000, 22050, 1, 12, 11, 11, 11, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AACLD, 52000, 64001, 22050, 1, 13, 11, 11, 10, 2, 0, 3, SBR_MONO, 1}, + + /* 24/48 kHz dual rate */ + {CODEC_AACLD, 20000, 22000, 24000, 1, 3, 4, 8, 8, 2, 0, 6, SBR_MONO, 2}, + {CODEC_AACLD, 22000, 28000, 24000, 1, 3, 8, 8, 7, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AACLD, 28000, 36000, 24000, 1, 4, 8, 8, 7, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AACLD, 36000, 56000, 24000, 1, 8, 9, 9, 8, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AACLD, 56000, 64001, 24000, 1, 13, 11, 11, 10, 2, 0, 3, SBR_MONO, 1}, + + /* 32/64 kHz dual rate */ + {CODEC_AACLD, 24000, 36000, 32000, 1, 4, 4, 4, 4, 2, 0, 3, SBR_MONO, 3}, + {CODEC_AACLD, 36000, 60000, 32000, 1, 7, 7, 6, 6, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AACLD, 60000, 72000, 32000, 1, 9, 9, 8, 8, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AACLD, 72000, 100000, 32000, 1, 11, 11, 10, 10, 2, 0, 3, SBR_MONO, + 1}, + {CODEC_AACLD, 100000, 160001, 32000, 1, 13, 13, 11, 11, 2, 0, 3, SBR_MONO, + 1}, + + /* 44/88 kHz dual rate */ + {CODEC_AACLD, 36000, 60000, 44100, 1, 8, 7, 6, 9, 2, 0, 3, SBR_MONO, 2}, + {CODEC_AACLD, 60000, 72000, 44100, 1, 9, 9, 10, 10, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AACLD, 72000, 100000, 44100, 1, 11, 11, 11, 11, 2, 0, 3, SBR_MONO, + 1}, + {CODEC_AACLD, 100000, 160001, 44100, 1, 13, 13, 11, 11, 2, 0, 3, SBR_MONO, + 1}, + + /* 48/96 kHz dual rate */ /* 32 and 40kbps line tuned for dual-rate SBR + */ + {CODEC_AACLD, 36000, 60000, 48000, 1, 4, 7, 4, 4, 2, 0, 3, SBR_MONO, 3}, + {CODEC_AACLD, 60000, 72000, 48000, 1, 9, 9, 10, 10, 2, 0, 3, SBR_MONO, 1}, + {CODEC_AACLD, 72000, 100000, 48000, 1, 11, 11, 11, 11, 2, 0, 3, SBR_MONO, + 1}, + {CODEC_AACLD, 100000, 160001, 48000, 1, 13, 13, 11, 11, 2, 0, 3, SBR_MONO, + 1}, + + /*** stereo ***/ + /* 16/32 kHz dual rate */ + {CODEC_AACLD, 32000, 36000, 16000, 2, 10, 9, 12, 11, 2, 0, -3, + SBR_SWITCH_LRC, 2}, + {CODEC_AACLD, 36000, 44000, 16000, 2, 13, 13, 13, 13, 2, 0, -3, + SBR_SWITCH_LRC, 2}, + {CODEC_AACLD, 44000, 52000, 16000, 2, 10, 9, 11, 9, 2, 0, -3, + SBR_SWITCH_LRC, 2}, + {CODEC_AACLD, 52000, 60000, 16000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_SWITCH_LRC, 1}, + {CODEC_AACLD, 60000, 76000, 16000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 76000, 128001, 16000, 2, 14, 14, 13, 13, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 22.05/44.1 kHz dual rate */ + {CODEC_AACLD, 32000, 36000, 22050, 2, 5, 4, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AACLD, 36000, 44000, 22050, 2, 5, 8, 8, 8, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AACLD, 44000, 52000, 22050, 2, 7, 10, 8, 8, 3, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AACLD, 52000, 60000, 22050, 2, 9, 11, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, + 1}, + {CODEC_AACLD, 60000, 76000, 22050, 2, 10, 12, 10, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 76000, 82000, 22050, 2, 12, 12, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 82000, 128001, 22050, 2, 13, 12, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 24/48 kHz dual rate */ + {CODEC_AACLD, 32000, 36000, 24000, 2, 5, 4, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AACLD, 36000, 44000, 24000, 2, 4, 8, 8, 8, 2, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AACLD, 44000, 52000, 24000, 2, 6, 10, 8, 8, 3, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AACLD, 52000, 60000, 24000, 2, 9, 11, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, + 1}, + {CODEC_AACLD, 60000, 76000, 24000, 2, 11, 12, 10, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 76000, 88000, 24000, 2, 12, 13, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 88000, 128001, 24000, 2, 13, 13, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 32/64 kHz dual rate */ + {CODEC_AACLD, 60000, 80000, 32000, 2, 7, 7, 6, 6, 3, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AACLD, 80000, 112000, 32000, 2, 9, 9, 8, 8, 3, 0, -3, SBR_LEFT_RIGHT, + 1}, + {CODEC_AACLD, 112000, 144000, 32000, 2, 11, 11, 10, 10, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 144000, 256001, 32000, 2, 13, 13, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 44.1/88.2 kHz dual rate */ + {CODEC_AACLD, 60000, 80000, 44100, 2, 7, 7, 6, 6, 3, 0, -3, SBR_SWITCH_LRC, + 2}, + {CODEC_AACLD, 80000, 112000, 44100, 2, 10, 10, 8, 8, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 112000, 144000, 44100, 2, 12, 12, 10, 10, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 144000, 256001, 44100, 2, 13, 13, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + + /* 48/96 kHz dual rate */ + {CODEC_AACLD, 60000, 80000, 48000, 2, 7, 7, 10, 10, 2, 0, -3, + SBR_SWITCH_LRC, 2}, + {CODEC_AACLD, 80000, 112000, 48000, 2, 9, 9, 10, 10, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 112000, 144000, 48000, 2, 11, 11, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 144000, 176000, 48000, 2, 12, 12, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + {CODEC_AACLD, 176000, 256001, 48000, 2, 13, 13, 11, 11, 3, 0, -3, + SBR_LEFT_RIGHT, 1}, + +}; + +const int sbrTuningTableSize = + sizeof(sbrTuningTable) / sizeof(sbrTuningTable[0]); + +const psTuningTable_t psTuningTable[4] = { + {8000, 22000, PSENC_STEREO_BANDS_10, PSENC_NENV_1, + FL2FXCONST_DBL(3.0f / 4.0f)}, + {22000, 28000, PSENC_STEREO_BANDS_20, PSENC_NENV_1, + FL2FXCONST_DBL(2.0f / 4.0f)}, + {28000, 36000, PSENC_STEREO_BANDS_20, PSENC_NENV_2, + FL2FXCONST_DBL(1.5f / 4.0f)}, + {36000, 160001, PSENC_STEREO_BANDS_20, PSENC_NENV_4, + FL2FXCONST_DBL(1.1f / 4.0f)}, +}; + +//@} diff --git a/fdk-aac/libSBRenc/src/sbrenc_rom.h b/fdk-aac/libSBRenc/src/sbrenc_rom.h new file mode 100644 index 0000000..18c1fb9 --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbrenc_rom.h @@ -0,0 +1,145 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! +\file +\brief Declaration of constant tables +$Revision: 92790 $ +*/ +#ifndef SBRENC_ROM_H +#define SBRENC_ROM_H + +#include "sbr_def.h" +#include "sbr_encoder.h" + +#include "ps_main.h" + +/* + huffman tables +*/ +extern const INT v_Huff_envelopeLevelC10T[121]; +extern const UCHAR v_Huff_envelopeLevelL10T[121]; +extern const INT v_Huff_envelopeLevelC10F[121]; +extern const UCHAR v_Huff_envelopeLevelL10F[121]; +extern const INT bookSbrEnvBalanceC10T[49]; +extern const UCHAR bookSbrEnvBalanceL10T[49]; +extern const INT bookSbrEnvBalanceC10F[49]; +extern const UCHAR bookSbrEnvBalanceL10F[49]; +extern const INT v_Huff_envelopeLevelC11T[63]; +extern const UCHAR v_Huff_envelopeLevelL11T[63]; +extern const INT v_Huff_envelopeLevelC11F[63]; +extern const UCHAR v_Huff_envelopeLevelL11F[63]; +extern const INT bookSbrEnvBalanceC11T[25]; +extern const UCHAR bookSbrEnvBalanceL11T[25]; +extern const INT bookSbrEnvBalanceC11F[25]; +extern const UCHAR bookSbrEnvBalanceL11F[25]; +extern const INT v_Huff_NoiseLevelC11T[63]; +extern const UCHAR v_Huff_NoiseLevelL11T[63]; +extern const INT bookSbrNoiseBalanceC11T[25]; +extern const UCHAR bookSbrNoiseBalanceL11T[25]; + +extern const sbrTuningTable_t sbrTuningTable[]; +extern const int sbrTuningTableSize; + +extern const psTuningTable_t psTuningTable[4]; + +#endif diff --git a/fdk-aac/libSBRenc/src/ton_corr.cpp b/fdk-aac/libSBRenc/src/ton_corr.cpp new file mode 100644 index 0000000..1c050e2 --- /dev/null +++ b/fdk-aac/libSBRenc/src/ton_corr.cpp @@ -0,0 +1,891 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "ton_corr.h" + +#include "sbrenc_ram.h" +#include "sbr_misc.h" +#include "genericStds.h" +#include "autocorr2nd.h" + +#define BAND_V_SIZE 32 +#define NUM_V_COMBINE \ + 8 /* Must be a divisor of 64 and fulfill the ASSERTs below */ + +/**************************************************************************/ +/*! + \brief Calculates the tonal to noise ration for different frequency bands + and time segments. + + The ratio between the predicted energy (tonal energy A) and the total + energy (A + B) is calculated. This is converted to the ratio between + the predicted energy (tonal energy A) and the non-predictable energy + (noise energy B). Hence the quota-matrix contains A/B = q/(1-q). + + The samples in nrgVector are scaled by 1.0/16.0 + The samples in pNrgVectorFreq are scaled by 1.0/2.0 + The samples in quotaMatrix are scaled by RELAXATION + + \return none. + +*/ +/**************************************************************************/ + +void FDKsbrEnc_CalculateTonalityQuotas( + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + FIXP_DBL **RESTRICT + sourceBufferReal, /*!< The real part of the QMF-matrix. */ + FIXP_DBL **RESTRICT + sourceBufferImag, /*!< The imaginary part of the QMF-matrix. */ + INT usb, /*!< upper side band, highest + 1 QMF band in the SBR range. */ + INT qmfScale /*!< sclefactor of QMF subsamples */ +) { + INT i, k, r, r2, timeIndex, autoCorrScaling; + + INT startIndexMatrix = hTonCorr->startIndexMatrix; + INT totNoEst = hTonCorr->numberOfEstimates; + INT noEstPerFrame = hTonCorr->numberOfEstimatesPerFrame; + INT move = hTonCorr->move; + INT noQmfChannels = hTonCorr->noQmfChannels; /* Number of Bands */ + INT buffLen = hTonCorr->bufferLength; /* Number of Slots */ + INT stepSize = hTonCorr->stepSize; + INT *pBlockLength = hTonCorr->lpcLength; + INT **RESTRICT signMatrix = hTonCorr->signMatrix; + FIXP_DBL *RESTRICT nrgVector = hTonCorr->nrgVector; + FIXP_DBL **RESTRICT quotaMatrix = hTonCorr->quotaMatrix; + FIXP_DBL *RESTRICT pNrgVectorFreq = hTonCorr->nrgVectorFreq; + + FIXP_DBL *realBuf; + FIXP_DBL *imagBuf; + + FIXP_DBL alphar[2], alphai[2], fac; + + C_ALLOC_SCRATCH_START(ac, ACORR_COEFS, 1) + C_ALLOC_SCRATCH_START(realBufRef, FIXP_DBL, 2 * BAND_V_SIZE * NUM_V_COMBINE) + realBuf = realBufRef; + imagBuf = realBuf + BAND_V_SIZE * NUM_V_COMBINE; + + FDK_ASSERT(buffLen <= BAND_V_SIZE); + FDK_ASSERT(sizeof(FIXP_DBL) * NUM_V_COMBINE * BAND_V_SIZE * 2 < + (1024 * sizeof(FIXP_DBL) - sizeof(ACORR_COEFS))); + + /* + * Buffering of the quotaMatrix and the quotaMatrixTransp. + *********************************************************/ + for (i = 0; i < move; i++) { + FDKmemcpy(quotaMatrix[i], quotaMatrix[i + noEstPerFrame], + noQmfChannels * sizeof(FIXP_DBL)); + FDKmemcpy(signMatrix[i], signMatrix[i + noEstPerFrame], + noQmfChannels * sizeof(INT)); + } + + FDKmemmove(nrgVector, nrgVector + noEstPerFrame, move * sizeof(FIXP_DBL)); + FDKmemclear(nrgVector + startIndexMatrix, + (totNoEst - startIndexMatrix) * sizeof(FIXP_DBL)); + FDKmemclear(pNrgVectorFreq, noQmfChannels * sizeof(FIXP_DBL)); + + /* + * Calculate the quotas for the current time steps. + **************************************************/ + + for (r = 0; r < usb; r++) { + int blockLength; + + k = hTonCorr->nextSample; /* startSample */ + timeIndex = startIndexMatrix; + /* Copy as many as possible Band across all Slots at once */ + if (realBuf != realBufRef) { + realBuf -= BAND_V_SIZE; + imagBuf -= BAND_V_SIZE; + } else { + realBuf += BAND_V_SIZE * (NUM_V_COMBINE - 1); + imagBuf += BAND_V_SIZE * (NUM_V_COMBINE - 1); + + for (i = 0; i < buffLen; i++) { + int v; + FIXP_DBL *ptr; + ptr = realBuf + i; + for (v = 0; v < NUM_V_COMBINE; v++) { + ptr[0] = sourceBufferReal[i][r + v]; + ptr[0 + BAND_V_SIZE * NUM_V_COMBINE] = sourceBufferImag[i][r + v]; + ptr -= BAND_V_SIZE; + } + } + } + + blockLength = pBlockLength[0]; + + while (k <= buffLen - blockLength) { + autoCorrScaling = fixMin( + getScalefactor(&realBuf[k - LPC_ORDER], LPC_ORDER + blockLength), + getScalefactor(&imagBuf[k - LPC_ORDER], LPC_ORDER + blockLength)); + autoCorrScaling = fixMax(0, autoCorrScaling - 1); + + scaleValues(&realBuf[k - LPC_ORDER], LPC_ORDER + blockLength, + autoCorrScaling); + scaleValues(&imagBuf[k - LPC_ORDER], LPC_ORDER + blockLength, + autoCorrScaling); + + autoCorrScaling <<= 1; /* consider qmf buffer scaling twice */ + autoCorrScaling += + autoCorr2nd_cplx(ac, realBuf + k, imagBuf + k, blockLength); + + if (ac->det == FL2FXCONST_DBL(0.0f)) { + alphar[1] = alphai[1] = FL2FXCONST_DBL(0.0f); + + alphar[0] = (ac->r01r) >> 2; + alphai[0] = (ac->r01i) >> 2; + + fac = fMultDiv2(ac->r00r, ac->r11r) >> 1; + } else { + alphar[1] = (fMultDiv2(ac->r01r, ac->r12r) >> 1) - + (fMultDiv2(ac->r01i, ac->r12i) >> 1) - + (fMultDiv2(ac->r02r, ac->r11r) >> 1); + alphai[1] = (fMultDiv2(ac->r01i, ac->r12r) >> 1) + + (fMultDiv2(ac->r01r, ac->r12i) >> 1) - + (fMultDiv2(ac->r02i, ac->r11r) >> 1); + + alphar[0] = (fMultDiv2(ac->r01r, ac->det) >> (ac->det_scale + 1)) + + fMult(alphar[1], ac->r12r) + fMult(alphai[1], ac->r12i); + alphai[0] = (fMultDiv2(ac->r01i, ac->det) >> (ac->det_scale + 1)) + + fMult(alphai[1], ac->r12r) - fMult(alphar[1], ac->r12i); + + fac = fMultDiv2(ac->r00r, fMult(ac->det, ac->r11r)) >> + (ac->det_scale + 1); + } + + if (fac == FL2FXCONST_DBL(0.0f)) { + quotaMatrix[timeIndex][r] = FL2FXCONST_DBL(0.0f); + signMatrix[timeIndex][r] = 0; + } else { + /* quotaMatrix is scaled with the factor RELAXATION + parse RELAXATION in fractional part and shift factor: 1/(1/0.524288 * + 2^RELAXATION_SHIFT) */ + FIXP_DBL tmp, num, denom; + INT numShift, denomShift, commonShift; + INT sign; + + num = fMultDiv2(alphar[0], ac->r01r) + fMultDiv2(alphai[0], ac->r01i) - + fMultDiv2(alphar[1], fMult(ac->r02r, ac->r11r)) - + fMultDiv2(alphai[1], fMult(ac->r02i, ac->r11r)); + num = fixp_abs(num); + + denom = (fac >> 1) + + (fMultDiv2(fac, RELAXATION_FRACT) >> RELAXATION_SHIFT) - num; + denom = fixp_abs(denom); + + num = fMult(num, RELAXATION_FRACT); + + numShift = CountLeadingBits(num) - 2; + num = scaleValue(num, numShift); + + denomShift = CountLeadingBits(denom); + denom = (FIXP_DBL)denom << denomShift; + + if ((num > FL2FXCONST_DBL(0.0f)) && (denom != FL2FXCONST_DBL(0.0f))) { + commonShift = + fixMin(numShift - denomShift + RELAXATION_SHIFT, DFRACT_BITS - 1); + if (commonShift < 0) { + commonShift = -commonShift; + tmp = schur_div(num, denom, 16); + commonShift = fixMin(commonShift, CountLeadingBits(tmp)); + quotaMatrix[timeIndex][r] = tmp << commonShift; + } else { + quotaMatrix[timeIndex][r] = + schur_div(num, denom, 16) >> commonShift; + } + } else { + quotaMatrix[timeIndex][r] = FL2FXCONST_DBL(0.0f); + } + + if (ac->r11r != FL2FXCONST_DBL(0.0f)) { + if (((ac->r01r >= FL2FXCONST_DBL(0.0f)) && + (ac->r11r >= FL2FXCONST_DBL(0.0f))) || + ((ac->r01r < FL2FXCONST_DBL(0.0f)) && + (ac->r11r < FL2FXCONST_DBL(0.0f)))) { + sign = 1; + } else { + sign = -1; + } + } else { + sign = 1; + } + + if (sign < 0) { + r2 = r; /* (INT) pow(-1, band); */ + } else { + r2 = r + 1; /* (INT) pow(-1, band+1); */ + } + signMatrix[timeIndex][r] = 1 - 2 * (r2 & 0x1); + } + + nrgVector[timeIndex] += + ((ac->r00r) >> + fixMin(DFRACT_BITS - 1, + (2 * qmfScale + autoCorrScaling + SCALE_NRGVEC))); + /* pNrgVectorFreq[r] finally has to be divided by noEstPerFrame, replaced + * division by shifting with one */ + pNrgVectorFreq[r] = + pNrgVectorFreq[r] + + ((ac->r00r) >> + fixMin(DFRACT_BITS - 1, + (2 * qmfScale + autoCorrScaling + SCALE_NRGVEC))); + + blockLength = pBlockLength[1]; + k += stepSize; + timeIndex++; + } + } + + C_ALLOC_SCRATCH_END(realBufRef, FIXP_DBL, 2 * BAND_V_SIZE * NUM_V_COMBINE) + C_ALLOC_SCRATCH_END(ac, ACORR_COEFS, 1) +} + +/**************************************************************************/ +/*! + \brief Extracts the parameters required in the decoder to obtain the + correct tonal to noise ratio after SBR. + + Estimates the tonal to noise ratio of the original signal (using LPC). + Predicts the tonal to noise ration of the SBR signal (in the decoder) by + patching the tonal to noise ratio values similar to the patching of the + lowband in the decoder. Given the tonal to noise ratio of the original + and the SBR signal, it estimates the required amount of inverse filtering, + additional noise as well as any additional sines. + + \return none. + +*/ +/**************************************************************************/ +void FDKsbrEnc_TonCorrParamExtr( + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INVF_MODE *infVec, /*!< Vector where the inverse filtering levels will be + stored. */ + FIXP_DBL *noiseLevels, /*!< Vector where the noise levels will be stored. */ + INT *missingHarmonicFlag, /*!< Flag set to one or zero, dependent on if any + strong sines are missing.*/ + UCHAR *missingHarmonicsIndex, /*!< Vector indicating where sines are + missing. */ + UCHAR *envelopeCompensation, /*!< Vector to store compensation values for + the energies in. */ + const SBR_FRAME_INFO *frameInfo, /*!< Frame info struct, contains the time + and frequency grid of the current + frame.*/ + UCHAR *transientInfo, /*!< Transient info.*/ + UCHAR *freqBandTable, /*!< Frequency band tables for high-res.*/ + INT nSfb, /*!< Number of scalefactor bands for high-res. */ + XPOS_MODE xposType, /*!< Type of transposer used in the decoder.*/ + UINT sbrSyntaxFlags) { + INT band; + INT transientFlag = transientInfo[1]; /*!< Flag indicating if a transient is + present in the current frame. */ + INT transientPos = transientInfo[0]; /*!< Position of the transient.*/ + INT transientFrame, transientFrameInvfEst; + INVF_MODE *infVecPtr; + + /* Determine if this is a frame where a transient starts... + + The detection of noise-floor, missing harmonics and invf_est, is not in sync + for the non-buf-opt decoder such as AAC. Hence we need to keep track on the + transient in the present frame as well as in the next. + */ + transientFrame = 0; + if (hTonCorr->transientNextFrame) { /* The transient was detected in the + previous frame, but is actually */ + transientFrame = 1; + hTonCorr->transientNextFrame = 0; + + if (transientFlag) { + if (transientPos + hTonCorr->transientPosOffset >= + frameInfo->borders[frameInfo->nEnvelopes]) { + hTonCorr->transientNextFrame = 1; + } + } + } else { + if (transientFlag) { + if (transientPos + hTonCorr->transientPosOffset < + frameInfo->borders[frameInfo->nEnvelopes]) { + transientFrame = 1; + hTonCorr->transientNextFrame = 0; + } else { + hTonCorr->transientNextFrame = 1; + } + } + } + transientFrameInvfEst = transientFrame; + + /* + Estimate the required invese filtereing level. + */ + if (hTonCorr->switchInverseFilt) + FDKsbrEnc_qmfInverseFilteringDetector( + &hTonCorr->sbrInvFilt, hTonCorr->quotaMatrix, hTonCorr->nrgVector, + hTonCorr->indexVector, hTonCorr->frameStartIndexInvfEst, + hTonCorr->numberOfEstimatesPerFrame + hTonCorr->frameStartIndexInvfEst, + transientFrameInvfEst, infVec); + + /* + Detect what tones will be missing. + */ + if (xposType == XPOS_LC) { + FDKsbrEnc_SbrMissingHarmonicsDetectorQmf( + &hTonCorr->sbrMissingHarmonicsDetector, hTonCorr->quotaMatrix, + hTonCorr->signMatrix, hTonCorr->indexVector, frameInfo, transientInfo, + missingHarmonicFlag, missingHarmonicsIndex, freqBandTable, nSfb, + envelopeCompensation, hTonCorr->nrgVectorFreq); + } else { + *missingHarmonicFlag = 0; + FDKmemclear(missingHarmonicsIndex, nSfb * sizeof(UCHAR)); + } + + /* + Noise floor estimation + */ + + infVecPtr = hTonCorr->sbrInvFilt.prevInvfMode; + + FDKsbrEnc_sbrNoiseFloorEstimateQmf( + &hTonCorr->sbrNoiseFloorEstimate, frameInfo, noiseLevels, + hTonCorr->quotaMatrix, hTonCorr->indexVector, *missingHarmonicFlag, + hTonCorr->frameStartIndex, hTonCorr->numberOfEstimatesPerFrame, + transientFrame, infVecPtr, sbrSyntaxFlags); + + /* Store the invfVec data for the next frame...*/ + for (band = 0; band < hTonCorr->sbrInvFilt.noDetectorBands; band++) { + hTonCorr->sbrInvFilt.prevInvfMode[band] = infVec[band]; + } +} + +/**************************************************************************/ +/*! + \brief Searches for the closest match in the frequency master table. + + + + \return closest entry. + +*/ +/**************************************************************************/ +static INT findClosestEntry(INT goalSb, UCHAR *v_k_master, INT numMaster, + INT direction) { + INT index; + + if (goalSb <= v_k_master[0]) return v_k_master[0]; + + if (goalSb >= v_k_master[numMaster]) return v_k_master[numMaster]; + + if (direction) { + index = 0; + while (v_k_master[index] < goalSb) { + index++; + } + } else { + index = numMaster; + while (v_k_master[index] > goalSb) { + index--; + } + } + + return v_k_master[index]; +} + +/**************************************************************************/ +/*! + \brief resets the patch + + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +static INT resetPatch( + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INT xposctrl, /*!< Different patch modes. */ + INT highBandStartSb, /*!< Start band of the SBR range. */ + UCHAR *v_k_master, /*!< Master frequency table from which all other table + are derived.*/ + INT numMaster, /*!< Number of elements in the master table. */ + INT fs, /*!< Sampling frequency. */ + INT noChannels) /*!< Number of QMF-channels. */ +{ + INT patch, k, i; + INT targetStopBand; + + PATCH_PARAM *patchParam = hTonCorr->patchParam; + + INT sbGuard = hTonCorr->guard; + INT sourceStartBand; + INT patchDistance; + INT numBandsInPatch; + + INT lsb = + v_k_master[0]; /* Lowest subband related to the synthesis filterbank */ + INT usb = v_k_master[numMaster]; /* Stop subband related to the synthesis + filterbank */ + INT xoverOffset = + highBandStartSb - + v_k_master[0]; /* Calculate distance in subbands between k0 and kx */ + + INT goalSb; + + /* + * Initialize the patching parameter + */ + + if (xposctrl == 1) { + lsb += xoverOffset; + xoverOffset = 0; + } + + goalSb = (INT)((2 * noChannels * 16000 + (fs >> 1)) / fs); /* 16 kHz band */ + goalSb = findClosestEntry(goalSb, v_k_master, numMaster, + 1); /* Adapt region to master-table */ + + /* First patch */ + sourceStartBand = hTonCorr->shiftStartSb + xoverOffset; + targetStopBand = lsb + xoverOffset; + + /* even (odd) numbered channel must be patched to even (odd) numbered channel + */ + patch = 0; + while (targetStopBand < usb) { + /* To many patches */ + if (patch >= MAX_NUM_PATCHES) return (1); /*Number of patches to high */ + + patchParam[patch].guardStartBand = targetStopBand; + targetStopBand += sbGuard; + patchParam[patch].targetStartBand = targetStopBand; + + numBandsInPatch = + goalSb - targetStopBand; /* get the desired range of the patch */ + + if (numBandsInPatch >= lsb - sourceStartBand) { + /* desired number bands are not available -> patch whole source range */ + patchDistance = + targetStopBand - sourceStartBand; /* get the targetOffset */ + patchDistance = + patchDistance & ~1; /* rounding off odd numbers and make all even */ + numBandsInPatch = lsb - (targetStopBand - patchDistance); + numBandsInPatch = findClosestEntry(targetStopBand + numBandsInPatch, + v_k_master, numMaster, 0) - + targetStopBand; /* Adapt region to master-table */ + } + + /* desired number bands are available -> get the minimal even patching + * distance */ + patchDistance = + numBandsInPatch + targetStopBand - lsb; /* get minimal distance */ + patchDistance = (patchDistance + 1) & + ~1; /* rounding up odd numbers and make all even */ + + if (numBandsInPatch <= 0) { + patch--; + } else { + patchParam[patch].sourceStartBand = targetStopBand - patchDistance; + patchParam[patch].targetBandOffs = patchDistance; + patchParam[patch].numBandsInPatch = numBandsInPatch; + patchParam[patch].sourceStopBand = + patchParam[patch].sourceStartBand + numBandsInPatch; + + targetStopBand += patchParam[patch].numBandsInPatch; + } + + /* All patches but first */ + sourceStartBand = hTonCorr->shiftStartSb; + + /* Check if we are close to goalSb */ + if (fixp_abs(targetStopBand - goalSb) < 3) { + goalSb = usb; + } + + patch++; + } + + patch--; + + /* if highest patch contains less than three subband: skip it */ + if (patchParam[patch].numBandsInPatch < 3 && patch > 0) { + patch--; + } + + hTonCorr->noOfPatches = patch + 1; + + /* Assign the index-vector, so we know where to look for the high-band. + -1 represents a guard-band. */ + for (k = 0; k < hTonCorr->patchParam[0].guardStartBand; k++) + hTonCorr->indexVector[k] = k; + + for (i = 0; i < hTonCorr->noOfPatches; i++) { + INT sourceStart = hTonCorr->patchParam[i].sourceStartBand; + INT targetStart = hTonCorr->patchParam[i].targetStartBand; + INT numberOfBands = hTonCorr->patchParam[i].numBandsInPatch; + INT startGuardBand = hTonCorr->patchParam[i].guardStartBand; + + for (k = 0; k < (targetStart - startGuardBand); k++) + hTonCorr->indexVector[startGuardBand + k] = -1; + + for (k = 0; k < numberOfBands; k++) + hTonCorr->indexVector[targetStart + k] = sourceStart + k; + } + + return (0); +} + +/**************************************************************************/ +/*! + \brief Creates an instance of the tonality correction parameter module. + + The module includes modules for inverse filtering level estimation, + missing harmonics detection and noise floor level estimation. + + \return errorCode, noError if successful. +*/ +/**************************************************************************/ +INT FDKsbrEnc_CreateTonCorrParamExtr( + HANDLE_SBR_TON_CORR_EST + hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + INT chan) /*!< Channel index, needed for mem allocation */ +{ + INT i; + FIXP_DBL *quotaMatrix = GetRam_Sbr_quotaMatrix(chan); + INT *signMatrix = GetRam_Sbr_signMatrix(chan); + + if ((NULL == quotaMatrix) || (NULL == signMatrix)) { + goto bail; + } + + FDKmemclear(hTonCorr, sizeof(SBR_TON_CORR_EST)); + + for (i = 0; i < MAX_NO_OF_ESTIMATES; i++) { + hTonCorr->quotaMatrix[i] = quotaMatrix + (i * 64); + hTonCorr->signMatrix[i] = signMatrix + (i * 64); + } + + if (0 != FDKsbrEnc_CreateSbrMissingHarmonicsDetector( + &hTonCorr->sbrMissingHarmonicsDetector, chan)) { + goto bail; + } + + return 0; + +bail: + hTonCorr->quotaMatrix[0] = quotaMatrix; + hTonCorr->signMatrix[0] = signMatrix; + + FDKsbrEnc_DeleteTonCorrParamExtr(hTonCorr); + + return -1; +} + +/**************************************************************************/ +/*! + \brief Initialize an instance of the tonality correction parameter module. + + The module includes modules for inverse filtering level estimation, + missing harmonics detection and noise floor level estimation. + + \return errorCode, noError if successful. +*/ +/**************************************************************************/ +INT FDKsbrEnc_InitTonCorrParamExtr( + INT frameSize, /*!< Current SBR frame size. */ + HANDLE_SBR_TON_CORR_EST + hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + HANDLE_SBR_CONFIG_DATA + sbrCfg, /*!< Pointer to SBR configuration parameters. */ + INT timeSlots, /*!< Number of time-slots per frame */ + INT xposCtrl, /*!< Different patch modes. */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + UINT useSpeechConfig) /*!< Speech or music tuning. */ +{ + INT nCols = sbrCfg->noQmfSlots; + INT fs = sbrCfg->sampleFreq; + INT noQmfChannels = sbrCfg->noQmfBands; + + INT highBandStartSb = sbrCfg->freqBandTable[LOW_RES][0]; + UCHAR *v_k_master = sbrCfg->v_k_master; + INT numMaster = sbrCfg->num_Master; + + UCHAR **freqBandTable = sbrCfg->freqBandTable; + INT *nSfb = sbrCfg->nSfb; + + INT i; + + /* + Reset the patching and allocate memory for the quota matrix. + Assuming parameters for the LPC analysis. + */ + if (sbrCfg->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + switch (timeSlots) { + case NUMBER_TIME_SLOTS_1920: + hTonCorr->lpcLength[0] = 8 - LPC_ORDER; + hTonCorr->lpcLength[1] = 7 - LPC_ORDER; + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LD; + hTonCorr->numberOfEstimatesPerFrame = 2; /* sbrCfg->noQmfSlots / 7 */ + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + break; + case NUMBER_TIME_SLOTS_2048: + hTonCorr->lpcLength[0] = 8 - LPC_ORDER; + hTonCorr->lpcLength[1] = 8 - LPC_ORDER; + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LD; + hTonCorr->numberOfEstimatesPerFrame = 2; /* sbrCfg->noQmfSlots / 8 */ + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + break; + } + } else + switch (timeSlots) { + case NUMBER_TIME_SLOTS_2048: + hTonCorr->lpcLength[0] = 16 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->lpcLength[1] = 16 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LC; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 16; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_2048; + break; + case NUMBER_TIME_SLOTS_1920: + hTonCorr->lpcLength[0] = 15 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->lpcLength[1] = 15 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LC; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 15; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_1920; + break; + default: + return -1; + } + + hTonCorr->bufferLength = nCols; + hTonCorr->stepSize = + hTonCorr->lpcLength[0] + LPC_ORDER; /* stepSize[0] implicitly 0. */ + + hTonCorr->nextSample = LPC_ORDER; /* firstSample */ + hTonCorr->move = hTonCorr->numberOfEstimates - + hTonCorr->numberOfEstimatesPerFrame; /* Number of estimates + to move when + buffering.*/ + if (hTonCorr->move < 0) { + return -1; + } + hTonCorr->startIndexMatrix = + hTonCorr->numberOfEstimates - + hTonCorr->numberOfEstimatesPerFrame; /* Where to store the latest + estimations in the tonality + Matrix.*/ + hTonCorr->frameStartIndex = 0; /* Where in the tonality matrix the current + frame (to be sent to the decoder) starts. */ + hTonCorr->prevTransientFlag = 0; + hTonCorr->transientNextFrame = 0; + + hTonCorr->noQmfChannels = noQmfChannels; + + for (i = 0; i < hTonCorr->numberOfEstimates; i++) { + FDKmemclear(hTonCorr->quotaMatrix[i], sizeof(FIXP_DBL) * noQmfChannels); + FDKmemclear(hTonCorr->signMatrix[i], sizeof(INT) * noQmfChannels); + } + + /* Reset the patch.*/ + hTonCorr->guard = 0; + hTonCorr->shiftStartSb = 1; + + if (resetPatch(hTonCorr, xposCtrl, highBandStartSb, v_k_master, numMaster, fs, + noQmfChannels)) + return (1); + + if (FDKsbrEnc_InitSbrNoiseFloorEstimate( + &hTonCorr->sbrNoiseFloorEstimate, ana_max_level, freqBandTable[LO], + nSfb[LO], noiseBands, noiseFloorOffset, timeSlots, useSpeechConfig)) + return (1); + + if (FDKsbrEnc_initInvFiltDetector( + &hTonCorr->sbrInvFilt, + hTonCorr->sbrNoiseFloorEstimate.freqBandTableQmf, + hTonCorr->sbrNoiseFloorEstimate.noNoiseBands, useSpeechConfig)) + return (1); + + if (FDKsbrEnc_InitSbrMissingHarmonicsDetector( + &hTonCorr->sbrMissingHarmonicsDetector, fs, frameSize, nSfb[HI], + noQmfChannels, hTonCorr->numberOfEstimates, hTonCorr->move, + hTonCorr->numberOfEstimatesPerFrame, sbrCfg->sbrSyntaxFlags)) + return (1); + + return (0); +} + +/**************************************************************************/ +/*! + \brief resets tonality correction parameter module. + + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +INT FDKsbrEnc_ResetTonCorrParamExtr( + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INT xposctrl, /*!< Different patch modes. */ + INT highBandStartSb, /*!< Start band of the SBR range. */ + UCHAR *v_k_master, /*!< Master frequency table from which all other table + are derived.*/ + INT numMaster, /*!< Number of elements in the master table. */ + INT fs, /*!< Sampling frequency (of the SBR part). */ + UCHAR * + *freqBandTable, /*!< Frequency band table for low-res and high-res. */ + INT *nSfb, /*!< Number of frequency bands (hig-res and low-res). */ + INT noQmfChannels /*!< Number of QMF channels. */ +) { + /* Reset the patch.*/ + hTonCorr->guard = 0; + hTonCorr->shiftStartSb = 1; + + if (resetPatch(hTonCorr, xposctrl, highBandStartSb, v_k_master, numMaster, fs, + noQmfChannels)) + return (1); + + /* Reset the noise floor estimate.*/ + if (FDKsbrEnc_resetSbrNoiseFloorEstimate(&hTonCorr->sbrNoiseFloorEstimate, + freqBandTable[LO], nSfb[LO])) + return (1); + + /* + Reset the inveerse filtereing detector. + */ + if (FDKsbrEnc_resetInvFiltDetector( + &hTonCorr->sbrInvFilt, + hTonCorr->sbrNoiseFloorEstimate.freqBandTableQmf, + hTonCorr->sbrNoiseFloorEstimate.noNoiseBands)) + return (1); + /* Reset the missing harmonics detector. */ + if (FDKsbrEnc_ResetSbrMissingHarmonicsDetector( + &hTonCorr->sbrMissingHarmonicsDetector, nSfb[HI])) + return (1); + + return (0); +} + +/**************************************************************************/ +/*! + \brief Deletes the tonality correction paramtere module. + + + + \return none + +*/ +/**************************************************************************/ +void FDKsbrEnc_DeleteTonCorrParamExtr( + HANDLE_SBR_TON_CORR_EST hTonCorr) /*!< Handle to SBR_TON_CORR struct. */ +{ + if (hTonCorr) { + FreeRam_Sbr_quotaMatrix(hTonCorr->quotaMatrix); + + FreeRam_Sbr_signMatrix(hTonCorr->signMatrix); + + FDKsbrEnc_DeleteSbrMissingHarmonicsDetector( + &hTonCorr->sbrMissingHarmonicsDetector); + } +} diff --git a/fdk-aac/libSBRenc/src/ton_corr.h b/fdk-aac/libSBRenc/src/ton_corr.h new file mode 100644 index 0000000..91aa278 --- /dev/null +++ b/fdk-aac/libSBRenc/src/ton_corr.h @@ -0,0 +1,258 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief General tonality correction detector module. +*/ +#ifndef TON_CORR_H +#define TON_CORR_H + +#include "sbr_encoder.h" +#include "mh_det.h" +#include "nf_est.h" +#include "invf_est.h" + +#define MAX_NUM_PATCHES 6 +#define SCALE_NRGVEC 4 + +/** parameter set for one single patch */ +typedef struct { + INT sourceStartBand; /*!< first band in lowbands where to take the samples + from */ + INT sourceStopBand; /*!< first band in lowbands which is not included in the + patch anymore */ + INT guardStartBand; /*!< first band in highbands to be filled with zeros in + order to reduce interferences between patches */ + INT targetStartBand; /*!< first band in highbands to be filled with whitened + lowband signal */ + INT targetBandOffs; /*!< difference between 'startTargetBand' and + 'startSourceBand' */ + INT numBandsInPatch; /*!< number of consecutive bands in this one patch */ +} PATCH_PARAM; + +typedef struct { + INT switchInverseFilt; /*!< Flag to enable dynamic adaption of invf. detection + */ + INT noQmfChannels; + INT bufferLength; /*!< Length of the r and i buffers. */ + INT stepSize; /*!< Stride for the lpc estimate. */ + INT numberOfEstimates; /*!< The total number of estiamtes, available in the + quotaMatrix.*/ + UINT numberOfEstimatesPerFrame; /*!< The number of estimates per frame + available in the quotaMatrix.*/ + INT lpcLength[2]; /*!< Segment length used for second order LPC analysis.*/ + INT nextSample; /*!< Where to start the LPC analysis of the current frame.*/ + INT move; /*!< How many estimates to move in the quotaMatrix, when buffering. + */ + INT frameStartIndex; /*!< The start index for the current frame in the r and i + buffers. */ + INT startIndexMatrix; /*!< The start index for the current frame in the + quotaMatrix. */ + INT frameStartIndexInvfEst; /*!< The start index of the inverse filtering, not + the same as the others, dependent on what + decoder is used (buffer opt, or no buffer opt). + */ + INT prevTransientFlag; /*!< The transisent flag (from the transient detector) + for the previous frame. */ + INT transientNextFrame; /*!< Flag to indicate that the transient will show up + in the next frame. */ + INT transientPosOffset; /*!< An offset value to match the transient pos as + calculated by the transient detector with the + actual position in the frame.*/ + + INT* signMatrix[MAX_NO_OF_ESTIMATES]; /*!< Matrix holding the sign of each + channe, i.e. indicating in what part + of a QMF channel a possible sine is. + */ + + FIXP_DBL* quotaMatrix[MAX_NO_OF_ESTIMATES]; /*!< Matrix holding the quota + values for all estimates, all + channels. */ + + FIXP_DBL nrgVector[MAX_NO_OF_ESTIMATES]; /*!< Vector holding the averaged + energies for every QMF band. */ + FIXP_DBL nrgVectorFreq[64]; /*!< Vector holding the averaged energies for + every QMF channel */ + + SCHAR indexVector[64]; /*!< Index vector poINTing to the correct lowband + channel, when indexing a highband channel, -1 + represents a guard band */ + PATCH_PARAM + patchParam[MAX_NUM_PATCHES]; /*!< new parameter set for patching */ + INT guard; /*!< number of guardbands between every patch */ + INT shiftStartSb; /*!< lowest subband of source range to be included in the + patches */ + INT noOfPatches; /*!< number of patches */ + + SBR_MISSING_HARMONICS_DETECTOR + sbrMissingHarmonicsDetector; /*!< SBR_MISSING_HARMONICS_DETECTOR struct. + */ + SBR_NOISE_FLOOR_ESTIMATE + sbrNoiseFloorEstimate; /*!< SBR_NOISE_FLOOR_ESTIMATE struct. */ + SBR_INV_FILT_EST sbrInvFilt; /*!< SBR_INV_FILT_EST struct. */ +} SBR_TON_CORR_EST; + +typedef SBR_TON_CORR_EST* HANDLE_SBR_TON_CORR_EST; + +void FDKsbrEnc_TonCorrParamExtr( + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INVF_MODE* infVec, /*!< Vector where the inverse filtering levels will be + stored. */ + FIXP_DBL* noiseLevels, /*!< Vector where the noise levels will be stored. */ + INT* missingHarmonicFlag, /*!< Flag set to one or zero, dependent on if any + strong sines are missing.*/ + UCHAR* missingHarmonicsIndex, /*!< Vector indicating where sines are + missing. */ + UCHAR* envelopeCompensation, /*!< Vector to store compensation values for + the energies in. */ + const SBR_FRAME_INFO* frameInfo, /*!< Frame info struct, contains the time + and frequency grid of the current + frame.*/ + UCHAR* transientInfo, /*!< Transient info.*/ + UCHAR* freqBandTable, /*!< Frequency band tables for high-res.*/ + INT nSfb, /*!< Number of scalefactor bands for high-res. */ + XPOS_MODE xposType, /*!< Type of transposer used in the decoder.*/ + UINT sbrSyntaxFlags); + +INT FDKsbrEnc_CreateTonCorrParamExtr( + HANDLE_SBR_TON_CORR_EST + hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + INT chan); /*!< Channel index, needed for mem allocation */ + +INT FDKsbrEnc_InitTonCorrParamExtr( + INT frameSize, /*!< Current SBR frame size. */ + HANDLE_SBR_TON_CORR_EST + hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + HANDLE_SBR_CONFIG_DATA + sbrCfg, /*!< Pointer to SBR configuration parameters. */ + INT timeSlots, /*!< Number of time-slots per frame */ + INT xposCtrl, /*!< Different patch modes. */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + UINT useSpeechConfig /*!< Speech or music tuning. */ +); + +void FDKsbrEnc_DeleteTonCorrParamExtr( + HANDLE_SBR_TON_CORR_EST hTonCorr); /*!< Handle to SBR_TON_CORR struct. */ + +void FDKsbrEnc_CalculateTonalityQuotas( + HANDLE_SBR_TON_CORR_EST hTonCorr, FIXP_DBL** sourceBufferReal, + FIXP_DBL** sourceBufferImag, INT usb, + INT qmfScale /*!< sclefactor of QMF subsamples */ +); + +INT FDKsbrEnc_ResetTonCorrParamExtr( + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INT xposctrl, /*!< Different patch modes. */ + INT highBandStartSb, /*!< Start band of the SBR range. */ + UCHAR* v_k_master, /*!< Master frequency table from which all other table + are derived.*/ + INT numMaster, /*!< Number of elements in the master table. */ + INT fs, /*!< Sampling frequency (of the SBR part). */ + UCHAR** + freqBandTable, /*!< Frequency band table for low-res and high-res. */ + INT* nSfb, /*!< Number of frequency bands (hig-res and low-res). */ + INT noQmfChannels /*!< Number of QMF channels. */ +); +#endif diff --git a/fdk-aac/libSBRenc/src/tran_det.cpp b/fdk-aac/libSBRenc/src/tran_det.cpp new file mode 100644 index 0000000..3b6765a --- /dev/null +++ b/fdk-aac/libSBRenc/src/tran_det.cpp @@ -0,0 +1,1092 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): Tobias Chalupka + + Description: SBR encoder transient detector + +*******************************************************************************/ + +#include "tran_det.h" + +#include "fram_gen.h" +#include "sbrenc_ram.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +#define NORM_QMF_ENERGY 9.31322574615479E-10 /* 2^-30 */ + +/* static FIXP_DBL ABS_THRES = fixMax( FL2FXCONST_DBL(1.28e5 * + * NORM_QMF_ENERGY), (FIXP_DBL)1) Minimum threshold for detecting changes */ +#define ABS_THRES ((FIXP_DBL)16) + +/******************************************************************************* + Functionname: spectralChange + ******************************************************************************* + \brief Calculates a measure for the spectral change within the frame + + The function says how good it would be to split the frame at the given border + position into 2 envelopes. + + The return value delta_sum is scaled with the factor 1/64 + + \return calculated value +*******************************************************************************/ +#define NRG_SHIFT 3 /* for energy summation */ + +static FIXP_DBL spectralChange( + FIXP_DBL Energies[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS], + INT *scaleEnergies, FIXP_DBL EnergyTotal, INT nSfb, INT start, INT border, + INT YBufferWriteOffset, INT stop, INT *result_e) { + INT i, j; + INT len1, len2; + SCHAR energies_e_diff[NUMBER_TIME_SLOTS_2304], energies_e, energyTotal_e = 19, + energies_e_add; + SCHAR prevEnergies_e_diff, newEnergies_e_diff; + FIXP_DBL tmp0, tmp1; + FIXP_DBL delta, delta_sum; + INT accu_e, tmp_e; + + delta_sum = FL2FXCONST_DBL(0.0f); + *result_e = 0; + + len1 = border - start; + len2 = stop - border; + + /* prefer borders near the middle of the frame */ + FIXP_DBL pos_weight; + pos_weight = FL2FXCONST_DBL(0.5f) - (len1 * GetInvInt(len1 + len2)); + pos_weight = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL - + (fMult(pos_weight, pos_weight) << 2); + + /*** Calc scaling for energies ***/ + FDK_ASSERT(scaleEnergies[0] >= 0); + FDK_ASSERT(scaleEnergies[1] >= 0); + + energies_e = 19 - fMin(scaleEnergies[0], scaleEnergies[1]); + + /* limit shift for energy accumulation, energies_e can be -10 min. */ + if (energies_e < -10) { + energies_e_add = -10 - energies_e; + energies_e = -10; + } else if (energies_e > 17) { + energies_e_add = energies_e - 17; + energies_e = 17; + } else { + energies_e_add = 0; + } + + /* compensate scaling differences between scaleEnergies[0] and + * scaleEnergies[1] */ + prevEnergies_e_diff = scaleEnergies[0] - + fMin(scaleEnergies[0], scaleEnergies[1]) + + energies_e_add + NRG_SHIFT; + newEnergies_e_diff = scaleEnergies[1] - + fMin(scaleEnergies[0], scaleEnergies[1]) + + energies_e_add + NRG_SHIFT; + + prevEnergies_e_diff = fMin(prevEnergies_e_diff, DFRACT_BITS - 1); + newEnergies_e_diff = fMin(newEnergies_e_diff, DFRACT_BITS - 1); + + for (i = start; i < YBufferWriteOffset; i++) { + energies_e_diff[i] = prevEnergies_e_diff; + } + for (i = YBufferWriteOffset; i < stop; i++) { + energies_e_diff[i] = newEnergies_e_diff; + } + + /* Sum up energies of all QMF-timeslots for both halfs */ + FDK_ASSERT(len1 <= 8); /* otherwise an overflow is possible */ + FDK_ASSERT(len2 <= 8); /* otherwise an overflow is possible */ + + for (j = 0; j < nSfb; j++) { + FIXP_DBL accu1 = FL2FXCONST_DBL(0.f); + FIXP_DBL accu2 = FL2FXCONST_DBL(0.f); + accu_e = energies_e + 3; + + /* Sum up energies in first half */ + for (i = start; i < border; i++) { + accu1 += scaleValue(Energies[i][j], -energies_e_diff[i]); + } + + /* Sum up energies in second half */ + for (i = border; i < stop; i++) { + accu2 += scaleValue(Energies[i][j], -energies_e_diff[i]); + } + + /* Ensure certain energy to prevent division by zero and to prevent + * splitting for very low levels */ + accu1 = fMax(accu1, (FIXP_DBL)len1); + accu2 = fMax(accu2, (FIXP_DBL)len2); + +/* Energy change in current band */ +#define LN2 FL2FXCONST_DBL(0.6931471806f) /* ln(2) */ + tmp0 = fLog2(accu2, accu_e) - fLog2(accu1, accu_e); + tmp1 = fLog2((FIXP_DBL)len1, 31) - fLog2((FIXP_DBL)len2, 31); + delta = fMult(LN2, (tmp0 + tmp1)); + delta = (FIXP_DBL)fAbs(delta); + + /* Weighting with amplitude ratio of this band */ + accu_e++; /* scale at least one bit due to (accu1+accu2) */ + accu1 >>= 1; + accu2 >>= 1; + + if (accu_e & 1) { + accu_e++; /* for a defined square result exponent, the exponent has to be + even */ + accu1 >>= 1; + accu2 >>= 1; + } + + delta_sum += fMult(sqrtFixp(accu1 + accu2), delta); + *result_e = ((accu_e >> 1) + LD_DATA_SHIFT); + } + + if (energyTotal_e & 1) { + energyTotal_e += 1; /* for a defined square result exponent, the exponent + has to be even */ + EnergyTotal >>= 1; + } + + delta_sum = fMult(delta_sum, invSqrtNorm2(EnergyTotal, &tmp_e)); + *result_e = *result_e + (tmp_e - (energyTotal_e >> 1)); + + return fMult(delta_sum, pos_weight); +} + +/******************************************************************************* + Functionname: addLowbandEnergies + ******************************************************************************* + \brief Calculates total lowband energy + + The input values Energies[0] (low-band) are scaled by the factor + 2^(14-*scaleEnergies[0]) + The input values Energies[1] (high-band) are scaled by the factor + 2^(14-*scaleEnergies[1]) + + \return total energy in the lowband, scaled by the factor 2^19 +*******************************************************************************/ +static FIXP_DBL addLowbandEnergies(FIXP_DBL **Energies, int *scaleEnergies, + int YBufferWriteOffset, int nrgSzShift, + int tran_off, UCHAR *freqBandTable, + int slots) { + INT nrgTotal_e; + FIXP_DBL nrgTotal_m; + FIXP_DBL accu1 = FL2FXCONST_DBL(0.0f); + FIXP_DBL accu2 = FL2FXCONST_DBL(0.0f); + int tran_offdiv2 = tran_off >> nrgSzShift; + const int sc1 = + DFRACT_BITS - + fNormz((FIXP_DBL)fMax( + 1, (freqBandTable[0] * (YBufferWriteOffset - tran_offdiv2) - 1))); + const int sc2 = + DFRACT_BITS - + fNormz((FIXP_DBL)fMax( + 1, (freqBandTable[0] * + (tran_offdiv2 + (slots >> nrgSzShift) - YBufferWriteOffset) - + 1))); + int ts, k; + + /* Sum up lowband energy from one frame at offset tran_off */ + /* freqBandTable[LORES] has MAX_FREQ_COEFFS/2 +1 coeefs max. */ + for (ts = tran_offdiv2; ts < YBufferWriteOffset; ts++) { + for (k = 0; k < freqBandTable[0]; k++) { + accu1 += Energies[ts][k] >> sc1; + } + } + for (; ts < tran_offdiv2 + (slots >> nrgSzShift); ts++) { + for (k = 0; k < freqBandTable[0]; k++) { + accu2 += Energies[ts][k] >> sc2; + } + } + + nrgTotal_m = fAddNorm(accu1, (sc1 - 5) - scaleEnergies[0], accu2, + (sc2 - 5) - scaleEnergies[1], &nrgTotal_e); + nrgTotal_m = scaleValueSaturate(nrgTotal_m, nrgTotal_e); + + return (nrgTotal_m); +} + +/******************************************************************************* + Functionname: addHighbandEnergies + ******************************************************************************* + \brief Add highband energies + + Highband energies are mapped to an array with smaller dimension: + Its time resolution is only 1 SBR-timeslot and its frequency resolution + is 1 SBR-band. Therefore the data to be fed into the spectralChange + function is reduced. + + The values EnergiesM are scaled by the factor (2^19-scaleEnergies[0]) for + slots<YBufferWriteOffset and by the factor (2^19-scaleEnergies[1]) for + slots>=YBufferWriteOffset. + + \return total energy in the highband, scaled by factor 2^19 +*******************************************************************************/ + +static FIXP_DBL addHighbandEnergies( + FIXP_DBL **RESTRICT Energies, /*!< input */ + INT *scaleEnergies, INT YBufferWriteOffset, + FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304] + [MAX_FREQ_COEFFS], /*!< Combined output */ + UCHAR *RESTRICT freqBandTable, INT nSfb, INT sbrSlots, INT timeStep) { + INT i, j, k, slotIn, slotOut, scale[2]; + INT li, ui; + FIXP_DBL nrgTotal; + FIXP_DBL accu = FL2FXCONST_DBL(0.0f); + + /* Combine QMF-timeslots to SBR-timeslots, + combine QMF-bands to SBR-bands, + combine Left and Right channel */ + for (slotOut = 0; slotOut < sbrSlots; slotOut++) { + /* Note: Below slotIn = slotOut and not slotIn = timeStep*slotOut + because the Energies[] time resolution is always the SBR slot resolution + regardless of the timeStep. */ + slotIn = slotOut; + + for (j = 0; j < nSfb; j++) { + accu = FL2FXCONST_DBL(0.0f); + + li = freqBandTable[j]; + ui = freqBandTable[j + 1]; + + for (k = li; k < ui; k++) { + for (i = 0; i < timeStep; i++) { + accu += Energies[slotIn][k] >> 5; + } + } + EnergiesM[slotOut][j] = accu; + } + } + + /* scale energies down before add up */ + scale[0] = fixMin(8, scaleEnergies[0]); + scale[1] = fixMin(8, scaleEnergies[1]); + + if ((scaleEnergies[0] - scale[0]) > (DFRACT_BITS - 1) || + (scaleEnergies[1] - scale[1]) > (DFRACT_BITS - 1)) + nrgTotal = FL2FXCONST_DBL(0.0f); + else { + /* Now add all energies */ + accu = FL2FXCONST_DBL(0.0f); + + for (slotOut = 0; slotOut < YBufferWriteOffset; slotOut++) { + for (j = 0; j < nSfb; j++) { + accu += (EnergiesM[slotOut][j] >> scale[0]); + } + } + nrgTotal = accu >> (scaleEnergies[0] - scale[0]); + + for (slotOut = YBufferWriteOffset; slotOut < sbrSlots; slotOut++) { + for (j = 0; j < nSfb; j++) { + accu += (EnergiesM[slotOut][j] >> scale[0]); + } + } + nrgTotal = fAddSaturate(nrgTotal, accu >> (scaleEnergies[1] - scale[1])); + } + + return (nrgTotal); +} + +/******************************************************************************* + Functionname: FDKsbrEnc_frameSplitter + ******************************************************************************* + \brief Decides if a FIXFIX-frame shall be splitted into 2 envelopes + + If no transient has been detected before, the frame can still be splitted + into 2 envelopes. +*******************************************************************************/ +void FDKsbrEnc_frameSplitter( + FIXP_DBL **Energies, INT *scaleEnergies, + HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, UCHAR *freqBandTable, + UCHAR *tran_vector, int YBufferWriteOffset, int YBufferSzShift, int nSfb, + int timeStep, int no_cols, FIXP_DBL *tonality) { + if (tran_vector[1] == 0) /* no transient was detected */ + { + FIXP_DBL delta; + INT delta_e; + FIXP_DBL(*EnergiesM)[MAX_FREQ_COEFFS]; + FIXP_DBL EnergyTotal, newLowbandEnergy, newHighbandEnergy; + INT border; + INT sbrSlots = fMultI(GetInvInt(timeStep), no_cols); + C_ALLOC_SCRATCH_START(_EnergiesM, FIXP_DBL, + NUMBER_TIME_SLOTS_2304 * MAX_FREQ_COEFFS) + + FDK_ASSERT(sbrSlots * timeStep == no_cols); + + EnergiesM = (FIXP_DBL(*)[MAX_FREQ_COEFFS])_EnergiesM; + + /* + Get Lowband-energy over a range of 2 frames (Look half a frame back and + ahead). + */ + newLowbandEnergy = addLowbandEnergies( + Energies, scaleEnergies, YBufferWriteOffset, YBufferSzShift, + h_sbrTransientDetector->tran_off, freqBandTable, no_cols); + + newHighbandEnergy = + addHighbandEnergies(Energies, scaleEnergies, YBufferWriteOffset, + EnergiesM, freqBandTable, nSfb, sbrSlots, timeStep); + + { + /* prevLowBandEnergy: Corresponds to 1 frame, starting with half a frame + look-behind newLowbandEnergy: Corresponds to 1 frame, starting in the + middle of the current frame */ + EnergyTotal = (newLowbandEnergy >> 1) + + (h_sbrTransientDetector->prevLowBandEnergy >> + 1); /* mean of new and prev LB NRG */ + EnergyTotal = + fAddSaturate(EnergyTotal, newHighbandEnergy); /* Add HB NRG */ + /* The below border should specify the same position as the middle border + of a FIXFIX-frame with 2 envelopes. */ + border = (sbrSlots + 1) >> 1; + + if ((INT)EnergyTotal & 0xffffffe0 && + (scaleEnergies[0] < 32 || scaleEnergies[1] < 32)) /* i.e. > 31 */ { + delta = spectralChange(EnergiesM, scaleEnergies, EnergyTotal, nSfb, 0, + border, YBufferWriteOffset, sbrSlots, &delta_e); + } else { + delta = FL2FXCONST_DBL(0.0f); + delta_e = 0; + + /* set tonality to 0 when energy is very low, since the amplitude + resolution should then be low as well */ + *tonality = FL2FXCONST_DBL(0.0f); + } + + if (fIsLessThan(h_sbrTransientDetector->split_thr_m, + h_sbrTransientDetector->split_thr_e, delta, delta_e)) { + tran_vector[0] = 1; /* Set flag for splitting */ + } else { + tran_vector[0] = 0; + } + } + + /* Update prevLowBandEnergy */ + h_sbrTransientDetector->prevLowBandEnergy = newLowbandEnergy; + h_sbrTransientDetector->prevHighBandEnergy = newHighbandEnergy; + C_ALLOC_SCRATCH_END(_EnergiesM, FIXP_DBL, + NUMBER_TIME_SLOTS_2304 * MAX_FREQ_COEFFS) + } +} + +/* + * Calculate transient energy threshold for each QMF band + */ +static void calculateThresholds(FIXP_DBL **RESTRICT Energies, + INT *RESTRICT scaleEnergies, + FIXP_DBL *RESTRICT thresholds, + int YBufferWriteOffset, int YBufferSzShift, + int noCols, int noRows, int tran_off) { + FIXP_DBL mean_val, std_val, temp; + FIXP_DBL i_noCols; + FIXP_DBL i_noCols1; + FIXP_DBL accu, accu0, accu1; + int scaleFactor0, scaleFactor1, commonScale; + int i, j; + + i_noCols = GetInvInt(noCols + tran_off) << YBufferSzShift; + i_noCols1 = GetInvInt(noCols + tran_off - 1) << YBufferSzShift; + + /* calc minimum scale of energies of previous and current frame */ + commonScale = fixMin(scaleEnergies[0], scaleEnergies[1]); + + /* calc scalefactors to adapt energies to common scale */ + scaleFactor0 = fixMin((scaleEnergies[0] - commonScale), (DFRACT_BITS - 1)); + scaleFactor1 = fixMin((scaleEnergies[1] - commonScale), (DFRACT_BITS - 1)); + + FDK_ASSERT((scaleFactor0 >= 0) && (scaleFactor1 >= 0)); + + /* calculate standard deviation in every subband */ + for (i = 0; i < noRows; i++) { + int startEnergy = (tran_off >> YBufferSzShift); + int endEnergy = ((noCols >> YBufferSzShift) + tran_off); + int shift; + + /* calculate mean value over decimated energy values (downsampled by 2). */ + accu0 = accu1 = FL2FXCONST_DBL(0.0f); + + for (j = startEnergy; j < YBufferWriteOffset; j++) + accu0 = fMultAddDiv2(accu0, Energies[j][i], i_noCols); + for (; j < endEnergy; j++) + accu1 = fMultAddDiv2(accu1, Energies[j][i], i_noCols); + + mean_val = ((accu0 << 1) >> scaleFactor0) + + ((accu1 << 1) >> scaleFactor1); /* average */ + shift = fixMax( + 0, CountLeadingBits(mean_val) - + 6); /* -6 to keep room for accumulating upto N = 24 values */ + + /* calculate standard deviation */ + accu = FL2FXCONST_DBL(0.0f); + + /* summe { ((mean_val-nrg)^2) * i_noCols1 } */ + for (j = startEnergy; j < YBufferWriteOffset; j++) { + temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor0)) + << shift; + temp = fPow2Div2(temp); + accu = fMultAddDiv2(accu, temp, i_noCols1); + } + for (; j < endEnergy; j++) { + temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor1)) + << shift; + temp = fPow2Div2(temp); + accu = fMultAddDiv2(accu, temp, i_noCols1); + } + accu <<= 2; + std_val = sqrtFixp(accu) >> shift; /* standard deviation */ + + /* + Take new threshold as average of calculated standard deviation ratio + and old threshold if greater than absolute threshold + */ + temp = (commonScale <= (DFRACT_BITS - 1)) + ? fMult(FL2FXCONST_DBL(0.66f), thresholds[i]) + + (fMult(FL2FXCONST_DBL(0.34f), std_val) >> commonScale) + : (FIXP_DBL)0; + + thresholds[i] = fixMax(ABS_THRES, temp); + + FDK_ASSERT(commonScale >= 0); + } +} + +/* + * Calculate transient levels for each QMF time slot. + */ +static void extractTransientCandidates( + FIXP_DBL **RESTRICT Energies, INT *RESTRICT scaleEnergies, + FIXP_DBL *RESTRICT thresholds, FIXP_DBL *RESTRICT transients, + int YBufferWriteOffset, int YBufferSzShift, int noCols, int start_band, + int stop_band, int tran_off, int addPrevSamples) { + FIXP_DBL i_thres; + C_ALLOC_SCRATCH_START(EnergiesTemp, FIXP_DBL, 2 * 32) + int tmpScaleEnergies0, tmpScaleEnergies1; + int endCond; + int startEnerg, endEnerg; + int i, j, jIndex, jpBM; + + tmpScaleEnergies0 = scaleEnergies[0]; + tmpScaleEnergies1 = scaleEnergies[1]; + + /* Scale value for first energies, upto YBufferWriteOffset */ + tmpScaleEnergies0 = fixMin(tmpScaleEnergies0, MAX_SHIFT_DBL); + /* Scale value for first energies, from YBufferWriteOffset upwards */ + tmpScaleEnergies1 = fixMin(tmpScaleEnergies1, MAX_SHIFT_DBL); + + FDK_ASSERT((tmpScaleEnergies0 >= 0) && (tmpScaleEnergies1 >= 0)); + + /* Keep addPrevSamples extra previous transient candidates. */ + FDKmemmove(transients, transients + noCols - addPrevSamples, + (tran_off + addPrevSamples) * sizeof(FIXP_DBL)); + FDKmemclear(transients + tran_off + addPrevSamples, + noCols * sizeof(FIXP_DBL)); + + endCond = noCols; /* Amount of new transient values to be calculated. */ + startEnerg = (tran_off - 3) >> YBufferSzShift; /* >>YBufferSzShift because of + amount of energy values. -3 + because of neighbors being + watched. */ + endEnerg = + ((noCols + (YBufferWriteOffset << YBufferSzShift)) - 1) >> + YBufferSzShift; /* YBufferSzShift shifts because of half energy values. */ + + /* Compute differential values with two different weightings in every subband + */ + for (i = start_band; i < stop_band; i++) { + FIXP_DBL thres = thresholds[i]; + + if ((LONG)thresholds[i] >= 256) + i_thres = (LONG)((LONG)MAXVAL_DBL / ((((LONG)thresholds[i])) + 1)) + << (32 - 24); + else + i_thres = (LONG)MAXVAL_DBL; + + /* Copy one timeslot and de-scale and de-squish */ + if (YBufferSzShift == 1) { + for (j = startEnerg; j < YBufferWriteOffset; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[(j << 1) + 1] = EnergiesTemp[j << 1] = + tmp >> tmpScaleEnergies0; + } + for (; j <= endEnerg; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[(j << 1) + 1] = EnergiesTemp[j << 1] = + tmp >> tmpScaleEnergies1; + } + } else { + for (j = startEnerg; j < YBufferWriteOffset; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[j] = tmp >> tmpScaleEnergies0; + } + for (; j <= endEnerg; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[j] = tmp >> tmpScaleEnergies1; + } + } + + /* Detect peaks in energy values. */ + + jIndex = tran_off; + jpBM = jIndex + addPrevSamples; + + for (j = endCond; j--; jIndex++, jpBM++) { + FIXP_DBL delta, tran; + int d; + + delta = (FIXP_DBL)0; + tran = (FIXP_DBL)0; + + for (d = 1; d < 4; d++) { + delta += EnergiesTemp[jIndex + d]; /* R */ + delta -= EnergiesTemp[jIndex - d]; /* L */ + delta -= thres; + + if (delta > (FIXP_DBL)0) { + tran = fMultAddDiv2(tran, i_thres, delta); + } + } + transients[jpBM] += (tran << 1); + } + } + C_ALLOC_SCRATCH_END(EnergiesTemp, FIXP_DBL, 2 * 32) +} + +void FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTran, + FIXP_DBL **Energies, INT *scaleEnergies, + UCHAR *transient_info, int YBufferWriteOffset, + int YBufferSzShift, int timeStep, + int frameMiddleBorder) { + int no_cols = h_sbrTran->no_cols; + int qmfStartSample; + int addPrevSamples; + int timeStepShift = 0; + int i, cond; + + /* Where to start looking for transients in the transient candidate buffer */ + qmfStartSample = timeStep * frameMiddleBorder; + /* We need to look one value backwards in the transients, so we might need one + * more previous value. */ + addPrevSamples = (qmfStartSample > 0) ? 0 : 1; + + switch (timeStep) { + case 1: + timeStepShift = 0; + break; + case 2: + timeStepShift = 1; + break; + case 4: + timeStepShift = 2; + break; + } + + calculateThresholds(Energies, scaleEnergies, h_sbrTran->thresholds, + YBufferWriteOffset, YBufferSzShift, h_sbrTran->no_cols, + h_sbrTran->no_rows, h_sbrTran->tran_off); + + extractTransientCandidates( + Energies, scaleEnergies, h_sbrTran->thresholds, h_sbrTran->transients, + YBufferWriteOffset, YBufferSzShift, h_sbrTran->no_cols, 0, + h_sbrTran->no_rows, h_sbrTran->tran_off, addPrevSamples); + + transient_info[0] = 0; + transient_info[1] = 0; + transient_info[2] = 0; + + /* Offset by the amount of additional previous transient candidates being + * kept. */ + qmfStartSample += addPrevSamples; + + /* Check for transients in second granule (pick the last value of subsequent + * values) */ + for (i = qmfStartSample; i < qmfStartSample + no_cols; i++) { + cond = (h_sbrTran->transients[i] < + fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1])) && + (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr); + + if (cond) { + transient_info[0] = (i - qmfStartSample) >> timeStepShift; + transient_info[1] = 1; + break; + } + } + + if (h_sbrTran->frameShift != 0) { + /* transient prediction for LDSBR */ + /* Check for transients in first <frameShift> qmf-slots of second frame */ + for (i = qmfStartSample + no_cols; + i < qmfStartSample + no_cols + h_sbrTran->frameShift; i++) { + cond = (h_sbrTran->transients[i] < + fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1])) && + (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr); + + if (cond) { + int pos = (int)((i - qmfStartSample - no_cols) >> timeStepShift); + if ((pos < 3) && (transient_info[1] == 0)) { + transient_info[2] = 1; + } + break; + } + } + } +} + +int FDKsbrEnc_InitSbrTransientDetector( + HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + UINT sbrSyntaxFlags, /* SBR syntax flags derived from AOT. */ + INT frameSize, INT sampleFreq, sbrConfigurationPtr params, int tran_fc, + int no_cols, int no_rows, int YBufferWriteOffset, int YBufferSzShift, + int frameShift, int tran_off) { + INT totalBitrate = + params->codecSettings.standardBitrate * params->codecSettings.nChannels; + INT codecBitrate = params->codecSettings.bitRate; + FIXP_DBL bitrateFactor_m, framedur_fix; + INT bitrateFactor_e, tmp_e; + + FDKmemclear(h_sbrTransientDetector, sizeof(SBR_TRANSIENT_DETECTOR)); + + h_sbrTransientDetector->frameShift = frameShift; + h_sbrTransientDetector->tran_off = tran_off; + + if (codecBitrate) { + bitrateFactor_m = fDivNorm((FIXP_DBL)totalBitrate, + (FIXP_DBL)(codecBitrate << 2), &bitrateFactor_e); + bitrateFactor_e += 2; + } else { + bitrateFactor_m = FL2FXCONST_DBL(1.0 / 4.0); + bitrateFactor_e = 2; + } + + framedur_fix = fDivNorm(frameSize, sampleFreq); + + /* The longer the frames, the more often should the FIXFIX- + case transmit 2 envelopes instead of 1. + Frame durations below 10 ms produce the highest threshold + so that practically always only 1 env is transmitted. */ + FIXP_DBL tmp = framedur_fix - FL2FXCONST_DBL(0.010); + + tmp = fixMax(tmp, FL2FXCONST_DBL(0.0001)); + tmp = fDivNorm(FL2FXCONST_DBL(0.000075), fPow2(tmp), &tmp_e); + + bitrateFactor_e = (tmp_e + bitrateFactor_e); + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + bitrateFactor_e--; /* divide by 2 */ + } + + FDK_ASSERT(no_cols <= 32); + FDK_ASSERT(no_rows <= 64); + + h_sbrTransientDetector->no_cols = no_cols; + h_sbrTransientDetector->tran_thr = + (FIXP_DBL)((params->tran_thr << (32 - 24 - 1)) / no_rows); + h_sbrTransientDetector->tran_fc = tran_fc; + h_sbrTransientDetector->split_thr_m = fMult(tmp, bitrateFactor_m); + h_sbrTransientDetector->split_thr_e = bitrateFactor_e; + h_sbrTransientDetector->no_rows = no_rows; + h_sbrTransientDetector->mode = params->tran_det_mode; + h_sbrTransientDetector->prevLowBandEnergy = FL2FXCONST_DBL(0.0f); + + return (0); +} + +#define ENERGY_SCALING_SIZE 32 + +INT FDKsbrEnc_InitSbrFastTransientDetector( + HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector, + const INT time_slots_per_frame, const INT bandwidth_qmf_slot, + const INT no_qmf_channels, const INT sbr_qmf_1st_band) { + int i; + int buff_size; + FIXP_DBL myExp; + FIXP_DBL myExpSlot; + + h_sbrFastTransientDetector->lookahead = TRAN_DET_LOOKAHEAD; + h_sbrFastTransientDetector->nTimeSlots = time_slots_per_frame; + + buff_size = h_sbrFastTransientDetector->nTimeSlots + + h_sbrFastTransientDetector->lookahead; + + for (i = 0; i < buff_size; i++) { + h_sbrFastTransientDetector->delta_energy[i] = FL2FXCONST_DBL(0.0f); + h_sbrFastTransientDetector->energy_timeSlots[i] = FL2FXCONST_DBL(0.0f); + h_sbrFastTransientDetector->lowpass_energy[i] = FL2FXCONST_DBL(0.0f); + h_sbrFastTransientDetector->transientCandidates[i] = 0; + } + + FDK_ASSERT(bandwidth_qmf_slot > 0.f); + h_sbrFastTransientDetector->stopBand = + fMin(TRAN_DET_STOP_FREQ / bandwidth_qmf_slot, no_qmf_channels); + h_sbrFastTransientDetector->startBand = + fMin(sbr_qmf_1st_band, + h_sbrFastTransientDetector->stopBand - TRAN_DET_MIN_QMFBANDS); + + FDK_ASSERT(h_sbrFastTransientDetector->startBand < no_qmf_channels); + FDK_ASSERT(h_sbrFastTransientDetector->startBand < + h_sbrFastTransientDetector->stopBand); + FDK_ASSERT(h_sbrFastTransientDetector->startBand > 1); + FDK_ASSERT(h_sbrFastTransientDetector->stopBand > 1); + + /* the energy weighting and adding up has a headroom of 6 Bits, + so up to 64 bands can be added without potential overflow. */ + FDK_ASSERT(h_sbrFastTransientDetector->stopBand - + h_sbrFastTransientDetector->startBand <= + 64); + +/* QMF_HP_dB_SLOPE_FIX says that we want a 20 dB per 16 kHz HP filter. + The following lines map this to the QMF bandwidth. */ +#define EXP_E 7 /* 64 (=64) multiplications max, max. allowed sum is 0.5 */ + myExp = fMultNorm(QMF_HP_dBd_SLOPE_FIX, 0, (FIXP_DBL)bandwidth_qmf_slot, + DFRACT_BITS - 1, EXP_E); + myExpSlot = myExp; + + for (i = 0; i < 64; i++) { + /* Calculate dBf over all qmf bands: + dBf = (10^(0.002266f/10*bw(slot)))^(band) = + = 2^(log2(10)*0.002266f/10*bw(slot)*band) = + = 2^(0.00075275f*bw(slot)*band) */ + + FIXP_DBL dBf_m; /* dBf mantissa */ + INT dBf_e; /* dBf exponent */ + INT tmp; + + INT dBf_int; /* dBf integer part */ + FIXP_DBL dBf_fract; /* dBf fractional part */ + + /* myExp*(i+1) = myExp_int - myExp_fract + myExp*(i+1) is split up here for better accuracy of CalcInvLdData(), + for its result can be split up into an integer and a fractional part */ + + /* Round up to next integer */ + FIXP_DBL myExp_int = + (myExpSlot & (FIXP_DBL)0xfe000000) + (FIXP_DBL)0x02000000; + + /* This is the fractional part that needs to be substracted */ + FIXP_DBL myExp_fract = myExp_int - myExpSlot; + + /* Calc integer part */ + dBf_int = CalcInvLdData(myExp_int); + /* The result needs to be re-scaled. The ld(myExp_int) had been scaled by + EXP_E, the CalcInvLdData expects the operand to be scaled by + LD_DATA_SHIFT. Therefore, the correctly scaled result is + dBf_int^(2^(EXP_E-LD_DATA_SHIFT)), which is dBf_int^2 */ + + if (dBf_int <= + 46340) { /* compare with maximum allowed value for signed integer + multiplication, 46340 = + (INT)floor(sqrt((double)(((UINT)1<<(DFRACT_BITS-1))-1))) */ + dBf_int *= dBf_int; + + /* Calc fractional part */ + dBf_fract = CalcInvLdData(-myExp_fract); + /* The result needs to be re-scaled. The ld(myExp_fract) had been scaled + by EXP_E, the CalcInvLdData expects the operand to be scaled by + LD_DATA_SHIFT. Therefore, the correctly scaled result is + dBf_fract^(2^(EXP_E-LD_DATA_SHIFT)), which is dBf_fract^2 */ + dBf_fract = fMultNorm(dBf_fract, dBf_fract, &tmp); + + /* Get worst case scaling of multiplication result */ + dBf_e = (DFRACT_BITS - 1 - tmp) - CountLeadingBits(dBf_int); + + /* Now multiply integer with fractional part of the result, thus resulting + in the overall accurate fractional result */ + dBf_m = fMultNorm(dBf_int, DFRACT_BITS - 1, dBf_fract, tmp, dBf_e); + + myExpSlot += myExp; + } else { + dBf_m = (FIXP_DBL)0; + dBf_e = 0; + } + + /* Keep the results */ + h_sbrFastTransientDetector->dBf_m[i] = dBf_m; + h_sbrFastTransientDetector->dBf_e[i] = dBf_e; + } + + /* Make sure that dBf is greater than 1.0 (because it should be a highpass) */ + /* ... */ + + return 0; +} + +void FDKsbrEnc_fastTransientDetect( + const HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector, + const FIXP_DBL *const *Energies, const int *const scaleEnergies, + const INT YBufferWriteOffset, UCHAR *const tran_vector) { + int timeSlot, band; + + FIXP_DBL max_delta_energy; /* helper to store maximum energy ratio */ + int max_delta_energy_scale; /* helper to store scale of maximum energy ratio + */ + int ind_max = 0; /* helper to store index of maximum energy ratio */ + int isTransientInFrame = 0; + + const int nTimeSlots = h_sbrFastTransientDetector->nTimeSlots; + const int lookahead = h_sbrFastTransientDetector->lookahead; + const int startBand = h_sbrFastTransientDetector->startBand; + const int stopBand = h_sbrFastTransientDetector->stopBand; + + int *transientCandidates = h_sbrFastTransientDetector->transientCandidates; + + FIXP_DBL *energy_timeSlots = h_sbrFastTransientDetector->energy_timeSlots; + int *energy_timeSlots_scale = + h_sbrFastTransientDetector->energy_timeSlots_scale; + + FIXP_DBL *delta_energy = h_sbrFastTransientDetector->delta_energy; + int *delta_energy_scale = h_sbrFastTransientDetector->delta_energy_scale; + + const FIXP_DBL thr = TRAN_DET_THRSHLD; + const INT thr_scale = TRAN_DET_THRSHLD_SCALE; + + /*reset transient info*/ + tran_vector[2] = 0; + + /* reset transient candidates */ + FDKmemclear(transientCandidates + lookahead, nTimeSlots * sizeof(int)); + + for (timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) { + int i, norm; + FIXP_DBL tmpE = FL2FXCONST_DBL(0.0f); + int headroomEnSlot = DFRACT_BITS - 1; + + FIXP_DBL smallNRG = FL2FXCONST_DBL(1e-2f); + FIXP_DBL denominator; + INT denominator_scale; + + /* determine minimum headroom of energy values for this timeslot */ + for (band = startBand; band < stopBand; band++) { + int tmp_headroom = fNormz(Energies[timeSlot][band]) - 1; + if (tmp_headroom < headroomEnSlot) { + headroomEnSlot = tmp_headroom; + } + } + + for (i = 0, band = startBand; band < stopBand; band++, i++) { + /* energy is weighted by weightingfactor stored in dBf_m array */ + /* dBf_m index runs from 0 to stopBand-startband */ + /* energy shifted by calculated headroom for maximum precision */ + FIXP_DBL weightedEnergy = + fMult(Energies[timeSlot][band] << headroomEnSlot, + h_sbrFastTransientDetector->dBf_m[i]); + + /* energy is added up */ + /* shift by 6 to have a headroom for maximum 64 additions */ + /* shift by dBf_e to handle weighting factor dependent scale factors */ + tmpE += + weightedEnergy >> (6 + (10 - h_sbrFastTransientDetector->dBf_e[i])); + } + + /* store calculated energy for timeslot */ + energy_timeSlots[timeSlot] = tmpE; + + /* calculate overall scale factor for energy of this timeslot */ + /* = original scale factor of energies + * (-scaleEnergies[0]+2*QMF_SCALE_OFFSET or + * -scaleEnergies[1]+2*QMF_SCALE_OFFSET */ + /* depending on YBufferWriteOffset) */ + /* + weighting factor scale (10) */ + /* + adding up scale factor ( 6) */ + /* - headroom of energy value (headroomEnSlot) */ + if (timeSlot < YBufferWriteOffset) { + energy_timeSlots_scale[timeSlot] = + (-scaleEnergies[0] + 2 * QMF_SCALE_OFFSET) + (10 + 6) - + headroomEnSlot; + } else { + energy_timeSlots_scale[timeSlot] = + (-scaleEnergies[1] + 2 * QMF_SCALE_OFFSET) + (10 + 6) - + headroomEnSlot; + } + + /* Add a small energy to the denominator, thus making the transient + detection energy-dependent. Loud transients are being detected, + silent ones not. */ + + /* make sure that smallNRG does not overflow */ + if (-energy_timeSlots_scale[timeSlot - 1] + 1 > 5) { + denominator = smallNRG; + denominator_scale = 0; + } else { + /* Leave an additional headroom of 1 bit for this addition. */ + smallNRG = + scaleValue(smallNRG, -(energy_timeSlots_scale[timeSlot - 1] + 1)); + denominator = (energy_timeSlots[timeSlot - 1] >> 1) + smallNRG; + denominator_scale = energy_timeSlots_scale[timeSlot - 1] + 1; + } + + delta_energy[timeSlot] = + fDivNorm(energy_timeSlots[timeSlot], denominator, &norm); + delta_energy_scale[timeSlot] = + energy_timeSlots_scale[timeSlot] - denominator_scale + norm; + } + + /*get transient candidates*/ + /* For every timeslot, check if delta(E) exceeds the threshold. If it did, + it could potentially be marked as a transient candidate. However, the 2 + slots before the current one must not be transients with an energy higher + than 1.4*E(current). If both aren't transients or if the energy of the + current timesolot is more than 1.4 times higher than the energy in the + last or the one before the last slot, it is marked as a transient.*/ + + FDK_ASSERT(lookahead >= 2); + for (timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) { + FIXP_DBL energy_cur_slot_weighted = + fMult(energy_timeSlots[timeSlot], FL2FXCONST_DBL(1.0f / 1.4f)); + if (!fIsLessThan(delta_energy[timeSlot], delta_energy_scale[timeSlot], thr, + thr_scale) && + (((transientCandidates[timeSlot - 2] == 0) && + (transientCandidates[timeSlot - 1] == 0)) || + !fIsLessThan(energy_cur_slot_weighted, + energy_timeSlots_scale[timeSlot], + energy_timeSlots[timeSlot - 1], + energy_timeSlots_scale[timeSlot - 1]) || + !fIsLessThan(energy_cur_slot_weighted, + energy_timeSlots_scale[timeSlot], + energy_timeSlots[timeSlot - 2], + energy_timeSlots_scale[timeSlot - 2]))) { + /* in case of strong transients, subsequent + * qmf slots might be recognized as transients. */ + transientCandidates[timeSlot] = 1; + } + } + + /*get transient with max energy*/ + max_delta_energy = FL2FXCONST_DBL(0.0f); + max_delta_energy_scale = 0; + ind_max = 0; + isTransientInFrame = 0; + for (timeSlot = 0; timeSlot < nTimeSlots; timeSlot++) { + int scale = fMax(delta_energy_scale[timeSlot], max_delta_energy_scale); + if (transientCandidates[timeSlot] && + ((delta_energy[timeSlot] >> (scale - delta_energy_scale[timeSlot])) > + (max_delta_energy >> (scale - max_delta_energy_scale)))) { + max_delta_energy = delta_energy[timeSlot]; + max_delta_energy_scale = scale; + ind_max = timeSlot; + isTransientInFrame = 1; + } + } + + /*from all transient candidates take the one with the biggest energy*/ + if (isTransientInFrame) { + tran_vector[0] = ind_max; + tran_vector[1] = 1; + } else { + /*reset transient info*/ + tran_vector[0] = tran_vector[1] = 0; + } + + /*check for transients in lookahead*/ + for (timeSlot = nTimeSlots; timeSlot < nTimeSlots + lookahead; timeSlot++) { + if (transientCandidates[timeSlot]) { + tran_vector[2] = 1; + } + } + + /*update buffers*/ + for (timeSlot = 0; timeSlot < lookahead; timeSlot++) { + transientCandidates[timeSlot] = transientCandidates[nTimeSlots + timeSlot]; + + /* fixpoint stuff */ + energy_timeSlots[timeSlot] = energy_timeSlots[nTimeSlots + timeSlot]; + energy_timeSlots_scale[timeSlot] = + energy_timeSlots_scale[nTimeSlots + timeSlot]; + + delta_energy[timeSlot] = delta_energy[nTimeSlots + timeSlot]; + delta_energy_scale[timeSlot] = delta_energy_scale[nTimeSlots + timeSlot]; + } +} diff --git a/fdk-aac/libSBRenc/src/tran_det.h b/fdk-aac/libSBRenc/src/tran_det.h new file mode 100644 index 0000000..d10a7db --- /dev/null +++ b/fdk-aac/libSBRenc/src/tran_det.h @@ -0,0 +1,191 @@ +/* ----------------------------------------------------------------------------- +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 encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +/*! + \file + \brief Transient detector prototypes $Revision: 95111 $ +*/ +#ifndef TRAN_DET_H +#define TRAN_DET_H + +#include "sbr_encoder.h" +#include "sbr_def.h" + +typedef struct { + FIXP_DBL transients[32 + (32 / 2)]; + FIXP_DBL thresholds[64]; + FIXP_DBL tran_thr; /* Master threshold for transient signals */ + FIXP_DBL split_thr_m; /* Threshold for splitting FIXFIX-frames into 2 env */ + INT split_thr_e; /* Scale for splitting threshold */ + FIXP_DBL prevLowBandEnergy; /* Energy of low band */ + FIXP_DBL prevHighBandEnergy; /* Energy of high band */ + INT tran_fc; /* Number of lowband subbands to discard */ + INT no_cols; + INT no_rows; + INT mode; + + int frameShift; + int tran_off; /* Offset for reading energy values. */ +} SBR_TRANSIENT_DETECTOR; + +typedef SBR_TRANSIENT_DETECTOR *HANDLE_SBR_TRANSIENT_DETECTOR; + +#define TRAN_DET_LOOKAHEAD 2 +#define TRAN_DET_START_FREQ 4500 /*start frequency for transient detection*/ +#define TRAN_DET_STOP_FREQ 13500 /*stop frequency for transient detection*/ +#define TRAN_DET_MIN_QMFBANDS \ + 4 /* minimum qmf bands for transient detection \ + */ +#define QMF_HP_dBd_SLOPE_FIX \ + FL2FXCONST_DBL(0.00075275f) /* 0.002266f/10 * log2(10) */ +#define TRAN_DET_THRSHLD FL2FXCONST_DBL(5.0f / 8.0f) +#define TRAN_DET_THRSHLD_SCALE (3) + +typedef struct { + INT transientCandidates[32 + TRAN_DET_LOOKAHEAD]; + INT nTimeSlots; + INT lookahead; + INT startBand; + INT stopBand; + + FIXP_DBL dBf_m[64]; + INT dBf_e[64]; + + FIXP_DBL energy_timeSlots[32 + TRAN_DET_LOOKAHEAD]; + INT energy_timeSlots_scale[32 + TRAN_DET_LOOKAHEAD]; + + FIXP_DBL delta_energy[32 + TRAN_DET_LOOKAHEAD]; + INT delta_energy_scale[32 + TRAN_DET_LOOKAHEAD]; + + FIXP_DBL lowpass_energy[32 + TRAN_DET_LOOKAHEAD]; + INT lowpass_energy_scale[32 + TRAN_DET_LOOKAHEAD]; +} FAST_TRAN_DETECTOR; +typedef FAST_TRAN_DETECTOR *HANDLE_FAST_TRAN_DET; + +INT FDKsbrEnc_InitSbrFastTransientDetector( + HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector, + const INT time_slots_per_frame, const INT bandwidth_qmf_slot, + const INT no_qmf_channels, const INT sbr_qmf_1st_band); + +void FDKsbrEnc_fastTransientDetect( + const HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector, + const FIXP_DBL *const *Energies, const int *const scaleEnergies, + const INT YBufferWriteOffset, UCHAR *const tran_vector); + +void FDKsbrEnc_transientDetect( + HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, FIXP_DBL **Energies, + INT *scaleEnergies, UCHAR *tran_vector, int YBufferWriteOffset, + int YBufferSzShift, int timeStep, int frameMiddleBorder); + +int FDKsbrEnc_InitSbrTransientDetector( + HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + UINT sbrSyntaxFlags, /* SBR syntax flags derived from AOT. */ + INT frameSize, INT sampleFreq, sbrConfigurationPtr params, int tran_fc, + int no_cols, int no_rows, int YBufferWriteOffset, int YBufferSzShift, + int frameShift, int tran_off); + +void FDKsbrEnc_frameSplitter( + FIXP_DBL **Energies, INT *scaleEnergies, + HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, UCHAR *freqBandTable, + UCHAR *tran_vector, int YBufferWriteOffset, int YBufferSzShift, int nSfb, + int timeStep, int no_cols, FIXP_DBL *tonality); +#endif |