From 2228e360595641dd906bf1773307f43d304f5b2e Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 11 Jul 2012 10:15:24 -0700 Subject: Snapshot 2bda038c163298531d47394bc2c09e1409c5d0db Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54 --- libAACenc/src/metadata_compressor.cpp | 1027 +++++++++++++++++++++++++++++++++ 1 file changed, 1027 insertions(+) create mode 100644 libAACenc/src/metadata_compressor.cpp (limited to 'libAACenc/src/metadata_compressor.cpp') diff --git a/libAACenc/src/metadata_compressor.cpp b/libAACenc/src/metadata_compressor.cpp new file mode 100644 index 0000000..852c8bc --- /dev/null +++ b/libAACenc/src/metadata_compressor.cpp @@ -0,0 +1,1027 @@ + +/* ----------------------------------------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. + All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements +the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. +This FDK AAC Codec software is intended to be used on a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual +audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by +independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part +of the MPEG specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) +may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners +individually for the purpose of encoding or decoding bit streams in products that are compliant with +the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license +these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec +software may already be covered under those patent licenses when it is used for those licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, +are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional +applications information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, are permitted without +payment of copyright license fees provided that you satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of the FDK AAC Codec or +your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation and/or other materials +provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. +You must make available free of charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived from this library without +prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec +software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software +and the date of any change. For modified versions of the FDK AAC Codec, the term +"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term +"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, +ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with +respect to this software. + +You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized +by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors +"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties +of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages, +including but not limited to procurement of substitute goods or services; loss of use, data, or profits, +or business interruption, however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of this software, even if +advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------------------------------------- */ + +/********************** Fraunhofer IIS FDK AAC Encoder lib ****************** + + Author(s): M. Neusinger + Description: Compressor for AAC Metadata Generator + +******************************************************************************/ + + +#include "metadata_compressor.h" +#include "channel_map.h" + + +#define LOG2 0.69314718056f /* natural logarithm of 2 */ +#define ILOG2 1.442695041f /* 1/LOG2 */ +#define FIXP_ILOG2_DIV2 (FL2FXCONST_DBL(ILOG2/2)) + +/*----------------- defines ----------------------*/ + +#define MAX_DRC_CHANNELS (8) /*!< Max number of audio input channels. */ +#define DOWNMIX_SHIFT (3) /*!< Max 8 channel. */ +#define WEIGHTING_FILTER_SHIFT (2) /*!< Scaling used in weighting filter. */ + +#define METADATA_INT_BITS 10 +#define METADATA_LINT_BITS 20 +#define METADATA_INT_SCALE (INT64(1)<<(METADATA_INT_BITS)) +#define METADATA_FRACT_BITS (DFRACT_BITS-1-METADATA_INT_BITS) +#define METADATA_FRACT_SCALE (INT64(1)<<(METADATA_FRACT_BITS)) + +/** + * Enum for channel assignment. + */ +enum { + L = 0, + R = 1, + C = 2, + LFE = 3, + LS = 4, + RS = 5, + S = 6, + LS2 = 7, + RS2 = 8 +}; + +/*--------------- structure definitions --------------------*/ + +/** + * Structure holds weighting filter filter states. + */ +struct WEIGHTING_STATES { + FIXP_DBL x1; + FIXP_DBL x2; + FIXP_DBL y1; + FIXP_DBL y2; +}; + +/** + * Dynamic Range Control compressor structure. + */ +struct DRC_COMP { + + FIXP_DBL maxBoostThr[2]; /*!< Max boost threshold. */ + FIXP_DBL boostThr[2]; /*!< Boost threshold. */ + FIXP_DBL earlyCutThr[2]; /*!< Early cut threshold. */ + FIXP_DBL cutThr[2]; /*!< Cut threshold. */ + FIXP_DBL maxCutThr[2]; /*!< Max cut threshold. */ + + FIXP_DBL boostFac[2]; /*!< Precalculated factor for boost compression. */ + FIXP_DBL earlyCutFac[2]; /*!< Precalculated factor for early cut compression. */ + FIXP_DBL cutFac[2]; /*!< Precalculated factor for cut compression. */ + + FIXP_DBL maxBoost[2]; /*!< Maximum boost. */ + FIXP_DBL maxCut[2]; /*!< Maximum cut. */ + FIXP_DBL maxEarlyCut[2]; /*!< Maximum early cut. */ + + FIXP_DBL fastAttack[2]; /*!< Fast attack coefficient. */ + FIXP_DBL fastDecay[2]; /*!< Fast release coefficient. */ + FIXP_DBL slowAttack[2]; /*!< Slow attack coefficient. */ + FIXP_DBL slowDecay[2]; /*!< Slow release coefficient. */ + UINT holdOff[2]; /*!< Hold time in blocks. */ + + FIXP_DBL attackThr[2]; /*!< Slow/fast attack threshold. */ + FIXP_DBL decayThr[2]; /*!< Slow/fast release threshold. */ + + DRC_PROFILE profile[2]; /*!< DRC profile. */ + INT blockLength; /*!< Block length in samples. */ + UINT sampleRate; /*!< Sample rate. */ + CHANNEL_MODE chanConfig; /*!< Channel configuration. */ + + UCHAR useWeighting; /*!< Use weighting filter. */ + + UINT channels; /*!< Number of channels. */ + UINT fullChannels; /*!< Number of full range channels. */ + INT channelIdx[9]; /*!< Offsets of interleaved channel samples (L, R, C, LFE, Ls, Rs, S, Ls2, Rs2). */ + + FIXP_DBL smoothLevel[2]; /*!< level smoothing states */ + FIXP_DBL smoothGain[2]; /*!< gain smoothing states */ + UINT holdCnt[2]; /*!< hold counter */ + + FIXP_DBL limGain[2]; /*!< limiter gain */ + FIXP_DBL limDecay; /*!< limiter decay (linear) */ + FIXP_DBL prevPeak[2]; /*!< max peak of previous block (stereo/mono)*/ + + WEIGHTING_STATES filter[MAX_DRC_CHANNELS]; /*!< array holds weighting filter states */ + +}; + +/*---------------- constants -----------------------*/ + +/** + * Profile tables. + */ +static const FIXP_DBL tabMaxBoostThr[] = { + (FIXP_DBL)(-43<limDecay = FL2FXCONST_DBL( ((0.006f / 256) * blockLength) / METADATA_INT_SCALE ); + + /* Save parameters. */ + drcComp->blockLength = blockLength; + drcComp->sampleRate = sampleRate; + drcComp->chanConfig = channelMode; + drcComp->useWeighting = useWeighting; + + if (FDK_DRC_Generator_setDrcProfile(drcComp, profileLine, profileRF)!=0) { /* expects initialized blockLength and sampleRate */ + return (-1); + } + + /* Set number of channels and channel offsets. */ + if (FDKaacEnc_InitChannelMapping(channelMode, channelOrder, &channelMapping)!=AAC_ENC_OK) { + return (-2); + } + + for (i = 0; i < 9; i++) drcComp->channelIdx[i] = -1; + + switch (channelMode) { + case MODE_1: /* mono */ + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + break; + case MODE_2: /* stereo */ + drcComp->channelIdx[L] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[0].ChannelIndex[1]; + break; + case MODE_1_2: /* 3ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + break; + case MODE_1_2_1: /* 4ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[S] = channelMapping.elInfo[2].ChannelIndex[0]; + break; + case MODE_1_2_2: /* 5ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[LS] = channelMapping.elInfo[2].ChannelIndex[0]; + drcComp->channelIdx[RS] = channelMapping.elInfo[2].ChannelIndex[1]; + break; + case MODE_1_2_2_1: /* 5.1 ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[LFE] = channelMapping.elInfo[3].ChannelIndex[0]; + drcComp->channelIdx[LS] = channelMapping.elInfo[2].ChannelIndex[0]; + drcComp->channelIdx[RS] = channelMapping.elInfo[2].ChannelIndex[1]; + break; + case MODE_1_2_2_2_1: /* 7.1 ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[LFE] = channelMapping.elInfo[4].ChannelIndex[0]; + drcComp->channelIdx[LS] = channelMapping.elInfo[2].ChannelIndex[0]; + drcComp->channelIdx[RS] = channelMapping.elInfo[2].ChannelIndex[1]; + drcComp->channelIdx[LS2] = channelMapping.elInfo[3].ChannelIndex[0]; + drcComp->channelIdx[RS2] = channelMapping.elInfo[3].ChannelIndex[1]; + break; + case MODE_1_1: + case MODE_1_1_1_1: + case MODE_1_1_1_1_1_1: + case MODE_1_1_1_1_1_1_1_1: + case MODE_1_1_1_1_1_1_1_1_1_1_1_1: + case MODE_2_2: + case MODE_2_2_2: + case MODE_2_2_2_2: + case MODE_2_2_2_2_2_2: + default: + return (-1); + } + + drcComp->fullChannels = channelMapping.nChannelsEff; + drcComp->channels = channelMapping.nChannels; + + /* Init states. */ + drcComp->smoothLevel[0] = drcComp->smoothLevel[1] = (FIXP_DBL)(-135<smoothGain, sizeof(drcComp->smoothGain)); + FDKmemclear(drcComp->holdCnt, sizeof(drcComp->holdCnt)); + FDKmemclear(drcComp->limGain, sizeof(drcComp->limGain)); + FDKmemclear(drcComp->prevPeak, sizeof(drcComp->prevPeak)); + FDKmemclear(drcComp->filter, sizeof(drcComp->filter)); + + return (0); +} + + +INT FDK_DRC_Generator_setDrcProfile( + HDRC_COMP drcComp, + const DRC_PROFILE profileLine, + const DRC_PROFILE profileRF + ) +{ + int profileIdx, i; + + drcComp->profile[0] = profileLine; + drcComp->profile[1] = profileRF; + + for (i = 0; i < 2; i++) { + /* get profile index */ + switch (drcComp->profile[i]) { + case DRC_NONE: + case DRC_FILMSTANDARD: profileIdx = 0; break; + case DRC_FILMLIGHT: profileIdx = 1; break; + case DRC_MUSICSTANDARD: profileIdx = 2; break; + case DRC_MUSICLIGHT: profileIdx = 3; break; + case DRC_SPEECH: profileIdx = 4; break; + case DRC_DELAY_TEST: profileIdx = 5; break; + default: return (-1); + } + + /* get parameters for selected profile */ + if (profileIdx >= 0) { + drcComp->maxBoostThr[i] = tabMaxBoostThr[profileIdx]; + drcComp->boostThr[i] = tabBoostThr[profileIdx]; + drcComp->earlyCutThr[i] = tabEarlyCutThr[profileIdx]; + drcComp->cutThr[i] = tabCutThr[profileIdx]; + drcComp->maxCutThr[i] = tabMaxCutThr[profileIdx]; + + drcComp->boostFac[i] = tabBoostRatio[profileIdx]; + drcComp->earlyCutFac[i] = tabEarlyCutRatio[profileIdx]; + drcComp->cutFac[i] = tabCutRatio[profileIdx]; + + drcComp->maxBoost[i] = tabMaxBoost[profileIdx]; + drcComp->maxCut[i] = tabMaxCut[profileIdx]; + drcComp->maxEarlyCut[i] = - fMult((drcComp->cutThr[i] - drcComp->earlyCutThr[i]), drcComp->earlyCutFac[i]); /* no scaling after mult needed, earlyCutFac is in FIXP_DBL */ + + drcComp->fastAttack[i] = tc2Coeff(tabFastAttack[profileIdx], drcComp->sampleRate, drcComp->blockLength); + drcComp->fastDecay[i] = tc2Coeff(tabFastDecay[profileIdx], drcComp->sampleRate, drcComp->blockLength); + drcComp->slowAttack[i] = tc2Coeff(tabSlowAttack[profileIdx], drcComp->sampleRate, drcComp->blockLength); + drcComp->slowDecay[i] = tc2Coeff(tabSlowDecay[profileIdx], drcComp->sampleRate, drcComp->blockLength); + drcComp->holdOff[i] = tabHoldOff[profileIdx] * 256 / drcComp->blockLength; + + drcComp->attackThr[i] = tabAttackThr[profileIdx]; + drcComp->decayThr[i] = tabDecayThr[profileIdx]; + } + + drcComp->smoothGain[i] = FL2FXCONST_DBL(0.f); + } + return (0); +} + + +INT FDK_DRC_Generator_Calc( + HDRC_COMP drcComp, + const INT_PCM * const inSamples, + const INT dialnorm, + const INT drc_TargetRefLevel, + const INT comp_TargetRefLevel, + FIXP_DBL clev, + FIXP_DBL slev, + INT * const pDynrng, + INT * const pCompr + ) +{ + int i, c; + FIXP_DBL peak[2]; + + + /************************************************************************** + * compressor + **************************************************************************/ + if ((drcComp->profile[0] != DRC_NONE) || (drcComp->profile[1] != DRC_NONE)) { + /* Calc loudness level */ + FIXP_DBL level_b = FL2FXCONST_DBL(0.f); + int level_e = DFRACT_BITS-1; + + /* Increase energy time resolution with shorter processing blocks. 32 is an empiric value. */ + const int granuleLength = fixMin(32, drcComp->blockLength); + + if (drcComp->useWeighting) { + FIXP_DBL x1, x2, y, y1, y2; + /* sum of filter coefficients about 2.5 -> squared value is 6.25 + WEIGHTING_FILTER_SHIFT is 2 -> scaling about 16, therefore reduce granuleShift by 1. + */ + const int granuleShift = getShiftFactor(granuleLength)-1; + + for (c = 0; c < (int)drcComp->channels; c++) { + const INT_PCM* pSamples = &inSamples[c]; + + if (c == drcComp->channelIdx[LFE]) { + continue; /* skip LFE */ + } + + /* get filter states */ + x1 = drcComp->filter[c].x1; + x2 = drcComp->filter[c].x2; + y1 = drcComp->filter[c].y1; + y2 = drcComp->filter[c].y2; + + i = 0; + + do { + + int offset = i; + FIXP_DBL accu = FL2FXCONST_DBL(0.f); + + for (i=offset; i < fixMin(offset+granuleLength,drcComp->blockLength); i++) { + /* apply weighting filter */ + FIXP_DBL x = FX_PCM2FX_DBL((FIXP_PCM)pSamples[i*drcComp->channels]) >> WEIGHTING_FILTER_SHIFT; + + /* y = b0 * (x - x2) - a1 * y1 - a2 * y2; */ + y = fMult(b0,x-x2) - fMult(a1,y1) - fMult(a2,y2); + + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + + accu += fPow2Div2(y)>>(granuleShift-1); /* partial energy */ + } /* i */ + + fixpAdd(accu, granuleShift+2*WEIGHTING_FILTER_SHIFT, &level_b, &level_e); /* sup up partial energies */ + + } while ( i < drcComp->blockLength ); + + + /* save filter states */ + drcComp->filter[c].x1 = x1; + drcComp->filter[c].x2 = x2; + drcComp->filter[c].y1 = y1; + drcComp->filter[c].y2 = y2; + } /* c */ + } /* weighting */ + else { + const int granuleShift = getShiftFactor(granuleLength); + + for (c = 0; c < (int)drcComp->channels; c++) { + const INT_PCM* pSamples = &inSamples[c]; + + if ((int)c == drcComp->channelIdx[LFE]) { + continue; /* skip LFE */ + } + + i = 0; + + do { + int offset = i; + FIXP_DBL accu = FL2FXCONST_DBL(0.f); + + for (i=offset; i < fixMin(offset+granuleLength,drcComp->blockLength); i++) { + /* partial energy */ + accu += fPow2Div2((FIXP_PCM)pSamples[i*drcComp->channels])>>(granuleShift-1); + } /* i */ + + fixpAdd(accu, granuleShift, &level_b, &level_e); /* sup up partial energies */ + + } while ( i < drcComp->blockLength ); + } + } /* weighting */ + + /* + * Convert to dBFS, apply dialnorm + */ + /* level scaling */ + + /* descaled level in ld64 representation */ + FIXP_DBL ldLevel = CalcLdData(level_b) + (FIXP_DBL)((level_e-12)<<(DFRACT_BITS-1-LD_DATA_SHIFT)) - CalcLdData((FIXP_DBL)(drcComp->blockLength<<(DFRACT_BITS-1-12))); + + /* if (level < 1e-10) level = 1e-10f; */ + ldLevel = FDKmax(ldLevel, FL2FXCONST_DBL(-0.51905126482615036685473741085772f)); + + /* level = 10 * log(level)/log(10) + 3; + * = 10*log(2)/log(10) * ld(level) + 3; + * = 10 * 0.30102999566398119521373889472449 * ld(level) + 3 + * = 10 * (0.30102999566398119521373889472449 * ld(level) + 0.3) + * = 10 * (0.30102999566398119521373889472449 * ld64(level) + 0.3/64) * 64 + * + * additional scaling with METADATA_FRACT_BITS: + * = 10 * (0.30102999566398119521373889472449 * ld64(level) + 0.3/64) * 64 * 2^(METADATA_FRACT_BITS) + * = 10 * (0.30102999566398119521373889472449 * ld64(level) + 0.3/64) * 2^(METADATA_FRACT_BITS+LD_DATA_SHIFT) + * = 10*2^(METADATA_FRACT_BITS+LD_DATA_SHIFT) * ( 0.30102999566398119521373889472449 * ld64(level) + 0.3/64 ) + * */ + FIXP_DBL level = fMult((FIXP_DBL)(10<<(METADATA_FRACT_BITS+LD_DATA_SHIFT)), fMult( FL2FXCONST_DBL(0.30102999566398119521373889472449f), ldLevel) + (FIXP_DBL)(FL2FXCONST_DBL(0.3f)>>LD_DATA_SHIFT) ); + + /* level -= dialnorm + 31 */ /* this is fixed to Dolby-ReferenceLevel as compressor profiles are defined relative to this */ + level -= ((FIXP_DBL)(dialnorm<<(METADATA_FRACT_BITS-16)) + (FIXP_DBL)(31<profile[i] == DRC_NONE) { + /* no compression */ + drcComp->smoothGain[i] = FL2FXCONST_DBL(0.f); + } + else { + FIXP_DBL gain, alpha, lvl2smthlvl; + + /* calc static gain */ + if (level <= drcComp->maxBoostThr[i]) { + /* max boost */ + gain = drcComp->maxBoost[i]; + } + else if (level < drcComp->boostThr[i]) { + /* boost range */ + gain = fMult((level - drcComp->boostThr[i]),drcComp->boostFac[i]); + } + else if (level <= drcComp->earlyCutThr[i]) { + /* null band */ + gain = FL2FXCONST_DBL(0.f); + } + else if (level <= drcComp->cutThr[i]) { + /* early cut range */ + gain = fMult((level - drcComp->earlyCutThr[i]), drcComp->earlyCutFac[i]); + } + else if (level < drcComp->maxCutThr[i]) { + /* cut range */ + gain = fMult((level - drcComp->cutThr[i]), drcComp->cutFac[i]) - drcComp->maxEarlyCut[i]; + } + else { + /* max cut */ + gain = -drcComp->maxCut[i]; + } + + /* choose time constant */ + lvl2smthlvl = level - drcComp->smoothLevel[i]; + if (gain < drcComp->smoothGain[i]) { + /* attack */ + if (lvl2smthlvl > drcComp->attackThr[i]) { + /* fast attack */ + alpha = drcComp->fastAttack[i]; + } + else { + /* slow attack */ + alpha = drcComp->slowAttack[i]; + } + } + else { + /* release */ + if (lvl2smthlvl < -drcComp->decayThr[i]) { + /* fast release */ + alpha = drcComp->fastDecay[i]; + } + else { + /* slow release */ + alpha = drcComp->slowDecay[i]; + } + } + + /* smooth gain & level */ + if ((gain < drcComp->smoothGain[i]) || (drcComp->holdCnt[i] == 0)) { /* hold gain unless we have an attack or hold period is over */ + FIXP_DBL accu; + + /* drcComp->smoothLevel[i] = (1-alpha) * drcComp->smoothLevel[i] + alpha * level; */ + accu = fMult((FL2FXCONST_DBL(1.f)-alpha), drcComp->smoothLevel[i]); + accu += fMult(alpha,level); + drcComp->smoothLevel[i] = accu; + + /* drcComp->smoothGain[i] = (1-alpha) * drcComp->smoothGain[i] + alpha * gain; */ + accu = fMult((FL2FXCONST_DBL(1.f)-alpha), drcComp->smoothGain[i]); + accu += fMult(alpha,gain); + drcComp->smoothGain[i] = accu; + } + + /* hold counter */ + if (drcComp->holdCnt[i]) { + drcComp->holdCnt[i]--; + } + if (gain < drcComp->smoothGain[i]) { + drcComp->holdCnt[i] = drcComp->holdOff[i]; + } + } /* profile != DRC_NONE */ + } /* for i=1..2 */ + } else { + /* no compression */ + drcComp->smoothGain[0] = FL2FXCONST_DBL(0.f); + drcComp->smoothGain[1] = FL2FXCONST_DBL(0.f); + } + + /************************************************************************** + * limiter + **************************************************************************/ + + /* find peak level */ + peak[0] = peak[1] = FL2FXCONST_DBL(0.f); + for (i = 0; i < drcComp->blockLength; i++) { + FIXP_DBL tmp; + const INT_PCM* pSamples = &inSamples[i*drcComp->channels]; + INT_PCM maxSample = 0; + + /* single channels */ + for (c = 0; c < (int)drcComp->channels; c++) { + maxSample = FDKmax(maxSample, fAbs(pSamples[c])); + } + peak[0] = fixMax(peak[0], FX_PCM2FX_DBL(maxSample)>>DOWNMIX_SHIFT); + + /* Lt/Rt downmix */ + if (drcComp->fullChannels > 2) { + /* Lt */ + tmp = FL2FXCONST_DBL(0.f); + + if (drcComp->channelIdx[LS] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */ + if (drcComp->channelIdx[LS2] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */ + if (drcComp->channelIdx[RS] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */ + if (drcComp->channelIdx[RS2] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */ + if ((drcComp->channelIdx[LS] >= 0) && (drcComp->channelIdx[LS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]])>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[L]])>>DOWNMIX_SHIFT); /* L */ + + peak[0] = fixMax(peak[0], fixp_abs(tmp)); + + /* Rt */ + tmp = FL2FXCONST_DBL(0.f); + if (drcComp->channelIdx[LS] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */ + if (drcComp->channelIdx[LS2] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */ + if (drcComp->channelIdx[RS] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */ + if (drcComp->channelIdx[RS2] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */ + if ((drcComp->channelIdx[RS] >= 0) && (drcComp->channelIdx[RS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]])>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[R]])>>DOWNMIX_SHIFT); /* R */ + + peak[0] = fixMax(peak[0], fixp_abs(tmp)); + } + + /* Lo/Ro downmix */ + if (drcComp->fullChannels > 2) { + /* Lo */ + tmp = FL2FXCONST_DBL(0.f); + if (drcComp->channelIdx[LS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */ + if (drcComp->channelIdx[LS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */ + if ((drcComp->channelIdx[LS] >= 0) && (drcComp->channelIdx[LS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(slev, fMult(FL2FXCONST_DBL(0.7f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]]))>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(clev, (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[L]])>>DOWNMIX_SHIFT); /* L */ + + peak[0] = fixMax(peak[0], fixp_abs(tmp)); + + /* Ro */ + tmp = FL2FXCONST_DBL(0.f); + if (drcComp->channelIdx[RS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */ + if (drcComp->channelIdx[RS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */ + if ((drcComp->channelIdx[RS] >= 0) && (drcComp->channelIdx[RS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(slev, fMult(FL2FXCONST_DBL(0.7f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]]))>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(clev, (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[R]])>>DOWNMIX_SHIFT); /* R */ + + peak[0] = fixMax(peak[0], fixp_abs(tmp)); + } + + peak[1] = fixMax(peak[0], peak[1]); + + /* Mono Downmix - for comp_val only */ + if (drcComp->fullChannels > 1) { + tmp = FL2FXCONST_DBL(0.f); + if (drcComp->channelIdx[LS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */ + if (drcComp->channelIdx[LS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */ + if (drcComp->channelIdx[RS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */ + if (drcComp->channelIdx[RS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */ + if ((drcComp->channelIdx[LS] >= 0) && (drcComp->channelIdx[LS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + /*if ((drcComp->channelIdx[RS] >= 0) && (drcComp->channelIdx[RS2] >= 0)) tmp *=0.707f;*/ /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(slev, fMult(FL2FXCONST_DBL(0.7f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]]))>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(clev, (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[L]])>>DOWNMIX_SHIFT); /* L */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[R]])>>DOWNMIX_SHIFT); /* R */ + + peak[1] = fixMax(peak[1], fixp_abs(tmp)); + } + } + + for (i=0; i<2; i++) { + FIXP_DBL tmp = drcComp->prevPeak[i]; + drcComp->prevPeak[i] = peak[i]; + peak[i] = fixMax(peak[i], tmp); + + /* + * Convert to dBFS, apply dialnorm + */ + /* descaled peak in ld64 representation */ + FIXP_DBL ld_peak = CalcLdData(peak[i]) + (FIXP_DBL)((LONG)DOWNMIX_SHIFT<<(DFRACT_BITS-1-LD_DATA_SHIFT)); + + /* if (peak < 1e-6) level = 1e-6f; */ + ld_peak = FDKmax(ld_peak, FL2FXCONST_DBL(-0.31143075889569022011284244651463f)); + + /* peak[i] = 20 * log(peak[i])/log(10) + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS) + * peak[i] = 20 * log(2)/log(10) * ld(peak[i]) + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS) + * peak[i] = 10 * 2*0.30102999566398119521373889472449 * ld(peak[i]) + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS) + * + * additional scaling with METADATA_FRACT_BITS: + * peak[i] = (10 * 2*0.30102999566398119521373889472449 * ld64(peak[i]) * 64 + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS))*2^(-METADATA_FRACT_BITS) + * peak[i] = 10*2^(METADATA_FRACT_BITS+LD_DATA_SHIFT) * 2*0.30102999566398119521373889472449 * ld64(peak[i]) + * + 0.2f*2^(-METADATA_FRACT_BITS) + drcComp->smoothGain[i] + */ + peak[i] = fMult((FIXP_DBL)(10<<(METADATA_FRACT_BITS+LD_DATA_SHIFT)), fMult( FL2FX_DBL(2*0.30102999566398119521373889472449f), ld_peak)); + peak[i] += (FL2FX_DBL(0.2f)>>METADATA_INT_BITS); /* add a little bit headroom */ + peak[i] += drcComp->smoothGain[i]; + } + + /* peak -= dialnorm + 31; */ /* this is Dolby style only */ + peak[0] -= (FIXP_DBL)((dialnorm-drc_TargetRefLevel)<<(METADATA_FRACT_BITS-16)); /* peak[0] -= dialnorm - drc_TargetRefLevel */ + + /* peak += 11; */ /* this is Dolby style only */ /* RF mode output is 11dB higher */ + /*peak += comp_TargetRefLevel - drc_TargetRefLevel;*/ + peak[1] -= (FIXP_DBL)((dialnorm-comp_TargetRefLevel)<<(METADATA_FRACT_BITS-16)); /* peak[1] -= dialnorm - comp_TargetRefLevel */ + + /* limiter gain */ + drcComp->limGain[0] += drcComp->limDecay; /* linear limiter release */ + drcComp->limGain[0] = fixMin(drcComp->limGain[0], -peak[0]); + + drcComp->limGain[1] += 2*drcComp->limDecay; /* linear limiter release */ + drcComp->limGain[1] = fixMin(drcComp->limGain[1], -peak[1]); + + /*************************************************************************/ + + /* apply limiting, return DRC gains*/ + { + FIXP_DBL tmp; + + tmp = drcComp->smoothGain[0]; + if (drcComp->limGain[0] < FL2FXCONST_DBL(0.f)) { + tmp += drcComp->limGain[0]; + } + *pDynrng = (LONG) scaleValue(tmp, -(METADATA_FRACT_BITS-16)); + + tmp = drcComp->smoothGain[1]; + if (drcComp->limGain[1] < FL2FXCONST_DBL(0.f)) { + tmp += drcComp->limGain[1]; + } + *pCompr = (LONG) scaleValue(tmp, -(METADATA_FRACT_BITS-16)); + } + + return 0; +} + + +DRC_PROFILE FDK_DRC_Generator_getDrcProfile(const HDRC_COMP drcComp) +{ + return drcComp->profile[0]; +} + +DRC_PROFILE FDK_DRC_Generator_getCompProfile(const HDRC_COMP drcComp) +{ + return drcComp->profile[1]; +} + + -- cgit v1.2.3