| /*
|
| ** 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, |
| 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, |
| 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); |
| } |
| |