Commit 7ad97579 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi

AAC Encoder low delay quality

* AAC-Encoder

   - Revise bit distribution for lowdelay configuration to improve encoder
     audio quality.
   - Adjust lowdelay bitreservoir for low bitreservoir configuration.
     Modified file(s):
        libAACenc\src\aacEnc_ram.cpp
        libAACenc\src\aacenc.cpp
        libAACenc\src\aacenc_lib.cpp
        libAACenc\src\aacenc_tns.cpp
        libAACenc\src\adj_thr.cpp
        libAACenc\src\adj_thr.h
        libAACenc\src\block_switch.cpp
        libAACenc\src\block_switch.h
        libAACenc\src\interface.h
        libAACenc\src\psy_main.cpp
        libAACenc\src\qc_data.h
        libAACenc\src\qc_main.cpp

* FDK-Library

   - Increase the accuracy in CalcInvLdData() calculation which improves the
     encoder audio quality.
     Modified file(s):
        libFDK\src\fixpoint_math.cpp

Bug 9428126

Change-Id: I302d7f4c3aeccf79e1b85f20e18a31e6e2b10544
parent 206a397c
......@@ -89,13 +89,13 @@ amm-info@iis.fraunhofer.de
******************************************************************************/
/*!
\file
\brief Memory layout
\brief Memory layout
\author Markus Lohwasser
*/
#include "aacEnc_ram.h"
C_ALLOC_MEM (AACdynamic_RAM, FIXP_DBL, AAC_ENC_DYN_RAM_SIZE/sizeof(FIXP_DBL))
C_AALLOC_MEM (AACdynamic_RAM, FIXP_DBL, AAC_ENC_DYN_RAM_SIZE/sizeof(FIXP_DBL))
/*
Static memory areas, must not be overwritten in other sections of the decoder !
......@@ -175,7 +175,7 @@ C_ALLOC_MEM (Ram_aacEnc_BitCntrState, BITCNTR_STATE, 1)
*/
C_ALLOC_MEM2 (Ram_aacEnc_QCout, QC_OUT, 1, (1))
C_ALLOC_MEM2 (Ram_aacEnc_QCelement, QC_OUT_ELEMENT, 1, (1)*(6))
C_ALLOC_MEM2 (Ram_aacEnc_QCelement, QC_OUT_ELEMENT, (1), (6))
QC_OUT_CHANNEL *GetRam_aacEnc_QCchannel (int n, UCHAR* dynamic_RAM) {
FDK_ASSERT(dynamic_RAM!=0);
return ((QC_OUT_CHANNEL*) (dynamic_RAM + P_BUF_0 + n*sizeof(QC_OUT_CHANNEL)));
......
......@@ -578,6 +578,8 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize(HANDLE_AAC_ENC hAacEnc,
qcInit.minBits = (config->minBitsPerFrame!=-1) ? fixMax(qcInit.minBits, config->minBitsPerFrame) : qcInit.minBits;
}
qcInit.sampleRate = config->sampleRate;
qcInit.advancedBitsToPe = isLowDelay(config->audioObjectType) ? 1 : 0 ;
qcInit.nSubFrames = config->nSubFrames;
qcInit.padding.paddingRest = config->sampleRate;
......
......@@ -98,7 +98,7 @@ amm-info@iis.fraunhofer.de
/* Encoder library info */
#define AACENCODER_LIB_VL0 3
#define AACENCODER_LIB_VL1 4
#define AACENCODER_LIB_VL2 7
#define AACENCODER_LIB_VL2 8
#define AACENCODER_LIB_TITLE "AAC Encoder"
#define AACENCODER_LIB_BUILD_DATE __DATE__
#define AACENCODER_LIB_BUILD_TIME __TIME__
......@@ -689,7 +689,7 @@ AACENC_ERROR FDKaacEnc_AdjustEncSettings(HANDLE_AACENCODER hAacEncoder,
hAacConfig->bitrateMode = 0;
}
if (config->userBitrateMode==0) {
hAacConfig->bitreservoir = 50*config->nChannels; /* default, reduced bitreservoir */
hAacConfig->bitreservoir = 100*config->nChannels; /* default, reduced bitreservoir */
}
if (hAacConfig->bitrateMode!=0) {
return AACENC_INVALID_CONFIG;
......
......@@ -83,7 +83,7 @@ amm-info@iis.fraunhofer.de
/******************************** MPEG Audio Encoder **************************
Initial author: Alex Groeschel
Initial author: Alex Groeschel, Tobias Chalupka
contents/description: Temporal noise shaping
******************************************************************************/
......
This diff is collapsed.
......@@ -98,13 +98,14 @@ amm-info@iis.fraunhofer.de
#include "interface.h"
void FDKaacEnc_peCalculation(PE_DATA *peData,
PSY_OUT_CHANNEL* psyOutChannel[(2)],
QC_OUT_CHANNEL* qcOutChannel[(2)],
struct TOOLSINFO *toolsInfo,
ATS_ELEMENT* adjThrStateElement,
const INT nChannels);
void FDKaacEnc_peCalculation(
PE_DATA *peData,
PSY_OUT_CHANNEL* psyOutChannel[(2)],
QC_OUT_CHANNEL* qcOutChannel[(2)],
struct TOOLSINFO *toolsInfo,
ATS_ELEMENT* adjThrStateElement,
const INT nChannels
);
INT FDKaacEnc_AdjThrNew(ADJ_THR_STATE** phAdjThr,
INT nElements);
......@@ -112,9 +113,13 @@ INT FDKaacEnc_AdjThrNew(ADJ_THR_STATE** phAdjThr,
void FDKaacEnc_AdjThrInit(ADJ_THR_STATE *hAdjThr,
const INT peMean,
ELEMENT_BITS* elBits[(6)],
INT invQuant,
INT nElements,
INT nChannelsEff,
INT sampleRate,
INT advancedBitsToPe,
FIXP_DBL vbrQualFactor);
void FDKaacEnc_DistributeBits(ADJ_THR_STATE *adjThrState,
ATS_ELEMENT *AdjThrStateElement,
......@@ -128,7 +133,7 @@ void FDKaacEnc_DistributeBits(ADJ_THR_STATE *adjThrState,
const INT bitresBits,
const INT maxBitresBits,
const FIXP_DBL maxBitFac,
const INT bitDistributenMode);
const INT bitDistributionMode);
void FDKaacEnc_AdjustThresholds(ATS_ELEMENT* AdjThrStateElement[(6)],
QC_OUT_ELEMENT* qcElement[(6)],
......
......@@ -83,7 +83,7 @@ amm-info@iis.fraunhofer.de
/***************************** MPEG-4 AAC Encoder **************************
Author(s): M. Werner
Author(s): M. Werner, Tobias Chalupka
Description: Block switching
******************************************************************************/
......@@ -100,9 +100,11 @@ amm-info@iis.fraunhofer.de
static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx);
static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl,
INT windowLen);
static void FDKaacEnc_CalcWindowEnergy(
BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl,
INT windowLen,
const INT_PCM *pTimeSignal
);
/****************** Constants *****************************/
/* LONG START SHORT STOP LOWOV */
......@@ -145,20 +147,9 @@ static const FIXP_DBL minAttackNrg = (FL2FXCONST_DBL(1e+6f*NORM_PCM_ENERGY)>>BLO
/**************** internal function prototypes ***********/
static INT FDKaacEnc_GetWindowIndex(INT blockSwWindowIndex);
static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT shortWndIdx);
static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl,
INT windowLen);
/****************** Routines ****************************/
void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay)
{
/* note: the pointer to timeSignal can be zeroed here, because it is initialized for every call
to FDKaacEnc_BlockSwitching anew */
FDKmemclear (blockSwitchingControl, sizeof(BLOCK_SWITCHING_CONTROL));
if (isLowDelay)
......@@ -214,7 +205,7 @@ static const INT chgWndSqLkAhd[2][2][N_BLOCKTYPES] =
/*attack */ {START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} } /* attack */
};
int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE)
int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE, const INT_PCM *pTimeSignal)
{
UINT i;
FIXP_DBL enM1, enMax;
......@@ -263,7 +254,7 @@ int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, con
/* Calculate unfiltered and filtered energies in subwindows and combine to segments */
FDKaacEnc_CalcWindowEnergy(blockSwitchingControl, granuleLength>>(nBlockSwitchWindows==4? 2:3 ));
FDKaacEnc_CalcWindowEnergy(blockSwitchingControl, granuleLength>>(nBlockSwitchWindows==4? 2:3 ), pTimeSignal);
/* now calculate if there is an attack */
......@@ -335,8 +326,7 @@ static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWnd
}
static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen)
static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen, const INT_PCM *pTimeSignal)
{
INT i;
UINT w;
......@@ -344,8 +334,6 @@ static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSw
FIXP_SGL hiPassCoeff0 = hiPassCoeff[0];
FIXP_SGL hiPassCoeff1 = hiPassCoeff[1];
INT_PCM *timeSignal = blockSwitchingControl->timeSignal;
/* sum up scalarproduct of timesignal as windowed Energies */
for (w=0; w < blockSwitchingControl->nBlockSwitchWindows; w++) {
......@@ -361,9 +349,9 @@ static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSw
FIXP_DBL tempUnfiltered, tempFiltred, t1, t2;
/* tempUnfiltered is scaled with 1 to prevent overflows during calculation of tempFiltred */
#if SAMPLE_BITS == DFRACT_BITS
tempUnfiltered = (FIXP_DBL) *timeSignal++ >> 1;
tempUnfiltered = (FIXP_DBL) *pTimeSignal++ >> 1;
#else
tempUnfiltered = (FIXP_DBL) *timeSignal++ << (DFRACT_BITS-SAMPLE_BITS-1);
tempUnfiltered = (FIXP_DBL) *pTimeSignal++ << (DFRACT_BITS-SAMPLE_BITS-1);
#endif
t1 = fMultDiv2(hiPassCoeff1, tempUnfiltered-temp_iirState0);
t2 = fMultDiv2(hiPassCoeff0, temp_iirState1);
......
......@@ -107,7 +107,6 @@ amm-info@iis.fraunhofer.de
/****************** Structures ***************************/
typedef struct{
INT_PCM *timeSignal;
INT lastWindowSequence;
INT windowShape;
INT lastWindowShape;
......@@ -136,7 +135,7 @@ typedef struct{
void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay);
int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE);
int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE, const INT_PCM *pTimeSignal);
int FDKaacEnc_SyncBlockSwitching(
BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft,
......
......@@ -92,6 +92,7 @@ amm-info@iis.fraunhofer.de
#define _INTERFACE_H
#include "common_fix.h"
#include "FDK_audio.h"
#include "psy_data.h"
#include "aacenc_tns.h"
......@@ -160,4 +161,9 @@ typedef struct {
}PSY_OUT;
inline int isLowDelay( AUDIO_OBJECT_TYPE aot )
{
return (aot==AOT_ER_AAC_LD || aot==AOT_ER_AAC_ELD);
}
#endif /* _INTERFACE_H */
......@@ -116,11 +116,6 @@ static const FIXP_DBL fadeOutFactor[FADE_OUT_LEN] = {1840644096, 1533870080, 122
/* forward definitions */
static inline int isLowDelay( AUDIO_OBJECT_TYPE aot )
{
return (aot==AOT_ER_AAC_LD || aot==AOT_ER_AAC_ELD);
}
/*****************************************************************************
functionname: FDKaacEnc_PsyNew
......@@ -513,28 +508,28 @@ AAC_ENCODER_ERROR FDKaacEnc_psyMain(INT channels,
for(ch = 0; ch < channels; ch++)
{
C_ALLOC_SCRATCH_START(timeSignal, INT_PCM, (1024));
psyStatic[ch]->blockSwitchingControl.timeSignal = timeSignal;
C_ALLOC_SCRATCH_START(pTimeSignal, INT_PCM, (1024))
/* deinterleave input data and use for block switching */
FDKaacEnc_deinterleaveInputBuffer( psyStatic[ch]->blockSwitchingControl.timeSignal,
FDKaacEnc_deinterleaveInputBuffer( pTimeSignal,
&pInput[chIdx[ch]],
psyConf->granuleLength,
totalChannels);
FDKaacEnc_BlockSwitching (&psyStatic[ch]->blockSwitchingControl,
psyConf->granuleLength
,psyStatic[ch]->isLFE
psyConf->granuleLength,
psyStatic[ch]->isLFE,
pTimeSignal
);
/* fill up internal input buffer, to 2xframelength samples */
FDKmemcpy(psyStatic[ch]->psyInputBuffer+blockSwitchingOffset,
psyStatic[ch]->blockSwitchingControl.timeSignal,
pTimeSignal,
(2*psyConf->granuleLength-blockSwitchingOffset)*sizeof(INT_PCM));
C_ALLOC_SCRATCH_END(timeSignal, INT_PCM, (1024));
C_ALLOC_SCRATCH_END(pTimeSignal, INT_PCM, (1024))
}
/* synch left and right block type */
......
......@@ -143,6 +143,8 @@ struct QC_INIT{
INT maxBits; /* maximum number of bits in reservoir */
INT averageBits; /* average number of bits we should use */
INT bitRes;
INT sampleRate; /* output sample rate */
INT advancedBitsToPe; /* if set, calc bits2PE factor depending on samplerate */
INT staticBits; /* Bits per frame consumed by transport layers. */
QCDATA_BR_MODE bitrateMode;
INT meanPe;
......@@ -252,7 +254,7 @@ typedef struct
INT minBitsPerFrame; /* minimal allowd bits per fram, superframing - DRM */
INT nElements;
QCDATA_BR_MODE bitrateMode;
INT bitDistributenMode; /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
INT bitDistributionMode; /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
INT bitResTot;
INT bitResTotMax;
INT maxIterations; /* Maximum number of allowed iterations before FDKaacEnc_crashRecovery() is applied. */
......
......@@ -382,10 +382,10 @@ AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE *hQC,
if ( isConstantBitrateMode(hQC->bitrateMode) ) {
INT bitresPerChannel = (hQC->bitResTotMax / init->channelMapping->nChannelsEff);
/* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
hQC->bitDistributenMode = (bitresPerChannel>50) ? 0 : (bitresPerChannel>0) ? 1 : 2;
hQC->bitDistributionMode = (bitresPerChannel>100) ? 0 : (bitresPerChannel>0) ? 1 : 2;
}
else {
hQC->bitDistributenMode = 0; /* full bitreservoir */
hQC->bitDistributionMode = 0; /* full bitreservoir */
}
......@@ -420,11 +420,17 @@ AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE *hQC,
break;
}
FDKaacEnc_AdjThrInit(hQC->hAdjThr,
init->meanPe,
hQC->elementBits, /* or channelBitrates, was: channelBitrate */
init->channelMapping->nElements,
hQC->vbrQualFactor);
FDKaacEnc_AdjThrInit(
hQC->hAdjThr,
init->meanPe,
hQC->elementBits, /* or channelBitrates, was: channelBitrate */
hQC->invQuant,
init->channelMapping->nElements,
init->channelMapping->nChannelsEff,
init->sampleRate, /* output sample rate */
init->advancedBitsToPe, /* if set, calc bits2PE factor depending on samplerate */
hQC->vbrQualFactor
);
return AAC_ENC_OK;
}
......@@ -655,7 +661,7 @@ static AAC_ENCODER_ERROR FDKaacEnc_prepareBitDistribution(QC_STATE* h
hQC->elementBits[i]->bitResLevelEl,
hQC->elementBits[i]->maxBitResBitsEl,
hQC->maxBitFac,
hQC->bitDistributenMode);
hQC->bitDistributionMode);
*totalAvailableBits += hQC->elementBits[i]->bitResLevelEl;
/* get total corrected granted PE */
......
......@@ -93,7 +93,7 @@ amm-info@iis.fraunhofer.de
/* FDK tools library info */
#define FDK_TOOLS_LIB_VL0 2
#define FDK_TOOLS_LIB_VL1 3
#define FDK_TOOLS_LIB_VL2 1
#define FDK_TOOLS_LIB_VL2 2
#define FDK_TOOLS_LIB_TITLE "FDK Tools"
#define FDK_TOOLS_LIB_BUILD_DATE __DATE__
#define FDK_TOOLS_LIB_BUILD_TIME __TIME__
......
......@@ -242,30 +242,72 @@ FIXP_DBL mul_dbl_sgl_rnd (const FIXP_DBL op1, const FIXP_SGL op2)
*****************************************************************************/
LNK_SECTION_CODE_L1
FIXP_DBL CalcInvLdData(FIXP_DBL op)
/* This table is used for lookup 2^x with */
/* x in range [0...1.0[ in steps of 1/32 */
LNK_SECTION_DATA_L1 static const UINT exp2_tab_long[32]={
0x40000000,0x4166C34C,0x42D561B4,0x444C0740,
0x45CAE0F2,0x47521CC6,0x48E1E9BA,0x4A7A77D4,
0x4C1BF829,0x4DC69CDD,0x4F7A9930,0x51382182,
0x52FF6B55,0x54D0AD5A,0x56AC1F75,0x5891FAC1,
0x5A82799A,0x5C7DD7A4,0x5E8451D0,0x60962665,
0x62B39509,0x64DCDEC3,0x6712460B,0x69540EC9,
0x6BA27E65,0x6DFDDBCC,0x70666F76,0x72DC8374,
0x75606374,0x77F25CCE,0x7A92BE8B,0x7D41D96E
// 0x80000000
};
/* This table is used for lookup 2^x with */
/* x in range [0...1/32[ in steps of 1/1024 */
LNK_SECTION_DATA_L1 static const UINT exp2w_tab_long[32]={
0x40000000,0x400B1818,0x4016321B,0x40214E0C,
0x402C6BE9,0x40378BB4,0x4042AD6D,0x404DD113,
0x4058F6A8,0x40641E2B,0x406F479E,0x407A7300,
0x4085A051,0x4090CF92,0x409C00C4,0x40A733E6,
0x40B268FA,0x40BD9FFF,0x40C8D8F5,0x40D413DD,
0x40DF50B8,0x40EA8F86,0x40F5D046,0x410112FA,
0x410C57A2,0x41179E3D,0x4122E6CD,0x412E3152,
0x41397DCC,0x4144CC3B,0x41501CA0,0x415B6EFB,
// 0x4166C34C,
};
/* This table is used for lookup 2^x with */
/* x in range [0...1/1024[ in steps of 1/32768 */
LNK_SECTION_DATA_L1 static const UINT exp2x_tab_long[32]={
0x40000000,0x400058B9,0x4000B173,0x40010A2D,
0x400162E8,0x4001BBA3,0x4002145F,0x40026D1B,
0x4002C5D8,0x40031E95,0x40037752,0x4003D011,
0x400428CF,0x4004818E,0x4004DA4E,0x4005330E,
0x40058BCE,0x4005E48F,0x40063D51,0x40069613,
0x4006EED5,0x40074798,0x4007A05B,0x4007F91F,
0x400851E4,0x4008AAA8,0x4009036E,0x40095C33,
0x4009B4FA,0x400A0DC0,0x400A6688,0x400ABF4F,
//0x400B1818
};
LNK_SECTION_CODE_L1 FIXP_DBL CalcInvLdData(FIXP_DBL x)
{
FIXP_DBL result_m;
int set_zero = (x < FL2FXCONST_DBL(-31.0/64.0))? 0 : 1;
int set_max = (x >= FL2FXCONST_DBL( 31.0/64.0)) | (x == FL2FXCONST_DBL(0.0));
if ( op == FL2FXCONST_DBL(0.0f) ) {
result_m = (FIXP_DBL)MAXVAL_DBL;
}
else if ( op < FL2FXCONST_DBL(0.0f) ) {
result_m = f2Pow(op, LD_DATA_SHIFT);
}
else {
int result_e;
FIXP_SGL frac = (FIXP_SGL)(LONG)(x & 0x3FF);
UINT index3 = (UINT)(LONG)(x >> 10) & 0x1F;
UINT index2 = (UINT)(LONG)(x >> 15) & 0x1F;
UINT index1 = (UINT)(LONG)(x >> 20) & 0x1F;
int exp = (x > FL2FXCONST_DBL(0.0f)) ? (31 - (int)(x>>25)) : (int)(-(x>>25));
result_m = f2Pow(op, LD_DATA_SHIFT, &result_e);
result_e = fixMin(fixMax(result_e+1-(DFRACT_BITS-1), -(DFRACT_BITS-1)), (DFRACT_BITS-1)); /* rounding and saturation */
UINT lookup1 = exp2_tab_long[index1]*set_zero;
UINT lookup2 = exp2w_tab_long[index2];
UINT lookup3 = exp2x_tab_long[index3];
UINT lookup3f = lookup3 + (UINT)(LONG)fMultDiv2((FIXP_DBL)(0x0016302F),(FIXP_SGL)frac);
UINT lookup12 = (UINT)(LONG)fMult((FIXP_DBL)lookup1, (FIXP_DBL) lookup2);
UINT lookup = (UINT)(LONG)fMult((FIXP_DBL)lookup12, (FIXP_DBL) lookup3f);
if ( (result_e>0) && ( result_m > (((FIXP_DBL)MAXVAL_DBL)>>result_e) ) ) {
result_m = (FIXP_DBL)MAXVAL_DBL; /* saturate to max representable value */
}
else {
result_m = (scaleValue(result_m, result_e)+(FIXP_DBL)1)>>1; /* descale result + rounding */
}
}
return result_m;
FIXP_DBL retVal = (lookup<<3) >> exp;
if (set_max)
retVal=FL2FXCONST_DBL(1.0f);
return retVal;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment