545 files changed, 230976 insertions, 0 deletions
diff --git a/audio_codec/libraac/sbrfreq.c b/audio_codec/libraac/sbrfreq.c new file mode 100644 index 0000000..e391046 --- a/dev/null +++ b/audio_codec/libraac/sbrfreq.c @@ -0,0 +1,667 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Source last modified: $Id: sbrfreq.c,v 1.2 2005/05/20 18:05:41 jrecker Exp $ + * + * Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, + * are subject to the current version of the RealNetworks Public + * Source License (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the current version of the RealNetworks Community + * Source License (the "RCSL") available at + * http://www.helixcommunity.org/content/rcsl, in which case the RCSL + * will apply. You may also obtain the license terms directly from + * RealNetworks. You may not use this file except in compliance with + * the RPSL or, if you have a valid RCSL with RealNetworks applicable + * to this file, the RCSL. Please see the applicable RPSL or RCSL for + * the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the + * portions it created. + * + * This file, and the files included with this file, is distributed + * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS + * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET + * ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point HE-AAC decoder + * Jon Recker (jrecker@real.com) + * February 2005 + * + * sbrfreq.c - frequency band table calculation for SBR + **************************************************************************************/ + +#include "sbr.h" +#include "assembly.h" + +/************************************************************************************** + * Function: BubbleSort + * + * Description: in-place sort of unsigned chars + * + * Inputs: buffer of elements to sort + * number of elements to sort + * + * Outputs: sorted buffer + * + * Return: none + **************************************************************************************/ +static void BubbleSort(unsigned char *v, int nItems) +{ + int i; + unsigned char t; + + while (nItems >= 2) { + for (i = 0; i < nItems - 1; i++) { + if (v[i + 1] < v[i]) { + t = v[i + 1]; + v[i + 1] = v[i]; + v[i] = t; + } + } + nItems--; + } +} + +/************************************************************************************** + * Function: VMin + * + * Description: find smallest element in a buffer of unsigned chars + * + * Inputs: buffer of elements to search + * number of elements to search + * + * Outputs: none + * + * Return: smallest element in buffer + **************************************************************************************/ +static unsigned char VMin(unsigned char *v, int nItems) +{ + int i; + unsigned char vMin; + + vMin = v[0]; + for (i = 1; i < nItems; i++) { + if (v[i] < vMin) { + vMin = v[i]; + } + } + return vMin; +} + +/************************************************************************************** + * Function: VMax + * + * Description: find largest element in a buffer of unsigned chars + * + * Inputs: buffer of elements to search + * number of elements to search + * + * Outputs: none + * + * Return: largest element in buffer + **************************************************************************************/ +static unsigned char VMax(unsigned char *v, int nItems) +{ + int i; + unsigned char vMax; + + vMax = v[0]; + for (i = 1; i < nItems; i++) { + if (v[i] > vMax) { + vMax = v[i]; + } + } + return vMax; +} + +/************************************************************************************** + * Function: CalcFreqMasterScaleZero + * + * Description: calculate master frequency table when freqScale == 0 + * (4.6.18.3.2.1, figure 4.39) + * + * Inputs: alterScale flag + * index of first QMF subband in master freq table (k0) + * index of last QMF subband (k2) + * + * Outputs: master frequency table + * + * Return: number of bands in master frequency table + * + * Notes: assumes k2 - k0 <= 48 and k2 >= k0 (4.6.18.3.6) + **************************************************************************************/ +static int CalcFreqMasterScaleZero(unsigned char *freqMaster, int alterScale, int k0, int k2) +{ + int nMaster, k, nBands, k2Achieved, dk, vDk[64], k2Diff; + + if (alterScale) { + dk = 2; + nBands = 2 * ((k2 - k0 + 2) >> 2); + } else { + dk = 1; + nBands = 2 * ((k2 - k0) >> 1); + } + + if (nBands <= 0) { + return 0; + } + + k2Achieved = k0 + nBands * dk; + k2Diff = k2 - k2Achieved; + for (k = 0; k < nBands; k++) { + vDk[k] = dk; + } + + if (k2Diff > 0) { + k = nBands - 1; + while (k2Diff) { + vDk[k]++; + k--; + k2Diff--; + } + } else if (k2Diff < 0) { + k = 0; + while (k2Diff) { + vDk[k]--; + k++; + k2Diff++; + } + } + + nMaster = nBands; + freqMaster[0] = k0; + for (k = 1; k <= nBands; k++) { + freqMaster[k] = freqMaster[k - 1] + vDk[k - 1]; + } + + return nMaster; +} + +/* mBandTab[i] = temp1[i] / 2 */ +static const int mBandTab[3] = {6, 5, 4}; + +/* invWarpTab[i] = 1.0 / temp2[i], Q30 (see 4.6.18.3.2.1) */ +static const int invWarpTab[2] = {0x40000000, 0x313b13b1}; + +/************************************************************************************** + * Function: CalcFreqMasterScale + * + * Description: calculate master frequency table when freqScale > 0 + * (4.6.18.3.2.1, figure 4.39) + * + * Inputs: alterScale flag + * freqScale flag + * index of first QMF subband in master freq table (k0) + * index of last QMF subband (k2) + * + * Outputs: master frequency table + * + * Return: number of bands in master frequency table + * + * Notes: assumes k2 - k0 <= 48 and k2 >= k0 (4.6.18.3.6) + **************************************************************************************/ +static int CalcFreqMaster(unsigned char *freqMaster, int freqScale, int alterScale, int k0, int k2) +{ + int bands, twoRegions, k, k1, t, vLast, vCurr, pCurr; + int invWarp, nBands0, nBands1, change; + unsigned char vDk1Min, vDk0Max; + unsigned char *vDelta; + + if (freqScale < 1 || freqScale > 3) { + return -1; + } + + bands = mBandTab[freqScale - 1]; + invWarp = invWarpTab[alterScale]; + + /* tested for all k0 = [5, 64], k2 = [k0, 64] */ + if (k2 * 10000 > 22449 * k0) { + twoRegions = 1; + k1 = 2 * k0; + } else { + twoRegions = 0; + k1 = k2; + } + + /* tested for all k0 = [5, 64], k1 = [k0, 64], freqScale = [1,3] */ + t = (log2Tab[k1] - log2Tab[k0]) >> 3; /* log2(k1/k0), Q28 to Q25 */ + nBands0 = 2 * (((bands * t) + (1 << 24)) >> 25); /* multiply by bands/2, round to nearest int (mBandTab has factor of 1/2 rolled in) */ + + /* tested for all valid combinations of k0, k1, nBands (from sampRate, freqScale, alterScale) + * roundoff error can be a problem with fixpt (e.g. pCurr = 12.499999 instead of 12.50003) + * because successive multiplication always undershoots a little bit, but this + * doesn't occur in any of the ratios we encounter from the valid k0/k1 bands in the spec + */ + t = RatioPowInv(k1, k0, nBands0); + pCurr = k0 << 24; + vLast = k0; + vDelta = freqMaster + 1; /* operate in-place */ + for (k = 0; k < nBands0; k++) { + pCurr = MULSHIFT32(pCurr, t) << 8; /* keep in Q24 */ + vCurr = (pCurr + (1 << 23)) >> 24; + vDelta[k] = (vCurr - vLast); + vLast = vCurr; + } + + /* sort the deltas and find max delta for first region */ + BubbleSort(vDelta, nBands0); + vDk0Max = VMax(vDelta, nBands0); + + /* fill master frequency table with bands from first region */ + freqMaster[0] = k0; + for (k = 1; k <= nBands0; k++) { + freqMaster[k] += freqMaster[k - 1]; + } + + /* if only one region, then the table is complete */ + if (!twoRegions) { + return nBands0; + } + + /* tested for all k1 = [10, 64], k2 = [k0, 64], freqScale = [1,3] */ + t = (log2Tab[k2] - log2Tab[k1]) >> 3; /* log2(k1/k0), Q28 to Q25 */ + t = MULSHIFT32(bands * t, invWarp) << 2; /* multiply by bands/2, divide by warp factor, keep Q25 */ + nBands1 = 2 * ((t + (1 << 24)) >> 25); /* round to nearest int */ + + /* see comments above for calculations in first region */ + t = RatioPowInv(k2, k1, nBands1); + pCurr = k1 << 24; + vLast = k1; + vDelta = freqMaster + nBands0 + 1; /* operate in-place */ + for (k = 0; k < nBands1; k++) { + pCurr = MULSHIFT32(pCurr, t) << 8; /* keep in Q24 */ + vCurr = (pCurr + (1 << 23)) >> 24; + vDelta[k] = (vCurr - vLast); + vLast = vCurr; + } + + /* sort the deltas, adjusting first and last if the second region has smaller deltas than the first */ + vDk1Min = VMin(vDelta, nBands1); + if (vDk1Min < vDk0Max) { + BubbleSort(vDelta, nBands1); + change = vDk0Max - vDelta[0]; + if (change > ((vDelta[nBands1 - 1] - vDelta[0]) >> 1)) { + change = ((vDelta[nBands1 - 1] - vDelta[0]) >> 1); + } + vDelta[0] += change; + vDelta[nBands1 - 1] -= change; + } + BubbleSort(vDelta, nBands1); + + /* fill master frequency table with bands from second region + * Note: freqMaster[nBands0] = k1 + */ + for (k = 1; k <= nBands1; k++) { + freqMaster[k + nBands0] += freqMaster[k + nBands0 - 1]; + } + + return (nBands0 + nBands1); +} + +/************************************************************************************** + * Function: CalcFreqHigh + * + * Description: calculate high resolution frequency table (4.6.18.3.2.2) + * + * Inputs: master frequency table + * number of bands in master frequency table + * crossover band from header + * + * Outputs: high resolution frequency table + * + * Return: number of bands in high resolution frequency table + **************************************************************************************/ +static int CalcFreqHigh(unsigned char *freqHigh, unsigned char *freqMaster, int nMaster, int crossOverBand) +{ + int k, nHigh; + + nHigh = nMaster - crossOverBand; + + for (k = 0; k <= nHigh; k++) { + freqHigh[k] = freqMaster[k + crossOverBand]; + } + + return nHigh; +} + +/************************************************************************************** + * Function: CalcFreqLow + * + * Description: calculate low resolution frequency table (4.6.18.3.2.2) + * + * Inputs: high resolution frequency table + * number of bands in high resolution frequency table + * + * Outputs: low resolution frequency table + * + * Return: number of bands in low resolution frequency table + **************************************************************************************/ +static int CalcFreqLow(unsigned char *freqLow, unsigned char *freqHigh, int nHigh) +{ + int k, nLow, oddFlag; + + nLow = nHigh - (nHigh >> 1); + freqLow[0] = freqHigh[0]; + oddFlag = nHigh & 0x01; + + for (k = 1; k <= nLow; k++) { + freqLow[k] = freqHigh[2 * k - oddFlag]; + } + + return nLow; +} + +/************************************************************************************** + * Function: CalcFreqNoise + * + * Description: calculate noise floor frequency table (4.6.18.3.2.2) + * + * Inputs: low resolution frequency table + * number of bands in low resolution frequency table + * index of starting QMF subband for SBR (kStart) + * index of last QMF subband (k2) + * number of noise bands + * + * Outputs: noise floor frequency table + * + * Return: number of bands in noise floor frequency table + **************************************************************************************/ +static int CalcFreqNoise(unsigned char *freqNoise, unsigned char *freqLow, int nLow, int kStart, int k2, int noiseBands) +{ + int i, iLast, k, nQ, lTop, lBottom; + + lTop = log2Tab[k2]; + lBottom = log2Tab[kStart]; + nQ = noiseBands * ((lTop - lBottom) >> 2); /* Q28 to Q26, noiseBands = [0,3] */ + nQ = (nQ + (1 << 25)) >> 26; + if (nQ < 1) { + nQ = 1; + } + + ASSERT(nQ <= MAX_NUM_NOISE_FLOOR_BANDS); /* required from 4.6.18.3.6 */ + + iLast = 0; + freqNoise[0] = freqLow[0]; + for (k = 1; k <= nQ; k++) { + i = iLast + (nLow - iLast) / (nQ + 1 - k); /* truncating division */ + freqNoise[k] = freqLow[i]; + iLast = i; + } + + return nQ; +} + +/************************************************************************************** + * Function: BuildPatches + * + * Description: build high frequency patches (4.6.18.6.3) + * + * Inputs: master frequency table + * number of bands in low resolution frequency table + * index of first QMF subband in master freq table (k0) + * index of starting QMF subband for SBR (kStart) + * number of QMF bands in high resolution frequency table + * sample rate index + * + * Outputs: starting subband for each patch + * number of subbands in each patch + * + * Return: number of patches + **************************************************************************************/ +static int BuildPatches(unsigned char *patchNumSubbands, unsigned char *patchStartSubband, unsigned char *freqMaster, + int nMaster, int k0, int kStart, int numQMFBands, int sampRateIdx) +{ + int i, j, k; + int msb, sb, usb, numPatches, goalSB, oddFlag; + + msb = k0; + usb = kStart; + numPatches = 0; + goalSB = goalSBTab[sampRateIdx]; + + if (nMaster == 0) { + patchNumSubbands[0] = 0; + patchStartSubband[0] = 0; + return 0; + } + + if (goalSB < kStart + numQMFBands) { + k = 0; + for (i = 0; freqMaster[i] < goalSB; i++) { + k = i + 1; + } + } else { + k = nMaster; + } + + do { + j = k + 1; + do { + j--; + sb = freqMaster[j]; + oddFlag = (sb - 2 + k0) & 0x01; + } while (sb > k0 - 1 + msb - oddFlag); + + patchNumSubbands[numPatches] = MAX(sb - usb, 0); + patchStartSubband[numPatches] = k0 - oddFlag - patchNumSubbands[numPatches]; + + /* from MPEG reference code - slightly different from spec */ + if ((patchNumSubbands[numPatches] < 3) && (numPatches > 0)) { + break; + } + + if (patchNumSubbands[numPatches] > 0) { + usb = sb; + msb = sb; + numPatches++; + } else { + msb = kStart; + } + + if (freqMaster[k] - sb < 3) { + k = nMaster; + } + + } while (sb != (kStart + numQMFBands) && numPatches <= MAX_NUM_PATCHES); + + return numPatches; +} + +/************************************************************************************** + * Function: FindFreq + * + * Description: search buffer of unsigned chars for a specific value + * + * Inputs: buffer of elements to search + * number of elements to search + * value to search for + * + * Outputs: none + * + * Return: non-zero if the value is found anywhere in the buffer, zero otherwise + **************************************************************************************/ +static int FindFreq(unsigned char *freq, int nFreq, unsigned char val) +{ + int k; + + for (k = 0; k < nFreq; k++) { + if (freq[k] == val) { + return 1; + } + } + + return 0; +} + +/************************************************************************************** + * Function: RemoveFreq + * + * Description: remove one element from a buffer of unsigned chars + * + * Inputs: buffer of elements + * number of elements + * index of element to remove + * + * Outputs: new buffer of length nFreq-1 + * + * Return: none + **************************************************************************************/ +static void RemoveFreq(unsigned char *freq, int nFreq, int removeIdx) +{ + int k; + + if (removeIdx >= nFreq) { + return; + } + + for (k = removeIdx; k < nFreq - 1; k++) { + freq[k] = freq[k + 1]; + } +} + +/************************************************************************************** + * Function: CalcFreqLimiter + * + * Description: calculate limiter frequency table (4.6.18.3.2.3) + * + * Inputs: number of subbands in each patch + * low resolution frequency table + * number of bands in low resolution frequency table + * index of starting QMF subband for SBR (kStart) + * number of limiter bands + * number of patches + * + * Outputs: limiter frequency table + * + * Return: number of bands in limiter frequency table + **************************************************************************************/ +static int CalcFreqLimiter(unsigned char *freqLimiter, unsigned char *patchNumSubbands, unsigned char *freqLow, + int nLow, int kStart, int limiterBands, int numPatches) +{ + int k, bands, nLimiter, nOctaves; + int limBandsPerOctave[3] = {120, 200, 300}; /* [1.2, 2.0, 3.0] * 100 */ + unsigned char patchBorders[MAX_NUM_PATCHES + 1]; + + /* simple case */ + if (limiterBands == 0) { + freqLimiter[0] = freqLow[0] - kStart; + freqLimiter[1] = freqLow[nLow] - kStart; + return 1; + } + + bands = limBandsPerOctave[limiterBands - 1]; + patchBorders[0] = kStart; + + /* from MPEG reference code - slightly different from spec (top border) */ + for (k = 1; k < numPatches; k++) { + patchBorders[k] = patchBorders[k - 1] + patchNumSubbands[k - 1]; + } + patchBorders[k] = freqLow[nLow]; + + for (k = 0; k <= nLow; k++) { + freqLimiter[k] = freqLow[k]; + } + + for (k = 1; k < numPatches; k++) { + freqLimiter[k + nLow] = patchBorders[k]; + } + + k = 1; + nLimiter = nLow + numPatches - 1; + BubbleSort(freqLimiter, nLimiter + 1); + + while (k <= nLimiter) { + nOctaves = log2Tab[freqLimiter[k]] - log2Tab[freqLimiter[k - 1]]; /* Q28 */ + nOctaves = (nOctaves >> 9) * bands; /* Q19, max bands = 300 < 2^9 */ + if (nOctaves < (49 << 19)) { /* compare with 0.49*100, in Q19 */ + if (freqLimiter[k] == freqLimiter[k - 1] || FindFreq(patchBorders, numPatches + 1, freqLimiter[k]) == 0) { + RemoveFreq(freqLimiter, nLimiter + 1, k); + nLimiter--; + } else if (FindFreq(patchBorders, numPatches + 1, freqLimiter[k - 1]) == 0) { + RemoveFreq(freqLimiter, nLimiter + 1, k - 1); + nLimiter--; + } else { + k++; + } + } else { + k++; + } + } + + /* store limiter boundaries as offsets from kStart */ + for (k = 0; k <= nLimiter; k++) { + freqLimiter[k] -= kStart; + } + + return nLimiter; +} + +/************************************************************************************** + * Function: CalcFreqTables + * + * Description: calulate master and derived frequency tables, and patches + * + * Inputs: initialized SBRHeader struct for this SCE/CPE block + * initialized SBRFreq struct for this SCE/CPE block + * sample rate index of output sample rate (after SBR) + * + * Outputs: master and derived frequency tables, and patches + * + * Return: non-zero if error, zero otherwise + **************************************************************************************/ +int CalcFreqTables(SBRHeader *sbrHdr, SBRFreq *sbrFreq, int sampRateIdx) +{ + int k0, k2; + + k0 = k0Tab[sampRateIdx][sbrHdr->startFreq]; + + if (sbrHdr->stopFreq == 14) { + k2 = 2 * k0; + } else if (sbrHdr->stopFreq == 15) { + k2 = 3 * k0; + } else { + k2 = k2Tab[sampRateIdx][sbrHdr->stopFreq]; + } + if (k2 > 64) { + k2 = 64; + } + + /* calculate master frequency table */ + if (sbrHdr->freqScale == 0) { + sbrFreq->nMaster = CalcFreqMasterScaleZero(sbrFreq->freqMaster, sbrHdr->alterScale, k0, k2); + } else { + sbrFreq->nMaster = CalcFreqMaster(sbrFreq->freqMaster, sbrHdr->freqScale, sbrHdr->alterScale, k0, k2); + } + + /* calculate high frequency table and related parameters */ + sbrFreq->nHigh = CalcFreqHigh(sbrFreq->freqHigh, sbrFreq->freqMaster, sbrFreq->nMaster, sbrHdr->crossOverBand); + sbrFreq->numQMFBands = sbrFreq->freqHigh[sbrFreq->nHigh] - sbrFreq->freqHigh[0]; + sbrFreq->kStart = sbrFreq->freqHigh[0]; + + /* calculate low frequency table */ + sbrFreq->nLow = CalcFreqLow(sbrFreq->freqLow, sbrFreq->freqHigh, sbrFreq->nHigh); + + /* calculate noise floor frequency table */ + sbrFreq->numNoiseFloorBands = CalcFreqNoise(sbrFreq->freqNoise, sbrFreq->freqLow, sbrFreq->nLow, sbrFreq->kStart, k2, sbrHdr->noiseBands); + + /* calculate limiter table */ + sbrFreq->numPatches = BuildPatches(sbrFreq->patchNumSubbands, sbrFreq->patchStartSubband, sbrFreq->freqMaster, + sbrFreq->nMaster, k0, sbrFreq->kStart, sbrFreq->numQMFBands, sampRateIdx); + sbrFreq->nLimiter = CalcFreqLimiter(sbrFreq->freqLimiter, sbrFreq->patchNumSubbands, sbrFreq->freqLow, sbrFreq->nLow, sbrFreq->kStart, + sbrHdr->limiterBands, sbrFreq->numPatches); + + return 0; +} |