mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-02-18 12:10:38 +01:00
Bug: 71430241 Test: CTS DecoderTest and DecoderTestAacDrc original-Change-Id: Iaa20f749b8a04d553b20247cfe1a8930ebbabe30 Apply clang-format also on header files. original-Change-Id: I14de1ef16bbc79ec0283e745f98356a10efeb2e4 Fixes for MPEG-D DRC original-Change-Id: If1de2d74bbbac84b3f67de3b88b83f6a23b8a15c Catch unsupported tw_mdct at an early stage original-Change-Id: Ied9dd00d754162a0e3ca1ae3e6b854315d818afe Fixing PVC transition frames original-Change-Id: Ib75725abe39252806c32d71176308f2c03547a4e Move qmf bands sanity check original-Change-Id: Iab540c3013c174d9490d2ae100a4576f51d8dbc4 Initialize scaling variable original-Change-Id: I3c4087101b70e998c71c1689b122b0d7762e0f9e Add 16 qmf band configuration to getSlotNrgHQ() original-Change-Id: I49a5d30f703a1b126ff163df9656db2540df21f1 Always apply byte alignment at the end of the AudioMuxElement original-Change-Id: I42d560287506d65d4c3de8bfe3eb9a4ebeb4efc7 Setup SBR element only if no parse error exists original-Change-Id: I1915b73704bc80ab882b9173d6bec59cbd073676 Additional array index check in HCR original-Change-Id: I18cc6e501ea683b5009f1bbee26de8ddd04d8267 Fix fade-in index selection in concealment module original-Change-Id: Ibf802ed6ed8c05e9257e1f3b6d0ac1162e9b81c1 Enable explicit backward compatible parser for AAC_LD original-Change-Id: I27e9c678dcb5d40ed760a6d1e06609563d02482d Skip spatial specific config in explicit backward compatible ASC original-Change-Id: Iff7cc365561319e886090cedf30533f562ea4d6e Update flags description in decoder API original-Change-Id: I9a5b4f8da76bb652f5580cbd3ba9760425c43830 Add QMF domain reset function original-Change-Id: I4f89a8a2c0277d18103380134e4ed86996e9d8d6 DRC upgrade v2.1.0 original-Change-Id: I5731c0540139dab220094cd978ef42099fc45b74 Fix integer overflow in sqrtFixp_lookup() original-Change-Id: I429a6f0d19aa2cc957e0f181066f0ca73968c914 Fix integer overflow in invSqrtNorm2() original-Change-Id: I84de5cbf9fb3adeb611db203fe492fabf4eb6155 Fix integer overflow in GenerateRandomVector() original-Change-Id: I3118a641008bd9484d479e5b0b1ee2b5d7d44d74 Fix integer overflow in adjustTimeSlot_EldGrid() original-Change-Id: I29d503c247c5c8282349b79df940416a512fb9d5 Fix integer overflow in FDKsbrEnc_codeEnvelope() original-Change-Id: I6b34b61ebb9d525b0c651ed08de2befc1f801449 Follow-up on: Fix integer overflow in adjustTimeSlot_EldGrid() original-Change-Id: I6f8f578cc7089e5eb7c7b93e580b72ca35ad689a Fix integer overflow in get_pk_v2() original-Change-Id: I63375bed40d45867f6eeaa72b20b1f33e815938c Fix integer overflow in Syn_filt_zero() original-Change-Id: Ie0c02fdfbe03988f9d3b20d10cd9fe4c002d1279 Fix integer overflow in CFac_CalcFacSignal() original-Change-Id: Id2d767c40066c591b51768e978eb8af3b803f0c5 Fix integer overflow in FDKaacEnc_FDKaacEnc_calcPeNoAH() original-Change-Id: Idcbd0f4a51ae2550ed106aa6f3d678d1f9724841 Fix integer overflow in sbrDecoder_calculateGainVec() original-Change-Id: I7081bcbe29c5cede9821b38d93de07c7add2d507 Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I4a95ddc18de150102352d4a1845f06094764c881 Fix integer overflow in Pred_Lt4() original-Change-Id: I4dbd012b2de7d07c3e70a47b92e3bfae8dbc750a Fix integer overflow in FDKsbrEnc_InitSbrFastTransientDetector() original-Change-Id: I788cbec1a4a00f44c2f3a72ad7a4afa219807d04 Fix unsigned integer overflow in FDKaacEnc_WriteBitstream() original-Change-Id: I68fc75166e7d2cd5cd45b18dbe3d8c2a92f1822a Fix unsigned integer overflow in FDK_MetadataEnc_Init() original-Change-Id: Ie8d025f9bcdb2442c704bd196e61065c03c10af4 Fix overflow in pseudo random number generators original-Change-Id: I3e2551ee01356297ca14e3788436ede80bd5513c Fix unsigned integer overflow in sbrDecoder_Parse() original-Change-Id: I3f231b2f437e9c37db4d5b964164686710eee971 Fix unsigned integer overflow in longsub() original-Change-Id: I73c2bc50415cac26f1f5a29e125bbe75f9180a6e Fix unsigned integer overflow in CAacDecoder_DecodeFrame() original-Change-Id: Ifce2db4b1454b46fa5f887e9d383f1cc43b291e4 Fix overflow at CLpdChannelStream_Read() original-Change-Id: Idb9d822ce3a4272e4794b643644f5434e2d4bf3f Fix unsigned integer overflow in Hcr_State_BODY_SIGN_ESC__ESC_WORD() original-Change-Id: I1ccf77c0015684b85534c5eb97162740a870b71c Fix unsigned integer overflow in UsacConfig_Parse() original-Change-Id: Ie6d27f84b6ae7eef092ecbff4447941c77864d9f Fix unsigned integer overflow in aacDecoder_drcParse() original-Change-Id: I713f28e883eea3d70b6fa56a7b8f8c22bcf66ca0 Fix unsigned integer overflow in aacDecoder_drcReadCompression() original-Change-Id: Ia34dfeb88c4705c558bce34314f584965cafcf7a Fix unsigned integer overflow in CDataStreamElement_Read() original-Change-Id: Iae896cc1d11f0a893d21be6aa90bd3e60a2c25f0 Fix unsigned integer overflow in transportDec_AdjustEndOfAccessUnit() original-Change-Id: I64cf29a153ee784bb4a16fdc088baabebc0007dc Fix unsigned integer overflow in transportDec_GetAuBitsRemaining() original-Change-Id: I975b3420faa9c16a041874ba0db82e92035962e4 Fix unsigned integer overflow in extractExtendedData() original-Change-Id: I2a59eb09e2053cfb58dfb75fcecfad6b85a80a8f Fix signed integer overflow in CAacDecoder_ExtPayloadParse() original-Change-Id: I4ad5ca4e3b83b5d964f1c2f8c5e7b17c477c7929 Fix unsigned integer overflow in CAacDecoder_DecodeFrame() original-Change-Id: I29a39df77d45c52a0c9c5c83c1ba81f8d0f25090 Follow-up on: Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I8fb194ffc073a3432a380845be71036a272d388f Fix signed integer overflow in _interpolateDrcGain() original-Change-Id: I879ec9ab14005069a7c47faf80e8bc6e03d22e60 Fix unsigned integer overflow in FDKreadBits() original-Change-Id: I1f47a6a8037ff70375aa8844947d5681bb4287ad Fix unsigned integer overflow in FDKbyteAlign() original-Change-Id: Id5f3a11a0c9e50fc6f76ed6c572dbd4e9f2af766 Fix unsigned integer overflow in FDK_get32() original-Change-Id: I9d33b8e97e3d38cbb80629cb859266ca0acdce96 Fix unsigned integer overflow in FDK_pushBack() original-Change-Id: Ic87f899bc8c6acf7a377a8ca7f3ba74c3a1e1c19 Fix unsigned integer overflow in FDK_pushForward() original-Change-Id: I3b754382f6776a34be1602e66694ede8e0b8effc Fix unsigned integer overflow in ReadPsData() original-Change-Id: I25361664ba8139e32bbbef2ca8c106a606ce9c37 Fix signed integer overflow in E_UTIL_residu() original-Change-Id: I8c3abd1f437ee869caa8fb5903ce7d3d641b6aad REVERT: Follow-up on: Integer overflow in CLpc_SynthesisLattice(). original-Change-Id: I3d340099acb0414795c8dfbe6362bc0a8f045f9b Follow-up on: Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I4aedb8b3a187064e9f4d985175aa55bb99cc7590 Follow-up on: Fix unsigned integer overflow in aacDecoder_drcParse() original-Change-Id: I2aa2e13916213bf52a67e8b0518e7bf7e57fb37d Fix integer overflow in acelp original-Change-Id: Ie6390c136d84055f8b728aefbe4ebef6e029dc77 Fix unsigned integer overflow in aacDecoder_UpdateBitStreamCounters() original-Change-Id: I391ffd97ddb0b2c184cba76139bfb356a3b4d2e2 Adjust concealment default settings original-Change-Id: I6a95db935a327c47df348030bcceafcb29f54b21 Saturate estimatedStartPos original-Change-Id: I27be2085e0ae83ec9501409f65e003f6bcba1ab6 Negative shift exponent in _interpolateDrcGain() original-Change-Id: I18edb26b26d002aafd5e633d4914960f7a359c29 Negative shift exponent in calculateICC() original-Change-Id: I3dcd2ae98d2eb70ee0d59750863cbb2a6f4f8aba Too large shift exponent in FDK_put() original-Change-Id: Ib7d9aaa434d2d8de4a13b720ca0464b31ca9b671 Too large shift exponent in CalcInvLdData() original-Change-Id: I43e6e78d4cd12daeb1dcd5d82d1798bdc2550262 Member access within null pointer of type SBR_CHANNEL original-Change-Id: Idc5e4ea8997810376d2f36bbdf628923b135b097 Member access within null pointer of type CpePersistentData original-Change-Id: Ib6c91cb0d37882768e5baf63324e429589de0d9d Member access within null pointer FDKaacEnc_psyMain() original-Change-Id: I7729b7f4479970531d9dc823abff63ca52e01997 Member access within null pointer FDKaacEnc_GetPnsParam() original-Change-Id: I9aa3b9f3456ae2e0f7483dbd5b3dde95fc62da39 Member access within null pointer FDKsbrEnc_EnvEncodeFrame() original-Change-Id: I67936f90ea714e90b3e81bc0dd1472cc713eb23a Add HCR sanity check original-Change-Id: I6c1d9732ebcf6af12f50b7641400752f74be39f7 Fix memory issue for HBE edge case with 8:3 SBR original-Change-Id: I11ea58a61e69fbe8bf75034b640baee3011e63e9 Additional SBR parametrization sanity check for ELD original-Change-Id: Ie26026fbfe174c2c7b3691f6218b5ce63e322140 Add MPEG-D DRC channel layout check original-Change-Id: Iea70a74f171b227cce636a9eac4ba662777a2f72 Additional out-of-bounds checks in MPEG-D DRC original-Change-Id: Ife4a8c3452c6fde8a0a09e941154a39a769777d4 Change-Id: Ic63cb2f628720f54fe9b572b0cb528e2599c624e
1349 lines
51 KiB
C++
1349 lines
51 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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
|
|
----------------------------------------------------------------------------- */
|
|
|
|
/**************************** AAC encoder library ******************************
|
|
|
|
Author(s): M.Werner
|
|
|
|
Description: Psychoaccoustic major function block
|
|
|
|
*******************************************************************************/
|
|
|
|
#include "psy_const.h"
|
|
|
|
#include "block_switch.h"
|
|
#include "transform.h"
|
|
#include "spreading.h"
|
|
#include "pre_echo_control.h"
|
|
#include "band_nrg.h"
|
|
#include "psy_configuration.h"
|
|
#include "psy_data.h"
|
|
#include "ms_stereo.h"
|
|
#include "interface.h"
|
|
#include "psy_main.h"
|
|
#include "grp_data.h"
|
|
#include "tns_func.h"
|
|
#include "pns_func.h"
|
|
#include "tonality.h"
|
|
#include "aacEnc_ram.h"
|
|
#include "intensity.h"
|
|
|
|
/* blending to reduce gibbs artifacts */
|
|
#define FADE_OUT_LEN 6
|
|
static const FIXP_DBL fadeOutFactor[FADE_OUT_LEN] = {
|
|
1840644096, 1533870080, 1227096064, 920322048, 613548032, 306774016};
|
|
|
|
/* forward definitions */
|
|
|
|
/*****************************************************************************
|
|
|
|
functionname: FDKaacEnc_PsyNew
|
|
description: allocates memory for psychoacoustic
|
|
returns: an error code
|
|
input: pointer to a psych handle
|
|
|
|
*****************************************************************************/
|
|
AAC_ENCODER_ERROR FDKaacEnc_PsyNew(PSY_INTERNAL **phpsy, const INT nElements,
|
|
const INT nChannels, UCHAR *dynamic_RAM) {
|
|
AAC_ENCODER_ERROR ErrorStatus;
|
|
PSY_INTERNAL *hPsy;
|
|
INT i;
|
|
|
|
hPsy = GetRam_aacEnc_PsyInternal();
|
|
*phpsy = hPsy;
|
|
if (hPsy == NULL) {
|
|
ErrorStatus = AAC_ENC_NO_MEMORY;
|
|
goto bail;
|
|
}
|
|
|
|
for (i = 0; i < nElements; i++) {
|
|
/* PSY_ELEMENT */
|
|
hPsy->psyElement[i] = GetRam_aacEnc_PsyElement(i);
|
|
if (hPsy->psyElement[i] == NULL) {
|
|
ErrorStatus = AAC_ENC_NO_MEMORY;
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < nChannels; i++) {
|
|
/* PSY_STATIC */
|
|
hPsy->pStaticChannels[i] = GetRam_aacEnc_PsyStatic(i);
|
|
if (hPsy->pStaticChannels[i] == NULL) {
|
|
ErrorStatus = AAC_ENC_NO_MEMORY;
|
|
goto bail;
|
|
}
|
|
/* AUDIO INPUT BUFFER */
|
|
hPsy->pStaticChannels[i]->psyInputBuffer = GetRam_aacEnc_PsyInputBuffer(i);
|
|
if (hPsy->pStaticChannels[i]->psyInputBuffer == NULL) {
|
|
ErrorStatus = AAC_ENC_NO_MEMORY;
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
/* reusable psych memory */
|
|
hPsy->psyDynamic = GetRam_aacEnc_PsyDynamic(0, dynamic_RAM);
|
|
|
|
return AAC_ENC_OK;
|
|
|
|
bail:
|
|
FDKaacEnc_PsyClose(phpsy, NULL);
|
|
|
|
return ErrorStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
|
|
functionname: FDKaacEnc_PsyOutNew
|
|
description: allocates memory for psyOut struc
|
|
returns: an error code
|
|
input: pointer to a psych handle
|
|
|
|
*****************************************************************************/
|
|
AAC_ENCODER_ERROR FDKaacEnc_PsyOutNew(PSY_OUT **phpsyOut, const INT nElements,
|
|
const INT nChannels, const INT nSubFrames,
|
|
UCHAR *dynamic_RAM) {
|
|
AAC_ENCODER_ERROR ErrorStatus;
|
|
int n, i;
|
|
int elInc = 0, chInc = 0;
|
|
|
|
for (n = 0; n < nSubFrames; n++) {
|
|
phpsyOut[n] = GetRam_aacEnc_PsyOut(n);
|
|
|
|
if (phpsyOut[n] == NULL) {
|
|
ErrorStatus = AAC_ENC_NO_MEMORY;
|
|
goto bail;
|
|
}
|
|
|
|
for (i = 0; i < nChannels; i++) {
|
|
phpsyOut[n]->pPsyOutChannels[i] = GetRam_aacEnc_PsyOutChannel(chInc++);
|
|
if (NULL == phpsyOut[n]->pPsyOutChannels[i]) {
|
|
ErrorStatus = AAC_ENC_NO_MEMORY;
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < nElements; i++) {
|
|
phpsyOut[n]->psyOutElement[i] = GetRam_aacEnc_PsyOutElements(elInc++);
|
|
if (phpsyOut[n]->psyOutElement[i] == NULL) {
|
|
ErrorStatus = AAC_ENC_NO_MEMORY;
|
|
goto bail;
|
|
}
|
|
}
|
|
} /* nSubFrames */
|
|
|
|
return AAC_ENC_OK;
|
|
|
|
bail:
|
|
FDKaacEnc_PsyClose(NULL, phpsyOut);
|
|
return ErrorStatus;
|
|
}
|
|
|
|
AAC_ENCODER_ERROR FDKaacEnc_psyInitStates(PSY_INTERNAL *hPsy,
|
|
PSY_STATIC *psyStatic,
|
|
AUDIO_OBJECT_TYPE audioObjectType) {
|
|
/* init input buffer */
|
|
FDKmemclear(psyStatic->psyInputBuffer,
|
|
MAX_INPUT_BUFFER_SIZE * sizeof(INT_PCM));
|
|
|
|
FDKaacEnc_InitBlockSwitching(&psyStatic->blockSwitchingControl,
|
|
isLowDelay(audioObjectType));
|
|
|
|
return AAC_ENC_OK;
|
|
}
|
|
|
|
AAC_ENCODER_ERROR FDKaacEnc_psyInit(PSY_INTERNAL *hPsy, PSY_OUT **phpsyOut,
|
|
const INT nSubFrames,
|
|
const INT nMaxChannels,
|
|
const AUDIO_OBJECT_TYPE audioObjectType,
|
|
CHANNEL_MAPPING *cm) {
|
|
AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK;
|
|
int i, ch, n, chInc = 0, resetChannels = 3;
|
|
|
|
if ((nMaxChannels > 2) && (cm->nChannels == 2)) {
|
|
chInc = 1;
|
|
FDKaacEnc_psyInitStates(hPsy, hPsy->pStaticChannels[0], audioObjectType);
|
|
}
|
|
|
|
if ((nMaxChannels == 2)) {
|
|
resetChannels = 0;
|
|
}
|
|
|
|
for (i = 0; i < cm->nElements; i++) {
|
|
for (ch = 0; ch < cm->elInfo[i].nChannelsInEl; ch++) {
|
|
hPsy->psyElement[i]->psyStatic[ch] = hPsy->pStaticChannels[chInc];
|
|
if (cm->elInfo[i].elType != ID_LFE) {
|
|
if (chInc >= resetChannels) {
|
|
FDKaacEnc_psyInitStates(hPsy, hPsy->psyElement[i]->psyStatic[ch],
|
|
audioObjectType);
|
|
}
|
|
mdct_init(&(hPsy->psyElement[i]->psyStatic[ch]->mdctPers), NULL, 0);
|
|
hPsy->psyElement[i]->psyStatic[ch]->isLFE = 0;
|
|
} else {
|
|
hPsy->psyElement[i]->psyStatic[ch]->isLFE = 1;
|
|
}
|
|
chInc++;
|
|
}
|
|
}
|
|
|
|
for (n = 0; n < nSubFrames; n++) {
|
|
chInc = 0;
|
|
for (i = 0; i < cm->nElements; i++) {
|
|
for (ch = 0; ch < cm->elInfo[i].nChannelsInEl; ch++) {
|
|
phpsyOut[n]->psyOutElement[i]->psyOutChannel[ch] =
|
|
phpsyOut[n]->pPsyOutChannels[chInc++];
|
|
}
|
|
}
|
|
}
|
|
|
|
return ErrorStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
|
|
functionname: FDKaacEnc_psyMainInit
|
|
description: initializes psychoacoustic
|
|
returns: an error code
|
|
|
|
*****************************************************************************/
|
|
|
|
AAC_ENCODER_ERROR FDKaacEnc_psyMainInit(
|
|
PSY_INTERNAL *hPsy, AUDIO_OBJECT_TYPE audioObjectType, CHANNEL_MAPPING *cm,
|
|
INT sampleRate, INT granuleLength, INT bitRate, INT tnsMask, INT bandwidth,
|
|
INT usePns, INT useIS, INT useMS, UINT syntaxFlags, ULONG initFlags) {
|
|
AAC_ENCODER_ERROR ErrorStatus;
|
|
int i, ch;
|
|
int channelsEff = cm->nChannelsEff;
|
|
int tnsChannels = 0;
|
|
FB_TYPE filterBank;
|
|
|
|
switch (FDKaacEnc_GetMonoStereoMode(cm->encMode)) {
|
|
/* ... and map to tnsChannels */
|
|
case EL_MODE_MONO:
|
|
tnsChannels = 1;
|
|
break;
|
|
case EL_MODE_STEREO:
|
|
tnsChannels = 2;
|
|
break;
|
|
default:
|
|
tnsChannels = 0;
|
|
}
|
|
|
|
switch (audioObjectType) {
|
|
default:
|
|
filterBank = FB_LC;
|
|
break;
|
|
case AOT_ER_AAC_LD:
|
|
filterBank = FB_LD;
|
|
break;
|
|
case AOT_ER_AAC_ELD:
|
|
filterBank = FB_ELD;
|
|
break;
|
|
}
|
|
|
|
hPsy->granuleLength = granuleLength;
|
|
|
|
ErrorStatus = FDKaacEnc_InitPsyConfiguration(
|
|
bitRate / channelsEff, sampleRate, bandwidth, LONG_WINDOW,
|
|
hPsy->granuleLength, useIS, useMS, &(hPsy->psyConf[0]), filterBank);
|
|
if (ErrorStatus != AAC_ENC_OK) return ErrorStatus;
|
|
|
|
ErrorStatus = FDKaacEnc_InitTnsConfiguration(
|
|
(bitRate * tnsChannels) / channelsEff, sampleRate, tnsChannels,
|
|
LONG_WINDOW, hPsy->granuleLength, isLowDelay(audioObjectType),
|
|
(syntaxFlags & AC_SBR_PRESENT) ? 1 : 0, &(hPsy->psyConf[0].tnsConf),
|
|
&hPsy->psyConf[0], (INT)(tnsMask & 2), (INT)(tnsMask & 8));
|
|
|
|
if (ErrorStatus != AAC_ENC_OK) return ErrorStatus;
|
|
|
|
if (granuleLength > 512) {
|
|
ErrorStatus = FDKaacEnc_InitPsyConfiguration(
|
|
bitRate / channelsEff, sampleRate, bandwidth, SHORT_WINDOW,
|
|
hPsy->granuleLength, useIS, useMS, &hPsy->psyConf[1], filterBank);
|
|
|
|
if (ErrorStatus != AAC_ENC_OK) return ErrorStatus;
|
|
|
|
ErrorStatus = FDKaacEnc_InitTnsConfiguration(
|
|
(bitRate * tnsChannels) / channelsEff, sampleRate, tnsChannels,
|
|
SHORT_WINDOW, hPsy->granuleLength, isLowDelay(audioObjectType),
|
|
(syntaxFlags & AC_SBR_PRESENT) ? 1 : 0, &hPsy->psyConf[1].tnsConf,
|
|
&hPsy->psyConf[1], (INT)(tnsMask & 1), (INT)(tnsMask & 4));
|
|
|
|
if (ErrorStatus != AAC_ENC_OK) return ErrorStatus;
|
|
}
|
|
|
|
for (i = 0; i < cm->nElements; i++) {
|
|
for (ch = 0; ch < cm->elInfo[i].nChannelsInEl; ch++) {
|
|
if (initFlags) {
|
|
/* reset states */
|
|
FDKaacEnc_psyInitStates(hPsy, hPsy->psyElement[i]->psyStatic[ch],
|
|
audioObjectType);
|
|
}
|
|
|
|
FDKaacEnc_InitPreEchoControl(
|
|
hPsy->psyElement[i]->psyStatic[ch]->sfbThresholdnm1,
|
|
&hPsy->psyElement[i]->psyStatic[ch]->calcPreEcho,
|
|
hPsy->psyConf[0].sfbCnt, hPsy->psyConf[0].sfbPcmQuantThreshold,
|
|
&hPsy->psyElement[i]->psyStatic[ch]->mdctScalenm1);
|
|
}
|
|
}
|
|
|
|
ErrorStatus = FDKaacEnc_InitPnsConfiguration(
|
|
&hPsy->psyConf[0].pnsConf, bitRate / channelsEff, sampleRate, usePns,
|
|
hPsy->psyConf[0].sfbCnt, hPsy->psyConf[0].sfbOffset,
|
|
cm->elInfo[0].nChannelsInEl, (hPsy->psyConf[0].filterbank == FB_LC));
|
|
if (ErrorStatus != AAC_ENC_OK) return ErrorStatus;
|
|
|
|
if (granuleLength > 512) {
|
|
ErrorStatus = FDKaacEnc_InitPnsConfiguration(
|
|
&hPsy->psyConf[1].pnsConf, bitRate / channelsEff, sampleRate, usePns,
|
|
hPsy->psyConf[1].sfbCnt, hPsy->psyConf[1].sfbOffset,
|
|
cm->elInfo[1].nChannelsInEl, (hPsy->psyConf[1].filterbank == FB_LC));
|
|
if (ErrorStatus != AAC_ENC_OK) return ErrorStatus;
|
|
}
|
|
|
|
return ErrorStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
|
|
functionname: FDKaacEnc_psyMain
|
|
description: psychoacoustic
|
|
returns: an error code
|
|
|
|
This function assumes that enough input data is in the modulo buffer.
|
|
|
|
*****************************************************************************/
|
|
AAC_ENCODER_ERROR FDKaacEnc_psyMain(INT channels, PSY_ELEMENT *psyElement,
|
|
PSY_DYNAMIC *psyDynamic,
|
|
PSY_CONFIGURATION *psyConf,
|
|
PSY_OUT_ELEMENT *RESTRICT psyOutElement,
|
|
INT_PCM *pInput, const UINT inputBufSize,
|
|
INT *chIdx, INT totalChannels) {
|
|
const INT commonWindow = 1;
|
|
INT maxSfbPerGroup[(2)];
|
|
INT mdctSpectrum_e;
|
|
INT ch; /* counts through channels */
|
|
INT w; /* counts through windows */
|
|
INT sfb; /* counts through scalefactor bands */
|
|
INT line; /* counts through lines */
|
|
|
|
PSY_CONFIGURATION *RESTRICT hPsyConfLong = &psyConf[0];
|
|
PSY_CONFIGURATION *RESTRICT hPsyConfShort = &psyConf[1];
|
|
PSY_OUT_CHANNEL **RESTRICT psyOutChannel = psyOutElement->psyOutChannel;
|
|
FIXP_SGL sfbTonality[(2)][MAX_SFB_LONG];
|
|
|
|
PSY_STATIC **RESTRICT psyStatic = psyElement->psyStatic;
|
|
|
|
PSY_DATA *RESTRICT psyData[(2)];
|
|
TNS_DATA *RESTRICT tnsData[(2)];
|
|
PNS_DATA *RESTRICT pnsData[(2)];
|
|
|
|
INT zeroSpec = TRUE; /* means all spectral lines are zero */
|
|
|
|
INT blockSwitchingOffset;
|
|
|
|
PSY_CONFIGURATION *RESTRICT hThisPsyConf[(2)];
|
|
INT windowLength[(2)];
|
|
INT nWindows[(2)];
|
|
INT wOffset;
|
|
|
|
INT maxSfb[(2)];
|
|
INT *pSfbMaxScaleSpec[(2)];
|
|
FIXP_DBL *pSfbEnergy[(2)];
|
|
FIXP_DBL *pSfbSpreadEnergy[(2)];
|
|
FIXP_DBL *pSfbEnergyLdData[(2)];
|
|
FIXP_DBL *pSfbEnergyMS[(2)];
|
|
FIXP_DBL *pSfbThreshold[(2)];
|
|
|
|
INT isShortWindow[(2)];
|
|
|
|
/* number of incoming time samples to be processed */
|
|
const INT nTimeSamples = psyConf->granuleLength;
|
|
|
|
switch (hPsyConfLong->filterbank) {
|
|
case FB_LC:
|
|
blockSwitchingOffset =
|
|
nTimeSamples + (9 * nTimeSamples / (2 * TRANS_FAC));
|
|
break;
|
|
case FB_LD:
|
|
case FB_ELD:
|
|
blockSwitchingOffset = nTimeSamples;
|
|
break;
|
|
default:
|
|
return AAC_ENC_UNSUPPORTED_FILTERBANK;
|
|
}
|
|
|
|
for (ch = 0; ch < channels; ch++) {
|
|
psyData[ch] = &psyDynamic->psyData[ch];
|
|
tnsData[ch] = &psyDynamic->tnsData[ch];
|
|
pnsData[ch] = &psyDynamic->pnsData[ch];
|
|
|
|
psyData[ch]->mdctSpectrum = psyOutChannel[ch]->mdctSpectrum;
|
|
}
|
|
|
|
/* block switching */
|
|
if (hPsyConfLong->filterbank != FB_ELD) {
|
|
int err;
|
|
|
|
for (ch = 0; ch < channels; ch++) {
|
|
C_ALLOC_SCRATCH_START(pTimeSignal, INT_PCM, (1024))
|
|
|
|
/* copy input data and use for block switching */
|
|
FDKmemcpy(pTimeSignal, pInput + chIdx[ch] * inputBufSize,
|
|
nTimeSamples * sizeof(INT_PCM));
|
|
|
|
FDKaacEnc_BlockSwitching(&psyStatic[ch]->blockSwitchingControl,
|
|
nTimeSamples, psyStatic[ch]->isLFE, pTimeSignal);
|
|
|
|
/* fill up internal input buffer, to 2xframelength samples */
|
|
FDKmemcpy(psyStatic[ch]->psyInputBuffer + blockSwitchingOffset,
|
|
pTimeSignal,
|
|
(2 * nTimeSamples - blockSwitchingOffset) * sizeof(INT_PCM));
|
|
|
|
C_ALLOC_SCRATCH_END(pTimeSignal, INT_PCM, (1024))
|
|
}
|
|
|
|
/* synch left and right block type */
|
|
err = FDKaacEnc_SyncBlockSwitching(
|
|
&psyStatic[0]->blockSwitchingControl,
|
|
(channels > 1) ? &psyStatic[1]->blockSwitchingControl : NULL, channels,
|
|
commonWindow);
|
|
|
|
if (err) {
|
|
return AAC_ENC_UNSUPPORTED_AOT; /* mixed up LC and LD */
|
|
}
|
|
|
|
} else {
|
|
for (ch = 0; ch < channels; ch++) {
|
|
/* copy input data and use for block switching */
|
|
FDKmemcpy(psyStatic[ch]->psyInputBuffer + blockSwitchingOffset,
|
|
pInput + chIdx[ch] * inputBufSize,
|
|
nTimeSamples * sizeof(INT_PCM));
|
|
}
|
|
}
|
|
|
|
for (ch = 0; ch < channels; ch++)
|
|
isShortWindow[ch] =
|
|
(psyStatic[ch]->blockSwitchingControl.lastWindowSequence ==
|
|
SHORT_WINDOW);
|
|
|
|
/* set parameters according to window length */
|
|
for (ch = 0; ch < channels; ch++) {
|
|
if (isShortWindow[ch]) {
|
|
hThisPsyConf[ch] = hPsyConfShort;
|
|
windowLength[ch] = psyConf->granuleLength / TRANS_FAC;
|
|
nWindows[ch] = TRANS_FAC;
|
|
maxSfb[ch] = MAX_SFB_SHORT;
|
|
|
|
pSfbMaxScaleSpec[ch] = psyData[ch]->sfbMaxScaleSpec.Short[0];
|
|
pSfbEnergy[ch] = psyData[ch]->sfbEnergy.Short[0];
|
|
pSfbSpreadEnergy[ch] = psyData[ch]->sfbSpreadEnergy.Short[0];
|
|
pSfbEnergyLdData[ch] = psyData[ch]->sfbEnergyLdData.Short[0];
|
|
pSfbEnergyMS[ch] = psyData[ch]->sfbEnergyMS.Short[0];
|
|
pSfbThreshold[ch] = psyData[ch]->sfbThreshold.Short[0];
|
|
|
|
} else {
|
|
hThisPsyConf[ch] = hPsyConfLong;
|
|
windowLength[ch] = psyConf->granuleLength;
|
|
nWindows[ch] = 1;
|
|
maxSfb[ch] = MAX_GROUPED_SFB;
|
|
|
|
pSfbMaxScaleSpec[ch] = psyData[ch]->sfbMaxScaleSpec.Long;
|
|
pSfbEnergy[ch] = psyData[ch]->sfbEnergy.Long;
|
|
pSfbSpreadEnergy[ch] = psyData[ch]->sfbSpreadEnergy.Long;
|
|
pSfbEnergyLdData[ch] = psyData[ch]->sfbEnergyLdData.Long;
|
|
pSfbEnergyMS[ch] = psyData[ch]->sfbEnergyMS.Long;
|
|
pSfbThreshold[ch] = psyData[ch]->sfbThreshold.Long;
|
|
}
|
|
}
|
|
|
|
/* Transform and get mdctScaling for all channels and windows. */
|
|
for (ch = 0; ch < channels; ch++) {
|
|
/* update number of active bands */
|
|
if (psyStatic[ch]->isLFE) {
|
|
psyData[ch]->sfbActive = hThisPsyConf[ch]->sfbActiveLFE;
|
|
psyData[ch]->lowpassLine = hThisPsyConf[ch]->lowpassLineLFE;
|
|
} else {
|
|
psyData[ch]->sfbActive = hThisPsyConf[ch]->sfbActive;
|
|
psyData[ch]->lowpassLine = hThisPsyConf[ch]->lowpassLine;
|
|
}
|
|
|
|
if (hThisPsyConf[ch]->filterbank == FB_ELD) {
|
|
if (FDKaacEnc_Transform_Real_Eld(
|
|
psyStatic[ch]->psyInputBuffer, psyData[ch]->mdctSpectrum,
|
|
psyStatic[ch]->blockSwitchingControl.lastWindowSequence,
|
|
psyStatic[ch]->blockSwitchingControl.windowShape,
|
|
&psyStatic[ch]->blockSwitchingControl.lastWindowShape,
|
|
nTimeSamples, &mdctSpectrum_e, hThisPsyConf[ch]->filterbank,
|
|
psyStatic[ch]->overlapAddBuffer) != 0) {
|
|
return AAC_ENC_UNSUPPORTED_FILTERBANK;
|
|
}
|
|
} else {
|
|
if (FDKaacEnc_Transform_Real(
|
|
psyStatic[ch]->psyInputBuffer, psyData[ch]->mdctSpectrum,
|
|
psyStatic[ch]->blockSwitchingControl.lastWindowSequence,
|
|
psyStatic[ch]->blockSwitchingControl.windowShape,
|
|
&psyStatic[ch]->blockSwitchingControl.lastWindowShape,
|
|
&psyStatic[ch]->mdctPers, nTimeSamples, &mdctSpectrum_e,
|
|
hThisPsyConf[ch]->filterbank) != 0) {
|
|
return AAC_ENC_UNSUPPORTED_FILTERBANK;
|
|
}
|
|
}
|
|
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
wOffset = w * windowLength[ch];
|
|
|
|
/* Low pass / highest sfb */
|
|
FDKmemclear(
|
|
&psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine + wOffset],
|
|
(windowLength[ch] - psyData[ch]->lowpassLine) * sizeof(FIXP_DBL));
|
|
|
|
if ((hPsyConfLong->filterbank != FB_LC) &&
|
|
(psyData[ch]->lowpassLine >= FADE_OUT_LEN)) {
|
|
/* Do blending to reduce gibbs artifacts */
|
|
for (int i = 0; i < FADE_OUT_LEN; i++) {
|
|
psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine + wOffset -
|
|
FADE_OUT_LEN + i] =
|
|
fMult(psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine +
|
|
wOffset - FADE_OUT_LEN + i],
|
|
fadeOutFactor[i]);
|
|
}
|
|
}
|
|
|
|
/* Check for zero spectrum. These loops will usually terminate very, very
|
|
* early. */
|
|
for (line = 0; (line < psyData[ch]->lowpassLine) && (zeroSpec == TRUE);
|
|
line++) {
|
|
if (psyData[ch]->mdctSpectrum[line + wOffset] != (FIXP_DBL)0) {
|
|
zeroSpec = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} /* w loop */
|
|
|
|
psyData[ch]->mdctScale = mdctSpectrum_e;
|
|
|
|
/* rotate internal time samples */
|
|
FDKmemmove(psyStatic[ch]->psyInputBuffer,
|
|
psyStatic[ch]->psyInputBuffer + nTimeSamples,
|
|
nTimeSamples * sizeof(INT_PCM));
|
|
|
|
/* ... and get remaining samples from input buffer */
|
|
FDKmemcpy(psyStatic[ch]->psyInputBuffer + nTimeSamples,
|
|
pInput + (2 * nTimeSamples - blockSwitchingOffset) +
|
|
chIdx[ch] * inputBufSize,
|
|
(blockSwitchingOffset - nTimeSamples) * sizeof(INT_PCM));
|
|
|
|
} /* ch */
|
|
|
|
/* Do some rescaling to get maximum possible accuracy for energies */
|
|
if (zeroSpec == FALSE) {
|
|
/* Calc possible spectrum leftshift for each sfb (1 means: 1 bit left shift
|
|
* is possible without overflow) */
|
|
INT minSpecShift = MAX_SHIFT_DBL;
|
|
INT nrgShift = MAX_SHIFT_DBL;
|
|
INT finalShift = MAX_SHIFT_DBL;
|
|
FIXP_DBL currNrg = 0;
|
|
FIXP_DBL maxNrg = 0;
|
|
|
|
for (ch = 0; ch < channels; ch++) {
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
wOffset = w * windowLength[ch];
|
|
FDKaacEnc_CalcSfbMaxScaleSpec(
|
|
psyData[ch]->mdctSpectrum + wOffset, hThisPsyConf[ch]->sfbOffset,
|
|
pSfbMaxScaleSpec[ch] + w * maxSfb[ch], psyData[ch]->sfbActive);
|
|
|
|
for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++)
|
|
minSpecShift = fixMin(minSpecShift,
|
|
(pSfbMaxScaleSpec[ch] + w * maxSfb[ch])[sfb]);
|
|
}
|
|
}
|
|
|
|
/* Calc possible energy leftshift for each sfb (1 means: 1 bit left shift is
|
|
* possible without overflow) */
|
|
for (ch = 0; ch < channels; ch++) {
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
wOffset = w * windowLength[ch];
|
|
currNrg = FDKaacEnc_CheckBandEnergyOptim(
|
|
psyData[ch]->mdctSpectrum + wOffset,
|
|
pSfbMaxScaleSpec[ch] + w * maxSfb[ch], hThisPsyConf[ch]->sfbOffset,
|
|
psyData[ch]->sfbActive, pSfbEnergy[ch] + w * maxSfb[ch],
|
|
pSfbEnergyLdData[ch] + w * maxSfb[ch], minSpecShift - 4);
|
|
|
|
maxNrg = fixMax(maxNrg, currNrg);
|
|
}
|
|
}
|
|
|
|
if (maxNrg != (FIXP_DBL)0) {
|
|
nrgShift = (CountLeadingBits(maxNrg) >> 1) + (minSpecShift - 4);
|
|
}
|
|
|
|
/* 2check: Hasn't this decision to be made for both channels? */
|
|
/* For short windows 1 additional bit headroom is necessary to prevent
|
|
* overflows when summing up energies in FDKaacEnc_groupShortData() */
|
|
if (isShortWindow[0]) nrgShift--;
|
|
|
|
/* both spectrum and energies mustn't overflow */
|
|
finalShift = fixMin(minSpecShift, nrgShift);
|
|
|
|
/* do not shift more than 3 bits more to the left than signal without
|
|
* blockfloating point would be to avoid overflow of scaled PCM quantization
|
|
* thresholds */
|
|
if (finalShift > psyData[0]->mdctScale + 3)
|
|
finalShift = psyData[0]->mdctScale + 3;
|
|
|
|
FDK_ASSERT(finalShift >= 0); /* right shift is not allowed */
|
|
|
|
/* correct sfbEnergy and sfbEnergyLdData with new finalShift */
|
|
FIXP_DBL ldShift = finalShift * FL2FXCONST_DBL(2.0 / 64);
|
|
for (ch = 0; ch < channels; ch++) {
|
|
INT maxSfb_ch = maxSfb[ch];
|
|
INT w_maxSfb_ch = 0;
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) {
|
|
INT scale = fixMax(0, (pSfbMaxScaleSpec[ch] + w_maxSfb_ch)[sfb] - 4);
|
|
scale = fixMin((scale - finalShift) << 1, DFRACT_BITS - 1);
|
|
if (scale >= 0)
|
|
(pSfbEnergy[ch] + w_maxSfb_ch)[sfb] >>= (scale);
|
|
else
|
|
(pSfbEnergy[ch] + w_maxSfb_ch)[sfb] <<= (-scale);
|
|
(pSfbThreshold[ch] + w_maxSfb_ch)[sfb] =
|
|
fMult((pSfbEnergy[ch] + w_maxSfb_ch)[sfb], C_RATIO);
|
|
(pSfbEnergyLdData[ch] + w_maxSfb_ch)[sfb] += ldShift;
|
|
}
|
|
w_maxSfb_ch += maxSfb_ch;
|
|
}
|
|
}
|
|
|
|
if (finalShift != 0) {
|
|
for (ch = 0; ch < channels; ch++) {
|
|
INT wLen = windowLength[ch];
|
|
INT lowpassLine = psyData[ch]->lowpassLine;
|
|
wOffset = 0;
|
|
FIXP_DBL *mdctSpectrum = &psyData[ch]->mdctSpectrum[0];
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
FIXP_DBL *spectrum = &mdctSpectrum[wOffset];
|
|
for (line = 0; line < lowpassLine; line++) {
|
|
spectrum[line] <<= finalShift;
|
|
}
|
|
wOffset += wLen;
|
|
|
|
/* update sfbMaxScaleSpec */
|
|
for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++)
|
|
(pSfbMaxScaleSpec[ch] + w * maxSfb[ch])[sfb] -= finalShift;
|
|
}
|
|
/* update mdctScale */
|
|
psyData[ch]->mdctScale -= finalShift;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
/* all spectral lines are zero */
|
|
for (ch = 0; ch < channels; ch++) {
|
|
psyData[ch]->mdctScale =
|
|
0; /* otherwise mdctScale would be for example 7 and PCM quantization
|
|
* thresholds would be shifted 14 bits to the right causing some of
|
|
* them to become 0 (which causes problems later) */
|
|
/* clear sfbMaxScaleSpec */
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) {
|
|
(pSfbMaxScaleSpec[ch] + w * maxSfb[ch])[sfb] = 0;
|
|
(pSfbEnergy[ch] + w * maxSfb[ch])[sfb] = (FIXP_DBL)0;
|
|
(pSfbEnergyLdData[ch] + w * maxSfb[ch])[sfb] = FL2FXCONST_DBL(-1.0f);
|
|
(pSfbThreshold[ch] + w * maxSfb[ch])[sfb] = (FIXP_DBL)0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Advance psychoacoustics: Tonality and TNS */
|
|
if ((channels >= 1) && (psyStatic[0]->isLFE)) {
|
|
tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive[HIFILT] = 0;
|
|
tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive[LOFILT] = 0;
|
|
} else {
|
|
for (ch = 0; ch < channels; ch++) {
|
|
if (!isShortWindow[ch]) {
|
|
/* tonality */
|
|
FDKaacEnc_CalculateFullTonality(
|
|
psyData[ch]->mdctSpectrum, pSfbMaxScaleSpec[ch],
|
|
pSfbEnergyLdData[ch], sfbTonality[ch], psyData[ch]->sfbActive,
|
|
hThisPsyConf[ch]->sfbOffset, hThisPsyConf[ch]->pnsConf.usePns);
|
|
}
|
|
} /* ch */
|
|
|
|
if (hPsyConfLong->tnsConf.tnsActive || hPsyConfShort->tnsConf.tnsActive) {
|
|
INT tnsActive[TRANS_FAC] = {0};
|
|
INT nrgScaling[2] = {0, 0};
|
|
INT tnsSpecShift = 0;
|
|
|
|
for (ch = 0; ch < channels; ch++) {
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
wOffset = w * windowLength[ch];
|
|
/* TNS */
|
|
FDKaacEnc_TnsDetect(
|
|
tnsData[ch], &hThisPsyConf[ch]->tnsConf,
|
|
&psyOutChannel[ch]->tnsInfo, hThisPsyConf[ch]->sfbCnt,
|
|
psyData[ch]->mdctSpectrum + wOffset, w,
|
|
psyStatic[ch]->blockSwitchingControl.lastWindowSequence);
|
|
}
|
|
}
|
|
|
|
if (channels == 2) {
|
|
FDKaacEnc_TnsSync(
|
|
tnsData[1], tnsData[0], &psyOutChannel[1]->tnsInfo,
|
|
&psyOutChannel[0]->tnsInfo,
|
|
|
|
psyStatic[1]->blockSwitchingControl.lastWindowSequence,
|
|
psyStatic[0]->blockSwitchingControl.lastWindowSequence,
|
|
&hThisPsyConf[1]->tnsConf);
|
|
}
|
|
|
|
if (channels >= 1) {
|
|
FDK_ASSERT(1 == commonWindow); /* all checks for TNS do only work for
|
|
common windows (which is always set)*/
|
|
for (w = 0; w < nWindows[0]; w++) {
|
|
if (isShortWindow[0])
|
|
tnsActive[w] =
|
|
tnsData[0]->dataRaw.Short.subBlockInfo[w].tnsActive[HIFILT] ||
|
|
tnsData[0]->dataRaw.Short.subBlockInfo[w].tnsActive[LOFILT] ||
|
|
tnsData[channels - 1]
|
|
->dataRaw.Short.subBlockInfo[w]
|
|
.tnsActive[HIFILT] ||
|
|
tnsData[channels - 1]
|
|
->dataRaw.Short.subBlockInfo[w]
|
|
.tnsActive[LOFILT];
|
|
else
|
|
tnsActive[w] =
|
|
tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive[HIFILT] ||
|
|
tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive[LOFILT] ||
|
|
tnsData[channels - 1]
|
|
->dataRaw.Long.subBlockInfo.tnsActive[HIFILT] ||
|
|
tnsData[channels - 1]
|
|
->dataRaw.Long.subBlockInfo.tnsActive[LOFILT];
|
|
}
|
|
}
|
|
|
|
for (ch = 0; ch < channels; ch++) {
|
|
if (tnsActive[0] && !isShortWindow[ch]) {
|
|
/* Scale down spectrum if tns is active in one of the two channels
|
|
* with same lastWindowSequence */
|
|
/* first part of threshold calculation; it's not necessary to update
|
|
* sfbMaxScaleSpec */
|
|
INT shift = 1;
|
|
for (sfb = 0; sfb < hThisPsyConf[ch]->lowpassLine; sfb++) {
|
|
psyData[ch]->mdctSpectrum[sfb] =
|
|
psyData[ch]->mdctSpectrum[sfb] >> shift;
|
|
}
|
|
|
|
/* update thresholds */
|
|
for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) {
|
|
pSfbThreshold[ch][sfb] >>= (2 * shift);
|
|
}
|
|
|
|
psyData[ch]->mdctScale += shift; /* update mdctScale */
|
|
|
|
/* calc sfbEnergies after tnsEncode again ! */
|
|
}
|
|
}
|
|
|
|
for (ch = 0; ch < channels; ch++) {
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
wOffset = w * windowLength[ch];
|
|
FDKaacEnc_TnsEncode(
|
|
&psyOutChannel[ch]->tnsInfo, tnsData[ch],
|
|
hThisPsyConf[ch]->sfbCnt, &hThisPsyConf[ch]->tnsConf,
|
|
hThisPsyConf[ch]->sfbOffset[psyData[ch]->sfbActive],
|
|
/*hThisPsyConf[ch]->lowpassLine*/ /* filter stops
|
|
before that
|
|
line ! */
|
|
psyData[ch]->mdctSpectrum +
|
|
wOffset,
|
|
w, psyStatic[ch]->blockSwitchingControl.lastWindowSequence);
|
|
|
|
if (tnsActive[w]) {
|
|
/* Calc sfb-bandwise mdct-energies for left and right channel again,
|
|
*/
|
|
/* if tns active in current channel or in one channel with same
|
|
* lastWindowSequence left and right */
|
|
FDKaacEnc_CalcSfbMaxScaleSpec(psyData[ch]->mdctSpectrum + wOffset,
|
|
hThisPsyConf[ch]->sfbOffset,
|
|
pSfbMaxScaleSpec[ch] + w * maxSfb[ch],
|
|
psyData[ch]->sfbActive);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (ch = 0; ch < channels; ch++) {
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
if (tnsActive[w]) {
|
|
if (isShortWindow[ch]) {
|
|
FDKaacEnc_CalcBandEnergyOptimShort(
|
|
psyData[ch]->mdctSpectrum + w * windowLength[ch],
|
|
pSfbMaxScaleSpec[ch] + w * maxSfb[ch],
|
|
hThisPsyConf[ch]->sfbOffset, psyData[ch]->sfbActive,
|
|
pSfbEnergy[ch] + w * maxSfb[ch]);
|
|
} else {
|
|
nrgScaling[ch] = /* with tns, energy calculation can overflow; ->
|
|
scaling */
|
|
FDKaacEnc_CalcBandEnergyOptimLong(
|
|
psyData[ch]->mdctSpectrum, pSfbMaxScaleSpec[ch],
|
|
hThisPsyConf[ch]->sfbOffset, psyData[ch]->sfbActive,
|
|
pSfbEnergy[ch], pSfbEnergyLdData[ch]);
|
|
tnsSpecShift =
|
|
fixMax(tnsSpecShift, nrgScaling[ch]); /* nrgScaling is set
|
|
only if nrg would
|
|
have an overflow */
|
|
}
|
|
} /* if tnsActive */
|
|
}
|
|
} /* end channel loop */
|
|
|
|
/* adapt scaling to prevent nrg overflow, only for long blocks */
|
|
for (ch = 0; ch < channels; ch++) {
|
|
if ((tnsSpecShift != 0) && !isShortWindow[ch]) {
|
|
/* scale down spectrum, nrg's and thresholds, if there was an overflow
|
|
* in sfbNrg calculation after tns */
|
|
for (line = 0; line < hThisPsyConf[ch]->lowpassLine; line++) {
|
|
psyData[ch]->mdctSpectrum[line] >>= tnsSpecShift;
|
|
}
|
|
INT scale = (tnsSpecShift - nrgScaling[ch]) << 1;
|
|
for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) {
|
|
pSfbEnergyLdData[ch][sfb] -=
|
|
scale * FL2FXCONST_DBL(1.0 / LD_DATA_SCALING);
|
|
pSfbEnergy[ch][sfb] >>= scale;
|
|
pSfbThreshold[ch][sfb] >>= (tnsSpecShift << 1);
|
|
}
|
|
psyData[ch]->mdctScale += tnsSpecShift; /* update mdctScale; not
|
|
necessary to update
|
|
sfbMaxScaleSpec */
|
|
}
|
|
} /* end channel loop */
|
|
|
|
} /* TNS active */
|
|
else {
|
|
/* In case of disable TNS, reset its dynamic data. Some of its elements is
|
|
* required in PNS detection below. */
|
|
FDKmemclear(psyDynamic->tnsData, sizeof(psyDynamic->tnsData));
|
|
}
|
|
} /* !isLFE */
|
|
|
|
/* Advance thresholds */
|
|
for (ch = 0; ch < channels; ch++) {
|
|
INT headroom;
|
|
|
|
FIXP_DBL clipEnergy;
|
|
INT energyShift = psyData[ch]->mdctScale * 2;
|
|
INT clipNrgShift = energyShift - THR_SHIFTBITS;
|
|
if (isShortWindow[ch])
|
|
headroom = 6;
|
|
else
|
|
headroom = 0;
|
|
|
|
if (clipNrgShift >= 0)
|
|
clipEnergy = hThisPsyConf[ch]->clipEnergy >> clipNrgShift;
|
|
else if (clipNrgShift >= -headroom)
|
|
clipEnergy = hThisPsyConf[ch]->clipEnergy << -clipNrgShift;
|
|
else
|
|
clipEnergy = (FIXP_DBL)MAXVAL_DBL;
|
|
|
|
for (w = 0; w < nWindows[ch]; w++) {
|
|
INT i;
|
|
/* limit threshold to avoid clipping */
|
|
for (i = 0; i < psyData[ch]->sfbActive; i++) {
|
|
*(pSfbThreshold[ch] + w * maxSfb[ch] + i) =
|
|
fixMin(*(pSfbThreshold[ch] + w * maxSfb[ch] + i), clipEnergy);
|
|
}
|
|
|
|
/* spreading */
|
|
FDKaacEnc_SpreadingMax(psyData[ch]->sfbActive,
|
|
hThisPsyConf[ch]->sfbMaskLowFactor,
|
|
hThisPsyConf[ch]->sfbMaskHighFactor,
|
|
pSfbThreshold[ch] + w * maxSfb[ch]);
|
|
|
|
/* PCM quantization threshold */
|
|
energyShift += PCM_QUANT_THR_SCALE;
|
|
if (energyShift >= 0) {
|
|
energyShift = fixMin(DFRACT_BITS - 1, energyShift);
|
|
for (i = 0; i < psyData[ch]->sfbActive; i++) {
|
|
*(pSfbThreshold[ch] + w * maxSfb[ch] + i) = fixMax(
|
|
*(pSfbThreshold[ch] + w * maxSfb[ch] + i) >> THR_SHIFTBITS,
|
|
(hThisPsyConf[ch]->sfbPcmQuantThreshold[i] >> energyShift));
|
|
}
|
|
} else {
|
|
energyShift = fixMin(DFRACT_BITS - 1, -energyShift);
|
|
for (i = 0; i < psyData[ch]->sfbActive; i++) {
|
|
*(pSfbThreshold[ch] + w * maxSfb[ch] + i) = fixMax(
|
|
*(pSfbThreshold[ch] + w * maxSfb[ch] + i) >> THR_SHIFTBITS,
|
|
(hThisPsyConf[ch]->sfbPcmQuantThreshold[i] << energyShift));
|
|
}
|
|
}
|
|
|
|
if (!psyStatic[ch]->isLFE) {
|
|
/* preecho control */
|
|
if (psyStatic[ch]->blockSwitchingControl.lastWindowSequence ==
|
|
STOP_WINDOW) {
|
|
/* prevent FDKaacEnc_PreEchoControl from comparing stop
|
|
thresholds with short thresholds */
|
|
for (i = 0; i < psyData[ch]->sfbActive; i++) {
|
|
psyStatic[ch]->sfbThresholdnm1[i] = (FIXP_DBL)MAXVAL_DBL;
|
|
}
|
|
|
|
psyStatic[ch]->mdctScalenm1 = 0;
|
|
psyStatic[ch]->calcPreEcho = 0;
|
|
}
|
|
|
|
FDKaacEnc_PreEchoControl(
|
|
psyStatic[ch]->sfbThresholdnm1, psyStatic[ch]->calcPreEcho,
|
|
psyData[ch]->sfbActive, hThisPsyConf[ch]->maxAllowedIncreaseFactor,
|
|
hThisPsyConf[ch]->minRemainingThresholdFactor,
|
|
pSfbThreshold[ch] + w * maxSfb[ch], psyData[ch]->mdctScale,
|
|
&psyStatic[ch]->mdctScalenm1);
|
|
|
|
psyStatic[ch]->calcPreEcho = 1;
|
|
|
|
if (psyStatic[ch]->blockSwitchingControl.lastWindowSequence ==
|
|
START_WINDOW) {
|
|
/* prevent FDKaacEnc_PreEchoControl in next frame to compare start
|
|
thresholds with short thresholds */
|
|
for (i = 0; i < psyData[ch]->sfbActive; i++) {
|
|
psyStatic[ch]->sfbThresholdnm1[i] = (FIXP_DBL)MAXVAL_DBL;
|
|
}
|
|
|
|
psyStatic[ch]->mdctScalenm1 = 0;
|
|
psyStatic[ch]->calcPreEcho = 0;
|
|
}
|
|
}
|
|
|
|
/* spread energy to avoid hole detection */
|
|
FDKmemcpy(pSfbSpreadEnergy[ch] + w * maxSfb[ch],
|
|
pSfbEnergy[ch] + w * maxSfb[ch],
|
|
psyData[ch]->sfbActive * sizeof(FIXP_DBL));
|
|
|
|
FDKaacEnc_SpreadingMax(psyData[ch]->sfbActive,
|
|
hThisPsyConf[ch]->sfbMaskLowFactorSprEn,
|
|
hThisPsyConf[ch]->sfbMaskHighFactorSprEn,
|
|
pSfbSpreadEnergy[ch] + w * maxSfb[ch]);
|
|
}
|
|
}
|
|
|
|
/* Calc bandwise energies for mid and side channel. Do it only if 2 channels
|
|
* exist */
|
|
if (channels == 2) {
|
|
for (w = 0; w < nWindows[1]; w++) {
|
|
wOffset = w * windowLength[1];
|
|
FDKaacEnc_CalcBandNrgMSOpt(
|
|
psyData[0]->mdctSpectrum + wOffset,
|
|
psyData[1]->mdctSpectrum + wOffset,
|
|
pSfbMaxScaleSpec[0] + w * maxSfb[0],
|
|
pSfbMaxScaleSpec[1] + w * maxSfb[1], hThisPsyConf[1]->sfbOffset,
|
|
psyData[0]->sfbActive, pSfbEnergyMS[0] + w * maxSfb[0],
|
|
pSfbEnergyMS[1] + w * maxSfb[1],
|
|
(psyStatic[1]->blockSwitchingControl.lastWindowSequence !=
|
|
SHORT_WINDOW),
|
|
psyData[0]->sfbEnergyMSLdData, psyData[1]->sfbEnergyMSLdData);
|
|
}
|
|
}
|
|
|
|
/* group short data (maxSfb[ch] for short blocks is determined here) */
|
|
for (ch = 0; ch < channels; ch++) {
|
|
if (isShortWindow[ch]) {
|
|
int sfbGrp;
|
|
int noSfb = psyStatic[ch]->blockSwitchingControl.noOfGroups *
|
|
hPsyConfShort->sfbCnt;
|
|
/* At this point, energies and thresholds are copied/regrouped from the
|
|
* ".Short" to the ".Long" arrays */
|
|
FDKaacEnc_groupShortData(
|
|
psyData[ch]->mdctSpectrum, &psyData[ch]->sfbThreshold,
|
|
&psyData[ch]->sfbEnergy, &psyData[ch]->sfbEnergyMS,
|
|
&psyData[ch]->sfbSpreadEnergy, hPsyConfShort->sfbCnt,
|
|
psyData[ch]->sfbActive, hPsyConfShort->sfbOffset,
|
|
hPsyConfShort->sfbMinSnrLdData, psyData[ch]->groupedSfbOffset,
|
|
&maxSfbPerGroup[ch], psyOutChannel[ch]->sfbMinSnrLdData,
|
|
psyStatic[ch]->blockSwitchingControl.noOfGroups,
|
|
psyStatic[ch]->blockSwitchingControl.groupLen,
|
|
psyConf[1].granuleLength);
|
|
|
|
/* calculate ldData arrays (short values are in .Long-arrays after
|
|
* FDKaacEnc_groupShortData) */
|
|
for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) {
|
|
LdDataVector(&psyData[ch]->sfbEnergy.Long[sfbGrp],
|
|
&psyOutChannel[ch]->sfbEnergyLdData[sfbGrp],
|
|
psyData[ch]->sfbActive);
|
|
}
|
|
|
|
/* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/
|
|
for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) {
|
|
LdDataVector(&psyData[ch]->sfbThreshold.Long[sfbGrp],
|
|
&psyOutChannel[ch]->sfbThresholdLdData[sfbGrp],
|
|
psyData[ch]->sfbActive);
|
|
for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) {
|
|
psyOutChannel[ch]->sfbThresholdLdData[sfbGrp + sfb] =
|
|
fixMax(psyOutChannel[ch]->sfbThresholdLdData[sfbGrp + sfb],
|
|
FL2FXCONST_DBL(-0.515625f));
|
|
}
|
|
}
|
|
|
|
if (channels == 2) {
|
|
for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) {
|
|
LdDataVector(&psyData[ch]->sfbEnergyMS.Long[sfbGrp],
|
|
&psyData[ch]->sfbEnergyMSLdData[sfbGrp],
|
|
psyData[ch]->sfbActive);
|
|
}
|
|
}
|
|
|
|
FDKmemcpy(psyOutChannel[ch]->sfbOffsets, psyData[ch]->groupedSfbOffset,
|
|
(MAX_GROUPED_SFB + 1) * sizeof(INT));
|
|
|
|
} else {
|
|
int i;
|
|
/* maxSfb[ch] for long blocks */
|
|
for (sfb = psyData[ch]->sfbActive - 1; sfb >= 0; sfb--) {
|
|
for (line = hPsyConfLong->sfbOffset[sfb + 1] - 1;
|
|
line >= hPsyConfLong->sfbOffset[sfb]; line--) {
|
|
if (psyData[ch]->mdctSpectrum[line] != FL2FXCONST_SGL(0.0f)) break;
|
|
}
|
|
if (line > hPsyConfLong->sfbOffset[sfb]) break;
|
|
}
|
|
maxSfbPerGroup[ch] = sfb + 1;
|
|
maxSfbPerGroup[ch] =
|
|
fixMax(fixMin(5, psyData[ch]->sfbActive), maxSfbPerGroup[ch]);
|
|
|
|
/* sfbNrgLdData is calculated in FDKaacEnc_advancePsychLong, copy in
|
|
* psyOut structure */
|
|
FDKmemcpy(psyOutChannel[ch]->sfbEnergyLdData,
|
|
psyData[ch]->sfbEnergyLdData.Long,
|
|
psyData[ch]->sfbActive * sizeof(FIXP_DBL));
|
|
|
|
FDKmemcpy(psyOutChannel[ch]->sfbOffsets, hPsyConfLong->sfbOffset,
|
|
(MAX_GROUPED_SFB + 1) * sizeof(INT));
|
|
|
|
/* sfbMinSnrLdData modified in adjust threshold, copy necessary */
|
|
FDKmemcpy(psyOutChannel[ch]->sfbMinSnrLdData,
|
|
hPsyConfLong->sfbMinSnrLdData,
|
|
psyData[ch]->sfbActive * sizeof(FIXP_DBL));
|
|
|
|
/* sfbEnergyMSLdData ist already calculated in FDKaacEnc_CalcBandNrgMSOpt;
|
|
* only in long case */
|
|
|
|
/* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/
|
|
LdDataVector(psyData[ch]->sfbThreshold.Long,
|
|
psyOutChannel[ch]->sfbThresholdLdData,
|
|
psyData[ch]->sfbActive);
|
|
for (i = 0; i < psyData[ch]->sfbActive; i++) {
|
|
psyOutChannel[ch]->sfbThresholdLdData[i] =
|
|
fixMax(psyOutChannel[ch]->sfbThresholdLdData[i],
|
|
FL2FXCONST_DBL(-0.515625f));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Intensity parameter intialization.
|
|
*/
|
|
for (ch = 0; ch < channels; ch++) {
|
|
FDKmemclear(psyOutChannel[ch]->isBook, MAX_GROUPED_SFB * sizeof(INT));
|
|
FDKmemclear(psyOutChannel[ch]->isScale, MAX_GROUPED_SFB * sizeof(INT));
|
|
}
|
|
|
|
for (ch = 0; ch < channels; ch++) {
|
|
INT win = (isShortWindow[ch] ? 1 : 0);
|
|
if (!psyStatic[ch]->isLFE) {
|
|
/* PNS Decision */
|
|
FDKaacEnc_PnsDetect(
|
|
&(psyConf[0].pnsConf), pnsData[ch],
|
|
psyStatic[ch]->blockSwitchingControl.lastWindowSequence,
|
|
psyData[ch]->sfbActive,
|
|
maxSfbPerGroup[ch], /* count of Sfb which are not zero. */
|
|
psyOutChannel[ch]->sfbThresholdLdData, psyConf[win].sfbOffset,
|
|
psyData[ch]->mdctSpectrum, psyData[ch]->sfbMaxScaleSpec.Long,
|
|
sfbTonality[ch], psyOutChannel[ch]->tnsInfo.order[0][0],
|
|
tnsData[ch]->dataRaw.Long.subBlockInfo.predictionGain[HIFILT],
|
|
tnsData[ch]->dataRaw.Long.subBlockInfo.tnsActive[HIFILT],
|
|
psyOutChannel[ch]->sfbEnergyLdData, psyOutChannel[ch]->noiseNrg);
|
|
} /* !isLFE */
|
|
} /* ch */
|
|
|
|
/*
|
|
stereo Processing
|
|
*/
|
|
if (channels == 2) {
|
|
psyOutElement->toolsInfo.msDigest = MS_NONE;
|
|
psyOutElement->commonWindow = commonWindow;
|
|
if (psyOutElement->commonWindow)
|
|
maxSfbPerGroup[0] = maxSfbPerGroup[1] =
|
|
fixMax(maxSfbPerGroup[0], maxSfbPerGroup[1]);
|
|
if (psyStatic[0]->blockSwitchingControl.lastWindowSequence !=
|
|
SHORT_WINDOW) {
|
|
/* PNS preprocessing depending on ms processing: PNS not in Short Window!
|
|
*/
|
|
FDKaacEnc_PreProcessPnsChannelPair(
|
|
psyData[0]->sfbActive, (&psyData[0]->sfbEnergy)->Long,
|
|
(&psyData[1]->sfbEnergy)->Long, psyOutChannel[0]->sfbEnergyLdData,
|
|
psyOutChannel[1]->sfbEnergyLdData, psyData[0]->sfbEnergyMS.Long,
|
|
&(psyConf[0].pnsConf), pnsData[0], pnsData[1]);
|
|
|
|
FDKaacEnc_IntensityStereoProcessing(
|
|
psyData[0]->sfbEnergy.Long, psyData[1]->sfbEnergy.Long,
|
|
psyData[0]->mdctSpectrum, psyData[1]->mdctSpectrum,
|
|
psyData[0]->sfbThreshold.Long, psyData[1]->sfbThreshold.Long,
|
|
psyOutChannel[1]->sfbThresholdLdData,
|
|
psyData[0]->sfbSpreadEnergy.Long, psyData[1]->sfbSpreadEnergy.Long,
|
|
psyOutChannel[0]->sfbEnergyLdData, psyOutChannel[1]->sfbEnergyLdData,
|
|
&psyOutElement->toolsInfo.msDigest, psyOutElement->toolsInfo.msMask,
|
|
psyConf[0].sfbCnt, psyConf[0].sfbCnt, maxSfbPerGroup[0],
|
|
psyConf[0].sfbOffset,
|
|
psyConf[0].allowIS && psyOutElement->commonWindow,
|
|
psyOutChannel[1]->isBook, psyOutChannel[1]->isScale, pnsData);
|
|
|
|
FDKaacEnc_MsStereoProcessing(
|
|
psyData, psyOutChannel, psyOutChannel[1]->isBook,
|
|
&psyOutElement->toolsInfo.msDigest, psyOutElement->toolsInfo.msMask,
|
|
psyConf[0].allowMS, psyData[0]->sfbActive, psyData[0]->sfbActive,
|
|
maxSfbPerGroup[0], psyOutChannel[0]->sfbOffsets);
|
|
|
|
/* PNS postprocessing */
|
|
FDKaacEnc_PostProcessPnsChannelPair(
|
|
psyData[0]->sfbActive, &(psyConf[0].pnsConf), pnsData[0], pnsData[1],
|
|
psyOutElement->toolsInfo.msMask, &psyOutElement->toolsInfo.msDigest);
|
|
|
|
} else {
|
|
FDKaacEnc_IntensityStereoProcessing(
|
|
psyData[0]->sfbEnergy.Long, psyData[1]->sfbEnergy.Long,
|
|
psyData[0]->mdctSpectrum, psyData[1]->mdctSpectrum,
|
|
psyData[0]->sfbThreshold.Long, psyData[1]->sfbThreshold.Long,
|
|
psyOutChannel[1]->sfbThresholdLdData,
|
|
psyData[0]->sfbSpreadEnergy.Long, psyData[1]->sfbSpreadEnergy.Long,
|
|
psyOutChannel[0]->sfbEnergyLdData, psyOutChannel[1]->sfbEnergyLdData,
|
|
&psyOutElement->toolsInfo.msDigest, psyOutElement->toolsInfo.msMask,
|
|
psyStatic[0]->blockSwitchingControl.noOfGroups *
|
|
hPsyConfShort->sfbCnt,
|
|
psyConf[1].sfbCnt, maxSfbPerGroup[0], psyData[0]->groupedSfbOffset,
|
|
psyConf[0].allowIS && psyOutElement->commonWindow,
|
|
psyOutChannel[1]->isBook, psyOutChannel[1]->isScale, pnsData);
|
|
|
|
/* it's OK to pass the ".Long" arrays here. They contain grouped short
|
|
* data since FDKaacEnc_groupShortData() */
|
|
FDKaacEnc_MsStereoProcessing(
|
|
psyData, psyOutChannel, psyOutChannel[1]->isBook,
|
|
&psyOutElement->toolsInfo.msDigest, psyOutElement->toolsInfo.msMask,
|
|
psyConf[1].allowMS,
|
|
psyStatic[0]->blockSwitchingControl.noOfGroups *
|
|
hPsyConfShort->sfbCnt,
|
|
hPsyConfShort->sfbCnt, maxSfbPerGroup[0],
|
|
psyOutChannel[0]->sfbOffsets);
|
|
}
|
|
} /* (channels == 2) */
|
|
|
|
/*
|
|
PNS Coding
|
|
*/
|
|
for (ch = 0; ch < channels; ch++) {
|
|
if (psyStatic[ch]->isLFE) {
|
|
/* no PNS coding */
|
|
for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) {
|
|
psyOutChannel[ch]->noiseNrg[sfb] = NO_NOISE_PNS;
|
|
}
|
|
} else {
|
|
FDKaacEnc_CodePnsChannel(
|
|
psyData[ch]->sfbActive, &(hThisPsyConf[ch]->pnsConf),
|
|
pnsData[ch]->pnsFlag, psyData[ch]->sfbEnergyLdData.Long,
|
|
psyOutChannel[ch]->noiseNrg, /* this is the energy that will be
|
|
written to the bitstream */
|
|
psyOutChannel[ch]->sfbThresholdLdData);
|
|
}
|
|
}
|
|
|
|
/*
|
|
build output
|
|
*/
|
|
for (ch = 0; ch < channels; ch++) {
|
|
INT mask;
|
|
int grp;
|
|
psyOutChannel[ch]->maxSfbPerGroup = maxSfbPerGroup[ch];
|
|
psyOutChannel[ch]->mdctScale = psyData[ch]->mdctScale;
|
|
if (isShortWindow[ch] == 0) {
|
|
psyOutChannel[ch]->sfbCnt = hPsyConfLong->sfbActive;
|
|
psyOutChannel[ch]->sfbPerGroup = hPsyConfLong->sfbActive;
|
|
psyOutChannel[ch]->lastWindowSequence =
|
|
psyStatic[ch]->blockSwitchingControl.lastWindowSequence;
|
|
psyOutChannel[ch]->windowShape =
|
|
psyStatic[ch]->blockSwitchingControl.windowShape;
|
|
} else {
|
|
INT sfbCnt = psyStatic[ch]->blockSwitchingControl.noOfGroups *
|
|
hPsyConfShort->sfbCnt;
|
|
|
|
psyOutChannel[ch]->sfbCnt = sfbCnt;
|
|
psyOutChannel[ch]->sfbPerGroup = hPsyConfShort->sfbCnt;
|
|
psyOutChannel[ch]->lastWindowSequence = SHORT_WINDOW;
|
|
psyOutChannel[ch]->windowShape = SINE_WINDOW;
|
|
}
|
|
/* generate grouping mask */
|
|
mask = 0;
|
|
for (grp = 0; grp < psyStatic[ch]->blockSwitchingControl.noOfGroups;
|
|
grp++) {
|
|
int j;
|
|
mask <<= 1;
|
|
for (j = 1; j < psyStatic[ch]->blockSwitchingControl.groupLen[grp]; j++) {
|
|
mask = (mask << 1) | 1;
|
|
}
|
|
}
|
|
psyOutChannel[ch]->groupingMask = mask;
|
|
|
|
/* build interface */
|
|
FDKmemcpy(psyOutChannel[ch]->groupLen,
|
|
psyStatic[ch]->blockSwitchingControl.groupLen,
|
|
MAX_NO_OF_GROUPS * sizeof(INT));
|
|
FDKmemcpy(psyOutChannel[ch]->sfbEnergy, (&psyData[ch]->sfbEnergy)->Long,
|
|
MAX_GROUPED_SFB * sizeof(FIXP_DBL));
|
|
FDKmemcpy(psyOutChannel[ch]->sfbSpreadEnergy,
|
|
(&psyData[ch]->sfbSpreadEnergy)->Long,
|
|
MAX_GROUPED_SFB * sizeof(FIXP_DBL));
|
|
// FDKmemcpy(psyOutChannel[ch]->mdctSpectrum,
|
|
// psyData[ch]->mdctSpectrum, (1024)*sizeof(FIXP_DBL));
|
|
}
|
|
|
|
return AAC_ENC_OK;
|
|
}
|
|
|
|
void FDKaacEnc_PsyClose(PSY_INTERNAL **phPsyInternal, PSY_OUT **phPsyOut) {
|
|
int n, i;
|
|
|
|
if (phPsyInternal != NULL) {
|
|
PSY_INTERNAL *hPsyInternal = *phPsyInternal;
|
|
|
|
if (hPsyInternal) {
|
|
for (i = 0; i < (8); i++) {
|
|
if (hPsyInternal->pStaticChannels[i]) {
|
|
if (hPsyInternal->pStaticChannels[i]->psyInputBuffer)
|
|
FreeRam_aacEnc_PsyInputBuffer(
|
|
&hPsyInternal->pStaticChannels[i]
|
|
->psyInputBuffer); /* AUDIO INPUT BUFFER */
|
|
|
|
FreeRam_aacEnc_PsyStatic(
|
|
&hPsyInternal->pStaticChannels[i]); /* PSY_STATIC */
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ((8)); i++) {
|
|
if (hPsyInternal->psyElement[i])
|
|
FreeRam_aacEnc_PsyElement(
|
|
&hPsyInternal->psyElement[i]); /* PSY_ELEMENT */
|
|
}
|
|
|
|
FreeRam_aacEnc_PsyInternal(phPsyInternal);
|
|
}
|
|
}
|
|
|
|
if (phPsyOut != NULL) {
|
|
for (n = 0; n < (1); n++) {
|
|
if (phPsyOut[n]) {
|
|
for (i = 0; i < (8); i++) {
|
|
if (phPsyOut[n]->pPsyOutChannels[i])
|
|
FreeRam_aacEnc_PsyOutChannel(
|
|
&phPsyOut[n]->pPsyOutChannels[i]); /* PSY_OUT_CHANNEL */
|
|
}
|
|
|
|
for (i = 0; i < ((8)); i++) {
|
|
if (phPsyOut[n]->psyOutElement[i])
|
|
FreeRam_aacEnc_PsyOutElements(
|
|
&phPsyOut[n]->psyOutElement[i]); /* PSY_OUT_ELEMENTS */
|
|
}
|
|
|
|
FreeRam_aacEnc_PsyOut(&phPsyOut[n]);
|
|
}
|
|
}
|
|
}
|
|
}
|