| /* |
| ** 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: sf_estim.c |
| |
| Content: Scale factor estimation functions |
| |
| *******************************************************************************/ |
| |
| #include "basic_op.h" |
| #include "oper_32b.h" |
| #include "sf_estim.h" |
| #include "quantize.h" |
| #include "bit_cnt.h" |
| #include "aac_rom.h" |
| |
| static const Word16 MAX_SCF_DELTA = 60; |
| |
| /*! |
| constants reference in comments |
| |
| C0 = 6.75f; |
| C1 = -69.33295f; -16/3*log(MAX_QUANT+0.5-logCon)/log(2) |
| C2 = 4.0f; |
| C3 = 2.66666666f; |
| |
| PE_C1 = 3.0f; log(8.0)/log(2) |
| PE_C2 = 1.3219281f; log(2.5)/log(2) |
| PE_C3 = 0.5593573f; 1-C2/C1 |
| |
| */ |
| |
| #define FF_SQRT_BITS 7 |
| #define FF_SQRT_TABLE_SIZE (1<<FF_SQRT_BITS - 1<<(FF_SQRT_BITS-2)) |
| #define COEF08_31 0x66666666 /* 0.8*(1 << 31) */ |
| #define PE_C1_8 24 /* PE_C1*8 */ |
| #define PE_C2_16 21 /* PE_C2*8/PE_C3 */ |
| #define PE_SCALE 0x059a /* 0.7 * (1 << (15 - 1 - 3))*/ |
| |
| #define SCALE_ESTIMATE_COEF 0x5555 /* (8.8585/(4*log2(10))) * (1 << 15)*/ |
| |
| /********************************************************************************* |
| * |
| * function name: formfac_sqrt |
| * description: calculates sqrt(x)/256 |
| * |
| **********************************************************************************/ |
| __inline Word32 formfac_sqrt(Word32 x) |
| { |
| Word32 y; |
| Word32 preshift, postshift; |
| |
| |
| if (x==0) return 0; |
| preshift = norm_l(x) - (INT_BITS-1-FF_SQRT_BITS); |
| postshift = preshift >> 1; |
| preshift = postshift << 1; |
| postshift = postshift + 8; /* sqrt/256 */ |
| if(preshift >= 0) |
| y = x << preshift; /* now 1/4 <= y < 1 */ |
| else |
| y = x >> (-preshift); |
| y = formfac_sqrttable[y-32]; |
| |
| if(postshift >= 0) |
| y = y >> postshift; |
| else |
| y = y << (-postshift); |
| |
| return y; |
| } |
| |
| |
| /********************************************************************************* |
| * |
| * function name: CalcFormFactorChannel |
| * description: calculate the form factor one channel |
| * ffac(n) = sqrt(abs(X(k)) + sqrt(abs(X(k+1)) + .... |
| * |
| **********************************************************************************/ |
| static void |
| CalcFormFactorChannel(Word16 *logSfbFormFactor, |
| Word16 *sfbNRelevantLines, |
| Word16 *logSfbEnergy, |
| PSY_OUT_CHANNEL *psyOutChan) |
| { |
| Word32 sfbw, sfbw1; |
| Word32 i, j; |
| Word32 sfbOffs, sfb, shift; |
| |
| sfbw = sfbw1 = 0; |
| for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup){ |
| for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) { |
| i = sfbOffs+sfb; |
| |
| if (psyOutChan->sfbEnergy[i] > psyOutChan->sfbThreshold[i]) { |
| Word32 accu, avgFormFactor,iSfbWidth; |
| Word32 *mdctSpec; |
| sfbw = psyOutChan->sfbOffsets[i+1] - psyOutChan->sfbOffsets[i]; |
| iSfbWidth = invSBF[(sfbw >> 2) - 1]; |
| mdctSpec = psyOutChan->mdctSpectrum + psyOutChan->sfbOffsets[i]; |
| accu = 0; |
| /* calc sum of sqrt(spec) */ |
| for (j=sfbw; j; j--) { |
| accu += formfac_sqrt(L_abs(*mdctSpec)); mdctSpec++; |
| } |
| logSfbFormFactor[i] = iLog4(accu); |
| logSfbEnergy[i] = iLog4(psyOutChan->sfbEnergy[i]); |
| avgFormFactor = fixmul(rsqrt(psyOutChan->sfbEnergy[i],INT_BITS), iSfbWidth); |
| avgFormFactor = rsqrt((Word32)avgFormFactor,INT_BITS) >> 10; |
| /* result is multiplied by 4 */ |
| if(avgFormFactor) |
| sfbNRelevantLines[i] = accu / avgFormFactor; |
| else |
| sfbNRelevantLines[i] = 0x7fff; |
| } |
| else { |
| /* set number of lines to zero */ |
| sfbNRelevantLines[i] = 0; |
| } |
| } |
| } |
| } |
| |
| /********************************************************************************* |
| * |
| * function name: improveScf |
| * description: find better scalefactor with analysis by synthesis |
| * |
| **********************************************************************************/ |
| static Word16 improveScf(Word32 *spec, |
| Word16 sfbWidth, |
| Word32 thresh, |
| Word16 scf, |
| Word16 minScf, |
| Word32 *dist, |
| Word16 *minScfCalculated) |
| { |
| Word32 cnt; |
| Word32 sfbDist; |
| Word32 scfBest; |
| Word32 thresh125 = L_add(thresh, (thresh >> 2)); |
| |
| scfBest = scf; |
| |
| /* calc real distortion */ |
| sfbDist = calcSfbDist(spec, sfbWidth, scf); |
| *minScfCalculated = scf; |
| if(!sfbDist) |
| return scfBest; |
| |
| if (sfbDist > thresh125) { |
| Word32 scfEstimated; |
| Word32 sfbDistBest; |
| scfEstimated = scf; |
| sfbDistBest = sfbDist; |
| |
| cnt = 0; |
| while (sfbDist > thresh125 && (cnt < 3)) { |
| |
| scf = scf + 1; |
| sfbDist = calcSfbDist(spec, sfbWidth, scf); |
| |
| if (sfbDist < sfbDistBest) { |
| scfBest = scf; |
| sfbDistBest = sfbDist; |
| } |
| cnt = cnt + 1; |
| } |
| cnt = 0; |
| scf = scfEstimated; |
| sfbDist = sfbDistBest; |
| while ((sfbDist > thresh125) && (cnt < 1) && (scf > minScf)) { |
| |
| scf = scf - 1; |
| sfbDist = calcSfbDist(spec, sfbWidth, scf); |
| |
| if (sfbDist < sfbDistBest) { |
| scfBest = scf; |
| sfbDistBest = sfbDist; |
| } |
| *minScfCalculated = scf; |
| cnt = cnt + 1; |
| } |
| *dist = sfbDistBest; |
| } |
| else { |
| Word32 sfbDistBest; |
| Word32 sfbDistAllowed; |
| Word32 thresh08 = fixmul(COEF08_31, thresh); |
| sfbDistBest = sfbDist; |
| |
| if (sfbDist < thresh08) |
| sfbDistAllowed = sfbDist; |
| else |
| sfbDistAllowed = thresh08; |
| for (cnt=0; cnt<3; cnt++) { |
| scf = scf + 1; |
| sfbDist = calcSfbDist(spec, sfbWidth, scf); |
| |
| if (fixmul(COEF08_31,sfbDist) < sfbDistAllowed) { |
| *minScfCalculated = scfBest + 1; |
| scfBest = scf; |
| sfbDistBest = sfbDist; |
| } |
| } |
| *dist = sfbDistBest; |
| } |
| |
| /* return best scalefactor */ |
| return scfBest; |
| } |
| |
| /********************************************************************************* |
| * |
| * function name: countSingleScfBits |
| * description: count single scf bits in huffum |
| * |
| **********************************************************************************/ |
| static Word16 countSingleScfBits(Word16 scf, Word16 scfLeft, Word16 scfRight) |
| { |
| Word16 scfBits; |
| |
| scfBits = bitCountScalefactorDelta(scfLeft - scf) + |
| bitCountScalefactorDelta(scf - scfRight); |
| |
| return scfBits; |
| } |
| |
| /********************************************************************************* |
| * |
| * function name: calcSingleSpecPe |
| * description: ldRatio = log2(en(n)) - 0,375*scfGain(n) |
| * nbits = 0.7*nLines*ldRation for ldRation >= c1 |
| * nbits = 0.7*nLines*(c2 + c3*ldRatio) for ldRation < c1 |
| * |
| **********************************************************************************/ |
| static Word16 calcSingleSpecPe(Word16 scf, Word16 sfbConstPePart, Word16 nLines) |
| { |
| Word32 specPe; |
| Word32 ldRatio; |
| Word32 scf3; |
| |
| ldRatio = sfbConstPePart << 3; /* (sfbConstPePart -0.375*scf)*8 */ |
| scf3 = scf + scf + scf; |
| ldRatio = ldRatio - scf3; |
| |
| if (ldRatio < PE_C1_8) { |
| /* 21 : 2*8*PE_C2, 2*PE_C3 ~ 1*/ |
| ldRatio = (ldRatio + PE_C2_16) >> 1; |
| } |
| specPe = nLines * ldRatio; |
| specPe = (specPe * PE_SCALE) >> 14; |
| |
| return saturate(specPe); |
| } |
| |
| |
| /********************************************************************************* |
| * |
| * function name: countScfBitsDiff |
| * description: count different scf bits used |
| * |
| **********************************************************************************/ |
| static Word16 countScfBitsDiff(Word16 *scfOld, Word16 *scfNew, |
| Word16 sfbCnt, Word16 startSfb, Word16 stopSfb) |
| { |
| Word32 scfBitsDiff; |
| Word32 sfb, sfbLast; |
| Word32 sfbPrev, sfbNext; |
| |
| scfBitsDiff = 0; |
| sfb = 0; |
| |
| /* search for first relevant sfb */ |
| sfbLast = startSfb; |
| while (sfbLast < stopSfb && scfOld[sfbLast] == VOAAC_SHRT_MIN) { |
| |
| sfbLast = sfbLast + 1; |
| } |
| /* search for previous relevant sfb and count diff */ |
| sfbPrev = startSfb - 1; |
| while ((sfbPrev>=0) && scfOld[sfbPrev] == VOAAC_SHRT_MIN) { |
| |
| sfbPrev = sfbPrev - 1; |
| } |
| |
| if (sfbPrev>=0) { |
| scfBitsDiff += bitCountScalefactorDelta(scfNew[sfbPrev] - scfNew[sfbLast]) - |
| bitCountScalefactorDelta(scfOld[sfbPrev] - scfOld[sfbLast]); |
| } |
| /* now loop through all sfbs and count diffs of relevant sfbs */ |
| for (sfb=sfbLast+1; sfb<stopSfb; sfb++) { |
| |
| if (scfOld[sfb] != VOAAC_SHRT_MIN) { |
| scfBitsDiff += bitCountScalefactorDelta(scfNew[sfbLast] - scfNew[sfb]) - |
| bitCountScalefactorDelta(scfOld[sfbLast] - scfOld[sfb]); |
| sfbLast = sfb; |
| } |
| } |
| /* search for next relevant sfb and count diff */ |
| sfbNext = stopSfb; |
| while (sfbNext < sfbCnt && scfOld[sfbNext] == VOAAC_SHRT_MIN) { |
| |
| sfbNext = sfbNext + 1; |
| } |
| |
| if (sfbNext < sfbCnt) |
| scfBitsDiff += bitCountScalefactorDelta(scfNew[sfbLast] - scfNew[sfbNext]) - |
| bitCountScalefactorDelta(scfOld[sfbLast] - scfOld[sfbNext]); |
| |
| return saturate(scfBitsDiff); |
| } |
| |
| static Word16 calcSpecPeDiff(Word16 *scfOld, |
| Word16 *scfNew, |
| Word16 *sfbConstPePart, |
| Word16 *logSfbEnergy, |
| Word16 *logSfbFormFactor, |
| Word16 *sfbNRelevantLines, |
| Word16 startSfb, |
| Word16 stopSfb) |
| { |
| Word32 specPeDiff; |
| Word32 sfb; |
| |
| specPeDiff = 0; |
| |
| /* loop through all sfbs and count pe difference */ |
| for (sfb=startSfb; sfb<stopSfb; sfb++) { |
| |
| |
| if (scfOld[sfb] != VOAAC_SHRT_MIN) { |
| Word32 ldRatioOld, ldRatioNew; |
| Word32 scf3; |
| |
| |
| if (sfbConstPePart[sfb] == MIN_16) { |
| sfbConstPePart[sfb] = ((logSfbEnergy[sfb] - |
| logSfbFormFactor[sfb]) + 11-8*4+3) >> 2; |
| } |
| |
| |
| ldRatioOld = sfbConstPePart[sfb] << 3; |
| scf3 = scfOld[sfb] + scfOld[sfb] + scfOld[sfb]; |
| ldRatioOld = ldRatioOld - scf3; |
| ldRatioNew = sfbConstPePart[sfb] << 3; |
| scf3 = scfNew[sfb] + scfNew[sfb] + scfNew[sfb]; |
| ldRatioNew = ldRatioNew - scf3; |
| |
| if (ldRatioOld < PE_C1_8) { |
| /* 21 : 2*8*PE_C2, 2*PE_C3 ~ 1*/ |
| ldRatioOld = (ldRatioOld + PE_C2_16) >> 1; |
| } |
| |
| if (ldRatioNew < PE_C1_8) { |
| /* 21 : 2*8*PE_C2, 2*PE_C3 ~ 1*/ |
| ldRatioNew = (ldRatioNew + PE_C2_16) >> 1; |
| } |
| |
| specPeDiff += sfbNRelevantLines[sfb] * (ldRatioNew - ldRatioOld); |
| } |
| } |
| |
| specPeDiff = (specPeDiff * PE_SCALE) >> 14; |
| |
| return saturate(specPeDiff); |
| } |
| |
| |
| /********************************************************************************* |
| * |
| * function name: assimilateSingleScf |
| * description: searched for single scalefactor bands, where the number of bits gained |
| * by using a smaller scfgain(n) is greater than the estimated increased |
| * bit demand |
| * |
| **********************************************************************************/ |
| static void assimilateSingleScf(PSY_OUT_CHANNEL *psyOutChan, |
| Word16 *scf, |
| Word16 *minScf, |
| Word32 *sfbDist, |
| Word16 *sfbConstPePart, |
| Word16 *logSfbEnergy, |
| Word16 *logSfbFormFactor, |
| Word16 *sfbNRelevantLines, |
| Word16 *minScfCalculated, |
| Flag restartOnSuccess) |
| { |
| Word16 sfbLast, sfbAct, sfbNext, scfAct, scfMin; |
| Word16 *scfLast, *scfNext; |
| Word32 sfbPeOld, sfbPeNew; |
| Word32 sfbDistNew; |
| Word32 j; |
| Flag success; |
| Word16 deltaPe, deltaPeNew, deltaPeTmp; |
| Word16 *prevScfLast = psyOutChan->prevScfLast; |
| Word16 *prevScfNext = psyOutChan->prevScfNext; |
| Word16 *deltaPeLast = psyOutChan->deltaPeLast; |
| Flag updateMinScfCalculated; |
| |
| success = 0; |
| deltaPe = 0; |
| |
| for(j=0;j<psyOutChan->sfbCnt;j++){ |
| prevScfLast[j] = MAX_16; |
| prevScfNext[j] = MAX_16; |
| deltaPeLast[j] = MAX_16; |
| } |
| |
| sfbLast = -1; |
| sfbAct = -1; |
| sfbNext = -1; |
| scfLast = 0; |
| scfNext = 0; |
| scfMin = MAX_16; |
| do { |
| /* search for new relevant sfb */ |
| sfbNext = sfbNext + 1; |
| while (sfbNext < psyOutChan->sfbCnt && scf[sfbNext] == MIN_16) { |
| |
| sfbNext = sfbNext + 1; |
| } |
| |
| if ((sfbLast>=0) && (sfbAct>=0) && sfbNext < psyOutChan->sfbCnt) { |
| /* relevant scfs to the left and to the right */ |
| scfAct = scf[sfbAct]; |
| scfLast = scf + sfbLast; |
| scfNext = scf + sfbNext; |
| scfMin = min(*scfLast, *scfNext); |
| } |
| else { |
| |
| if (sfbLast == -1 && (sfbAct>=0) && sfbNext < psyOutChan->sfbCnt) { |
| /* first relevant scf */ |
| scfAct = scf[sfbAct]; |
| scfLast = &scfAct; |
| scfNext = scf + sfbNext; |
| scfMin = *scfNext; |
| } |
| else { |
| |
| if ((sfbLast>=0) && (sfbAct>=0) && sfbNext == psyOutChan->sfbCnt) { |
| /* last relevant scf */ |
| scfAct = scf[sfbAct]; |
| scfLast = scf + sfbLast; |
| scfNext = &scfAct; |
| scfMin = *scfLast; |
| } |
| } |
| } |
| |
| if (sfbAct>=0) |
| scfMin = max(scfMin, minScf[sfbAct]); |
| |
| if ((sfbAct >= 0) && |
| (sfbLast>=0 || sfbNext < psyOutChan->sfbCnt) && |
| scfAct > scfMin && |
| (*scfLast != prevScfLast[sfbAct] || |
| *scfNext != prevScfNext[sfbAct] || |
| deltaPe < deltaPeLast[sfbAct])) { |
| success = 0; |
| |
| /* estimate required bits for actual scf */ |
| if (sfbConstPePart[sfbAct] == MIN_16) { |
| sfbConstPePart[sfbAct] = logSfbEnergy[sfbAct] - |
| logSfbFormFactor[sfbAct] + 11-8*4; /* 4*log2(6.75) - 32 */ |
| |
| if (sfbConstPePart[sfbAct] < 0) |
| sfbConstPePart[sfbAct] = sfbConstPePart[sfbAct] + 3; |
| sfbConstPePart[sfbAct] = sfbConstPePart[sfbAct] >> 2; |
| } |
| |
| sfbPeOld = calcSingleSpecPe(scfAct, sfbConstPePart[sfbAct], sfbNRelevantLines[sfbAct]) + |
| countSingleScfBits(scfAct, *scfLast, *scfNext); |
| deltaPeNew = deltaPe; |
| updateMinScfCalculated = 1; |
| do { |
| scfAct = scfAct - 1; |
| /* check only if the same check was not done before */ |
| |
| if (scfAct < minScfCalculated[sfbAct]) { |
| sfbPeNew = calcSingleSpecPe(scfAct, sfbConstPePart[sfbAct], sfbNRelevantLines[sfbAct]) + |
| countSingleScfBits(scfAct, *scfLast, *scfNext); |
| /* use new scf if no increase in pe and |
| quantization error is smaller */ |
| deltaPeTmp = deltaPe + sfbPeNew - sfbPeOld; |
| |
| if (deltaPeTmp < 10) { |
| sfbDistNew = calcSfbDist(psyOutChan->mdctSpectrum+ |
| psyOutChan->sfbOffsets[sfbAct], |
| (psyOutChan->sfbOffsets[sfbAct+1] - psyOutChan->sfbOffsets[sfbAct]), |
| scfAct); |
| if (sfbDistNew < sfbDist[sfbAct]) { |
| /* success, replace scf by new one */ |
| scf[sfbAct] = scfAct; |
| sfbDist[sfbAct] = sfbDistNew; |
| deltaPeNew = deltaPeTmp; |
| success = 1; |
| } |
| /* mark as already checked */ |
| |
| if (updateMinScfCalculated) { |
| minScfCalculated[sfbAct] = scfAct; |
| } |
| } |
| else { |
| updateMinScfCalculated = 0; |
| } |
| } |
| |
| } while (scfAct > scfMin); |
| deltaPe = deltaPeNew; |
| /* save parameters to avoid multiple computations of the same sfb */ |
| prevScfLast[sfbAct] = *scfLast; |
| prevScfNext[sfbAct] = *scfNext; |
| deltaPeLast[sfbAct] = deltaPe; |
| } |
| |
| if (success && restartOnSuccess) { |
| /* start again at first sfb */ |
| sfbLast = -1; |
| sfbAct = -1; |
| sfbNext = -1; |
| scfLast = 0; |
| scfNext = 0; |
| scfMin = MAX_16; |
| success = 0; |
| } |
| else { |
| /* shift sfbs for next band */ |
| sfbLast = sfbAct; |
| sfbAct = sfbNext; |
| } |
| |
| } while (sfbNext < psyOutChan->sfbCnt); |
| } |
| |
| |
| /********************************************************************************* |
| * |
| * function name: assimilateMultipleScf |
| * description: scalefactor difference reduction |
| * |
| **********************************************************************************/ |
| static void assimilateMultipleScf(PSY_OUT_CHANNEL *psyOutChan, |
| Word16 *scf, |
| Word16 *minScf, |
| Word32 *sfbDist, |
| Word16 *sfbConstPePart, |
| Word16 *logSfbEnergy, |
| Word16 *logSfbFormFactor, |
| Word16 *sfbNRelevantLines) |
| { |
| Word32 sfb, startSfb, stopSfb, scfMin, scfMax, scfAct; |
| Flag possibleRegionFound; |
| Word32 deltaScfBits; |
| Word32 deltaSpecPe; |
| Word32 deltaPe, deltaPeNew; |
| Word32 sfbCnt; |
| Word32 *sfbDistNew = psyOutChan->sfbDistNew; |
| Word16 *scfTmp = psyOutChan->prevScfLast; |
| |
| deltaPe = 0; |
| sfbCnt = psyOutChan->sfbCnt; |
| |
| /* calc min and max scalfactors */ |
| scfMin = MAX_16; |
| scfMax = MIN_16; |
| for (sfb=0; sfb<sfbCnt; sfb++) { |
| |
| if (scf[sfb] != MIN_16) { |
| scfMin = min(scfMin, scf[sfb]); |
| scfMax = max(scfMax, scf[sfb]); |
| } |
| } |
| |
| if (scfMax != MIN_16) { |
| |
| scfAct = scfMax; |
| |
| do { |
| scfAct = scfAct - 1; |
| for (sfb=0; sfb<sfbCnt; sfb++) { |
| scfTmp[sfb] = scf[sfb]; |
| } |
| stopSfb = 0; |
| do { |
| sfb = stopSfb; |
| |
| while (sfb < sfbCnt && (scf[sfb] == MIN_16 || scf[sfb] <= scfAct)) { |
| sfb = sfb + 1; |
| } |
| startSfb = sfb; |
| sfb = sfb + 1; |
| |
| while (sfb < sfbCnt && (scf[sfb] == MIN_16 || scf[sfb] > scfAct)) { |
| sfb = sfb + 1; |
| } |
| stopSfb = sfb; |
| |
| possibleRegionFound = 0; |
| |
| if (startSfb < sfbCnt) { |
| possibleRegionFound = 1; |
| for (sfb=startSfb; sfb<stopSfb; sfb++) { |
| |
| if (scf[sfb]!=MIN_16) { |
| |
| if (scfAct < minScf[sfb]) { |
| possibleRegionFound = 0; |
| break; |
| } |
| } |
| } |
| } |
| |
| |
| if (possibleRegionFound) { /* region found */ |
| |
| /* replace scfs in region by scfAct */ |
| for (sfb=startSfb; sfb<stopSfb; sfb++) { |
| |
| if (scfTmp[sfb]!=MIN_16) |
| scfTmp[sfb] = scfAct; |
| } |
| |
| /* estimate change in bit demand for new scfs */ |
| deltaScfBits = countScfBitsDiff(scf,scfTmp,sfbCnt,startSfb,stopSfb); |
| deltaSpecPe = calcSpecPeDiff(scf, scfTmp, sfbConstPePart, |
| logSfbEnergy, logSfbFormFactor, sfbNRelevantLines, |
| startSfb, stopSfb); |
| deltaPeNew = deltaPe + deltaScfBits + deltaSpecPe; |
| |
| |
| if (deltaPeNew < 10) { |
| Word32 distOldSum, distNewSum; |
| |
| /* quantize and calc sum of new distortion */ |
| distOldSum = 0; |
| distNewSum = 0; |
| for (sfb=startSfb; sfb<stopSfb; sfb++) { |
| |
| if (scfTmp[sfb] != MIN_16) { |
| distOldSum = L_add(distOldSum, sfbDist[sfb]); |
| |
| sfbDistNew[sfb] = calcSfbDist(psyOutChan->mdctSpectrum + |
| psyOutChan->sfbOffsets[sfb], |
| (psyOutChan->sfbOffsets[sfb+1] - psyOutChan->sfbOffsets[sfb]), |
| scfAct); |
| |
| |
| if (sfbDistNew[sfb] > psyOutChan->sfbThreshold[sfb]) { |
| distNewSum = distOldSum << 1; |
| break; |
| } |
| distNewSum = L_add(distNewSum, sfbDistNew[sfb]); |
| } |
| } |
| |
| if (distNewSum < distOldSum) { |
| deltaPe = deltaPeNew; |
| for (sfb=startSfb; sfb<stopSfb; sfb++) { |
| |
| if (scf[sfb]!=MIN_16) { |
| scf[sfb] = scfAct; |
| sfbDist[sfb] = sfbDistNew[sfb]; |
| } |
| } |
| } |
| } |
| } |
| } while (stopSfb <= sfbCnt); |
| } while (scfAct > scfMin); |
| } |
| } |
| |
| /********************************************************************************* |
| * |
| * function name: EstimateScaleFactorsChannel |
| * description: estimate scale factors for one channel |
| * |
| **********************************************************************************/ |
| static void |
| EstimateScaleFactorsChannel(PSY_OUT_CHANNEL *psyOutChan, |
| Word16 *scf, |
| Word16 *globalGain, |
| Word16 *logSfbEnergy, |
| Word16 *logSfbFormFactor, |
| Word16 *sfbNRelevantLines) |
| { |
| Word32 i, j; |
| Word32 thresh, energy; |
| Word32 energyPart, thresholdPart; |
| Word32 scfInt, minScf, maxScf, maxAllowedScf, lastSf; |
| Word32 maxSpec; |
| Word32 *sfbDist = psyOutChan->sfbDist; |
| Word16 *minSfMaxQuant = psyOutChan->minSfMaxQuant; |
| Word16 *minScfCalculated = psyOutChan->minScfCalculated; |
| |
| |
| for (i=0; i<psyOutChan->sfbCnt; i++) { |
| Word32 sbfwith, sbfStart; |
| Word32 *mdctSpec; |
| thresh = psyOutChan->sfbThreshold[i]; |
| energy = psyOutChan->sfbEnergy[i]; |
| |
| sbfStart = psyOutChan->sfbOffsets[i]; |
| sbfwith = psyOutChan->sfbOffsets[i+1] - sbfStart; |
| mdctSpec = psyOutChan->mdctSpectrum+sbfStart; |
| |
| maxSpec = 0; |
| /* maximum of spectrum */ |
| for (j=sbfwith; j; j-- ) { |
| Word32 absSpec = L_abs(*mdctSpec); mdctSpec++; |
| maxSpec |= absSpec; |
| } |
| |
| /* scfs without energy or with thresh>energy are marked with MIN_16 */ |
| scf[i] = MIN_16; |
| minSfMaxQuant[i] = MIN_16; |
| |
| if ((maxSpec > 0) && (energy > thresh)) { |
| |
| energyPart = logSfbFormFactor[i]; |
| thresholdPart = iLog4(thresh); |
| /* -20 = 4*log2(6.75) - 32 */ |
| scfInt = ((thresholdPart - energyPart - 20) * SCALE_ESTIMATE_COEF) >> 15; |
| |
| minSfMaxQuant[i] = iLog4(maxSpec) - 68; /* 68 -16/3*log(MAX_QUANT+0.5-logCon)/log(2) + 1 */ |
| |
| |
| if (minSfMaxQuant[i] > scfInt) { |
| scfInt = minSfMaxQuant[i]; |
| } |
| |
| /* find better scalefactor with analysis by synthesis */ |
| scfInt = improveScf(psyOutChan->mdctSpectrum+sbfStart, |
| sbfwith, |
| thresh, scfInt, minSfMaxQuant[i], |
| &sfbDist[i], &minScfCalculated[i]); |
| |
| scf[i] = scfInt; |
| } |
| } |
| |
| |
| /* scalefactor differece reduction */ |
| { |
| Word16 sfbConstPePart[MAX_GROUPED_SFB]; |
| for(i=0;i<psyOutChan->sfbCnt;i++) { |
| sfbConstPePart[i] = MIN_16; |
| } |
| |
| assimilateSingleScf(psyOutChan, scf, |
| minSfMaxQuant, sfbDist, sfbConstPePart, logSfbEnergy, |
| logSfbFormFactor, sfbNRelevantLines, minScfCalculated, 1); |
| |
| assimilateMultipleScf(psyOutChan, scf, |
| minSfMaxQuant, sfbDist, sfbConstPePart, logSfbEnergy, |
| logSfbFormFactor, sfbNRelevantLines); |
| } |
| |
| /* get max scalefac for global gain */ |
| maxScf = MIN_16; |
| minScf = MAX_16; |
| for (i=0; i<psyOutChan->sfbCnt; i++) { |
| |
| if (maxScf < scf[i]) { |
| maxScf = scf[i]; |
| } |
| |
| if ((scf[i] != MIN_16) && (minScf > scf[i])) { |
| minScf = scf[i]; |
| } |
| } |
| /* limit scf delta */ |
| maxAllowedScf = minScf + MAX_SCF_DELTA; |
| for(i=0; i<psyOutChan->sfbCnt; i++) { |
| |
| if ((scf[i] != MIN_16) && (maxAllowedScf < scf[i])) { |
| scf[i] = maxAllowedScf; |
| } |
| } |
| /* new maxScf if any scf has been limited */ |
| |
| if (maxAllowedScf < maxScf) { |
| maxScf = maxAllowedScf; |
| } |
| |
| /* calc loop scalefactors */ |
| |
| if (maxScf > MIN_16) { |
| *globalGain = maxScf; |
| lastSf = 0; |
| |
| for(i=0; i<psyOutChan->sfbCnt; i++) { |
| |
| if (scf[i] == MIN_16) { |
| scf[i] = lastSf; |
| /* set band explicitely to zero */ |
| for (j=psyOutChan->sfbOffsets[i]; j<psyOutChan->sfbOffsets[i+1]; j++) { |
| psyOutChan->mdctSpectrum[j] = 0; |
| } |
| } |
| else { |
| scf[i] = maxScf - scf[i]; |
| lastSf = scf[i]; |
| } |
| } |
| } |
| else{ |
| *globalGain = 0; |
| /* set spectrum explicitely to zero */ |
| for(i=0; i<psyOutChan->sfbCnt; i++) { |
| scf[i] = 0; |
| for (j=psyOutChan->sfbOffsets[i]; j<psyOutChan->sfbOffsets[i+1]; j++) { |
| psyOutChan->mdctSpectrum[j] = 0; |
| } |
| } |
| } |
| } |
| |
| /********************************************************************************* |
| * |
| * function name: CalcFormFactor |
| * description: estimate Form factors for all channel |
| * |
| **********************************************************************************/ |
| void |
| CalcFormFactor(Word16 logSfbFormFactor[MAX_CHANNELS][MAX_GROUPED_SFB], |
| Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB], |
| Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], |
| PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], |
| const Word16 nChannels) |
| { |
| Word16 j; |
| |
| for (j=0; j<nChannels; j++) { |
| CalcFormFactorChannel(logSfbFormFactor[j], sfbNRelevantLines[j], logSfbEnergy[j], &psyOutChannel[j]); |
| } |
| } |
| |
| /********************************************************************************* |
| * |
| * function name: EstimateScaleFactors |
| * description: estimate scale factors for all channel |
| * |
| **********************************************************************************/ |
| void |
| EstimateScaleFactors(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], |
| QC_OUT_CHANNEL qcOutChannel[MAX_CHANNELS], |
| Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB], |
| Word16 logSfbFormFactor[MAX_CHANNELS][MAX_GROUPED_SFB], |
| Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB], |
| const Word16 nChannels) |
| { |
| Word16 j; |
| |
| for (j=0; j<nChannels; j++) { |
| EstimateScaleFactorsChannel(&psyOutChannel[j], |
| qcOutChannel[j].scf, |
| &(qcOutChannel[j].globalGain), |
| logSfbEnergy[j], |
| logSfbFormFactor[j], |
| sfbNRelevantLines[j]); |
| } |
| } |
| |