blob: dd40f9b24fbb834ba6d8b83eb66ef6fb88c31060 [file] [log] [blame]
/*
** Copyright 2003-2010, VisualOn, Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
/*******************************************************************************
File: psy_configuration.c
Content: Psychoaccoustic configuration functions
*******************************************************************************/
#include "basic_op.h"
#include "oper_32b.h"
#include "psy_configuration.h"
#include "adj_thr.h"
#include "aac_rom.h"
#define BARC_SCALE 100 /* integer barc values are scaled with 100 */
#define LOG2_1000 301 /* log2*1000 */
#define PI2_1000 1571 /* pi/2*1000*/
#define ATAN_COEF1 3560 /* 1000/0.280872f*/
#define ATAN_COEF2 281 /* 1000*0.280872f*/
typedef struct{
Word32 sampleRate;
const UWord8 *paramLong;
const UWord8 *paramShort;
}SFB_INFO_TAB;
static const Word16 ABS_LEV = 20;
static const Word16 BARC_THR_QUIET[] = {15, 10, 7, 2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3, 5, 10, 20, 30};
static const Word16 max_bark = 24; /* maximum bark-value */
static const Word16 maskLow = 30; /* in 1dB/bark */
static const Word16 maskHigh = 15; /* in 1*dB/bark */
static const Word16 c_ratio = 0x0029; /* pow(10.0f, -(29.0f/10.0f)) */
static const Word16 maskLowSprEnLong = 30; /* in 1dB/bark */
static const Word16 maskHighSprEnLong = 20; /* in 1dB/bark */
static const Word16 maskHighSprEnLongLowBr = 15; /* in 1dB/bark */
static const Word16 maskLowSprEnShort = 20; /* in 1dB/bark */
static const Word16 maskHighSprEnShort = 15; /* in 1dB/bark */
static const Word16 c_minRemainingThresholdFactor = 0x0148; /* 0.01 *(1 << 15)*/
static const Word32 c_maxsnr = 0x66666666; /* upper limit is -1 dB */
static const Word32 c_minsnr = 0x00624dd3; /* lower limit is -25 dB */
static const Word32 c_maxClipEnergyLong = 0x77359400; /* 2.0e9f*/
static const Word32 c_maxClipEnergyShort = 0x01dcd650; /* 2.0e9f/(AACENC_TRANS_FAC*AACENC_TRANS_FAC)*/
Word32 GetSRIndex(Word32 sampleRate)
{
if (92017 <= sampleRate) return 0;
if (75132 <= sampleRate) return 1;
if (55426 <= sampleRate) return 2;
if (46009 <= sampleRate) return 3;
if (37566 <= sampleRate) return 4;
if (27713 <= sampleRate) return 5;
if (23004 <= sampleRate) return 6;
if (18783 <= sampleRate) return 7;
if (13856 <= sampleRate) return 8;
if (11502 <= sampleRate) return 9;
if (9391 <= sampleRate) return 10;
return 11;
}
/*********************************************************************************
*
* function name: atan_1000
* description: calculates 1000*atan(x/1000)
* based on atan approx for x > 0
* atan(x) = x/((float)1.0f+(float)0.280872f*x*x) if x < 1
* = pi/2 - x/((float)0.280872f +x*x) if x >= 1
* return: 1000*atan(x/1000)
*
**********************************************************************************/
static Word16 atan_1000(Word32 val)
{
Word32 y;
if(L_sub(val, 1000) < 0) {
y = extract_l(((1000 * val) / (1000 + ((val * val) / ATAN_COEF1))));
}
else {
y = PI2_1000 - ((1000 * val) / (ATAN_COEF2 + ((val * val) / 1000)));
}
return extract_l(y);
}
/*****************************************************************************
*
* function name: BarcLineValue
* description: Calculates barc value for one frequency line
* returns: barc value of line * BARC_SCALE
* input: number of lines in transform, index of line to check, Fs
* output:
*
*****************************************************************************/
static Word16 BarcLineValue(Word16 noOfLines, Word16 fftLine, Word32 samplingFreq)
{
Word32 center_freq, temp, bvalFFTLine;
/* center frequency of fft line */
center_freq = (fftLine * samplingFreq) / (noOfLines << 1);
temp = atan_1000((center_freq << 2) / (3*10));
bvalFFTLine =
(26600 * atan_1000((center_freq*76) / 100) + 7*temp*temp) / (2*1000*1000 / BARC_SCALE);
return saturate(bvalFFTLine);
}
/*****************************************************************************
*
* function name: initThrQuiet
* description: init thredhold in quiet
*
*****************************************************************************/
static void initThrQuiet(Word16 numPb,
const Word16 *pbOffset,
Word16 *pbBarcVal,
Word32 *pbThresholdQuiet) {
Word16 i;
Word16 barcThrQuiet;
for(i=0; i<numPb; i++) {
Word16 bv1, bv2;
if (i>0)
bv1 = (pbBarcVal[i] + pbBarcVal[i-1]) >> 1;
else
bv1 = pbBarcVal[i] >> 1;
if (i < (numPb - 1))
bv2 = (pbBarcVal[i] + pbBarcVal[i+1]) >> 1;
else {
bv2 = pbBarcVal[i];
}
bv1 = min((bv1 / BARC_SCALE), max_bark);
bv2 = min((bv2 / BARC_SCALE), max_bark);
barcThrQuiet = min(BARC_THR_QUIET[bv1], BARC_THR_QUIET[bv2]);
/*
we calculate
pow(10.0f,(float)(barcThrQuiet - ABS_LEV)*0.1)*(float)ABS_LOW*(pbOffset[i+1] - pbOffset[i]);
*/
pbThresholdQuiet[i] = pow2_xy((((barcThrQuiet - ABS_LEV) * 100) +
LOG2_1000*(14+2*LOG_NORM_PCM)), LOG2_1000) * (pbOffset[i+1] - pbOffset[i]);
}
}
/*****************************************************************************
*
* function name: initSpreading
* description: init energy spreading parameter
*
*****************************************************************************/
static void initSpreading(Word16 numPb,
Word16 *pbBarcValue,
Word16 *pbMaskLoFactor,
Word16 *pbMaskHiFactor,
Word16 *pbMaskLoFactorSprEn,
Word16 *pbMaskHiFactorSprEn,
const Word32 bitrate,
const Word16 blockType)
{
Word16 i;
Word16 maskLowSprEn, maskHighSprEn;
if (sub(blockType, SHORT_WINDOW) != 0) {
maskLowSprEn = maskLowSprEnLong;
if (bitrate > 22000)
maskHighSprEn = maskHighSprEnLong;
else
maskHighSprEn = maskHighSprEnLongLowBr;
}
else {
maskLowSprEn = maskLowSprEnShort;
maskHighSprEn = maskHighSprEnShort;
}
for(i=0; i<numPb; i++) {
if (i > 0) {
Word32 dbVal;
Word16 dbark = pbBarcValue[i] - pbBarcValue[i-1];
/*
we calulate pow(10.0f, -0.1*dbVal/BARC_SCALE)
*/
dbVal = (maskHigh * dbark);
pbMaskHiFactor[i] = round16(pow2_xy(L_negate(dbVal), (Word32)LOG2_1000)); /* 0.301 log10(2) */
dbVal = (maskLow * dbark);
pbMaskLoFactor[i-1] = round16(pow2_xy(L_negate(dbVal),(Word32)LOG2_1000));
dbVal = (maskHighSprEn * dbark);
pbMaskHiFactorSprEn[i] = round16(pow2_xy(L_negate(dbVal),(Word32)LOG2_1000));
dbVal = (maskLowSprEn * dbark);
pbMaskLoFactorSprEn[i-1] = round16(pow2_xy(L_negate(dbVal),(Word32)LOG2_1000));
}
else {
pbMaskHiFactor[i] = 0;
pbMaskLoFactor[numPb-1] = 0;
pbMaskHiFactorSprEn[i] = 0;
pbMaskLoFactorSprEn[numPb-1] = 0;
}
}
}
/*****************************************************************************
*
* function name: initBarcValues
* description: init bark value
*
*****************************************************************************/
static void initBarcValues(Word16 numPb,
const Word16 *pbOffset,
Word16 numLines,
Word32 samplingFrequency,
Word16 *pbBval)
{
Word16 i;
Word16 pbBval0, pbBval1;
pbBval0 = 0;
for(i=0; i<numPb; i++){
pbBval1 = BarcLineValue(numLines, pbOffset[i+1], samplingFrequency);
pbBval[i] = (pbBval0 + pbBval1) >> 1;
pbBval0 = pbBval1;
}
}
/*****************************************************************************
*
* function name: initMinSnr
* description: calculate min snr parameter
* minSnr(n) = 1/(2^sfbPemin(n)/w(n) - 1.5)
*
*****************************************************************************/
static void initMinSnr(const Word32 bitrate,
const Word32 samplerate,
const Word16 numLines,
const Word16 *sfbOffset,
const Word16 *pbBarcVal,
const Word16 sfbActive,
Word16 *sfbMinSnr)
{
Word16 sfb;
Word16 barcWidth;
Word16 pePerWindow;
Word32 pePart;
Word32 snr;
Word16 pbVal0, pbVal1, shift;
/* relative number of active barks */
pePerWindow = bits2pe(extract_l((bitrate * numLines) / samplerate));
pbVal0 = 0;
for (sfb=0; sfb<sfbActive; sfb++) {
pbVal1 = (pbBarcVal[sfb] << 1) - pbVal0;
barcWidth = pbVal1 - pbVal0;
pbVal0 = pbVal1;
/* allow at least 2.4% of pe for each active barc */
pePart = ((pePerWindow * 24) * (max_bark * barcWidth)) /
(pbBarcVal[sfbActive-1] * (sfbOffset[sfb+1] - sfbOffset[sfb]));
pePart = min(pePart, 8400);
pePart = max(pePart, 1400);
/* minSnr(n) = 1/(2^sfbPemin(n)/w(n) - 1.5)*/
/* we add an offset of 2^16 to the pow functions */
/* 0xc000 = 1.5*(1 << 15)*/
snr = pow2_xy((pePart - 16*1000),1000) - 0x0000c000;
if(snr > 0x00008000)
{
shift = norm_l(snr);
snr = Div_32(0x00008000 << shift, snr << shift);
}
else
{
snr = 0x7fffffff;
}
/* upper limit is -1 dB */
snr = min(snr, c_maxsnr);
/* lower limit is -25 dB */
snr = max(snr, c_minsnr);
sfbMinSnr[sfb] = round16(snr);
}
}
/*****************************************************************************
*
* function name: InitPsyConfigurationLong
* description: init long block psychoacoustic configuration
*
*****************************************************************************/
Word16 InitPsyConfigurationLong(Word32 bitrate,
Word32 samplerate,
Word16 bandwidth,
PSY_CONFIGURATION_LONG *psyConf)
{
Word32 samplerateindex;
Word16 sfbBarcVal[MAX_SFB_LONG];
Word16 sfb;
/*
init sfb table
*/
samplerateindex = GetSRIndex(samplerate);
psyConf->sfbCnt = sfBandTotalLong[samplerateindex];
psyConf->sfbOffset = sfBandTabLong + sfBandTabLongOffset[samplerateindex];
psyConf->sampRateIdx = samplerateindex;
/*
calculate barc values for each pb
*/
initBarcValues(psyConf->sfbCnt,
psyConf->sfbOffset,
psyConf->sfbOffset[psyConf->sfbCnt],
samplerate,
sfbBarcVal);
/*
init thresholds in quiet
*/
initThrQuiet(psyConf->sfbCnt,
psyConf->sfbOffset,
sfbBarcVal,
psyConf->sfbThresholdQuiet);
/*
calculate spreading function
*/
initSpreading(psyConf->sfbCnt,
sfbBarcVal,
psyConf->sfbMaskLowFactor,
psyConf->sfbMaskHighFactor,
psyConf->sfbMaskLowFactorSprEn,
psyConf->sfbMaskHighFactorSprEn,
bitrate,
LONG_WINDOW);
/*
init ratio
*/
psyConf->ratio = c_ratio;
psyConf->maxAllowedIncreaseFactor = 2;
psyConf->minRemainingThresholdFactor = c_minRemainingThresholdFactor; /* 0.01 *(1 << 15)*/
psyConf->clipEnergy = c_maxClipEnergyLong;
psyConf->lowpassLine = extract_l((bandwidth<<1) * FRAME_LEN_LONG / samplerate);
for (sfb = 0; sfb < psyConf->sfbCnt; sfb++) {
if (sub(psyConf->sfbOffset[sfb], psyConf->lowpassLine) >= 0)
break;
}
psyConf->sfbActive = sfb;
/*
calculate minSnr
*/
initMinSnr(bitrate,
samplerate,
psyConf->sfbOffset[psyConf->sfbCnt],
psyConf->sfbOffset,
sfbBarcVal,
psyConf->sfbActive,
psyConf->sfbMinSnr);
return(0);
}
/*****************************************************************************
*
* function name: InitPsyConfigurationShort
* description: init short block psychoacoustic configuration
*
*****************************************************************************/
Word16 InitPsyConfigurationShort(Word32 bitrate,
Word32 samplerate,
Word16 bandwidth,
PSY_CONFIGURATION_SHORT *psyConf)
{
Word32 samplerateindex;
Word16 sfbBarcVal[MAX_SFB_SHORT];
Word16 sfb;
/*
init sfb table
*/
samplerateindex = GetSRIndex(samplerate);
psyConf->sfbCnt = sfBandTotalShort[samplerateindex];
psyConf->sfbOffset = sfBandTabShort + sfBandTabShortOffset[samplerateindex];
psyConf->sampRateIdx = samplerateindex;
/*
calculate barc values for each pb
*/
initBarcValues(psyConf->sfbCnt,
psyConf->sfbOffset,
psyConf->sfbOffset[psyConf->sfbCnt],
samplerate,
sfbBarcVal);
/*
init thresholds in quiet
*/
initThrQuiet(psyConf->sfbCnt,
psyConf->sfbOffset,
sfbBarcVal,
psyConf->sfbThresholdQuiet);
/*
calculate spreading function
*/
initSpreading(psyConf->sfbCnt,
sfbBarcVal,
psyConf->sfbMaskLowFactor,
psyConf->sfbMaskHighFactor,
psyConf->sfbMaskLowFactorSprEn,
psyConf->sfbMaskHighFactorSprEn,
bitrate,
SHORT_WINDOW);
/*
init ratio
*/
psyConf->ratio = c_ratio;
psyConf->maxAllowedIncreaseFactor = 2;
psyConf->minRemainingThresholdFactor = c_minRemainingThresholdFactor;
psyConf->clipEnergy = c_maxClipEnergyShort;
psyConf->lowpassLine = extract_l(((bandwidth << 1) * FRAME_LEN_SHORT) / samplerate);
for (sfb = 0; sfb < psyConf->sfbCnt; sfb++) {
if (psyConf->sfbOffset[sfb] >= psyConf->lowpassLine)
break;
}
psyConf->sfbActive = sfb;
/*
calculate minSnr
*/
initMinSnr(bitrate,
samplerate,
psyConf->sfbOffset[psyConf->sfbCnt],
psyConf->sfbOffset,
sfbBarcVal,
psyConf->sfbActive,
psyConf->sfbMinSnr);
return(0);
}