/* gainQuantization.c Copyright (C) 2011 Belledonne Communications, Grenoble, France Author : Johan Pascal This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "typedef.h" #include "codecParameters.h" #include "basicOperationsMacros.h" #include "utils.h" #include "codebooks.h" #include "gainQuantization.h" void initGainQuantization(bcg729EncoderChannelContextStruct *encoderChannelContext) { /*init previousGainPredictionError to -14 in Q10 */ encoderChannelContext->previousGainPredictionError[0] = -14336; encoderChannelContext->previousGainPredictionError[1] = -14336; encoderChannelContext->previousGainPredictionError[2] = -14336; encoderChannelContext->previousGainPredictionError[3] = -14336; } /*****************************************************************************/ /* gainQuantization : compute quantized adaptative and fixed codebooks gains */ /* spec 3.9 */ /* parameters: */ /* -(i/o) encoderChannelContext : the channel context data */ /* -(i) targetSignal: 40 values in Q0, x in eq63 */ /* -(i) filteredAdaptativeCodebookVector: 40 values in Q0, y in eq63 */ /* -(i) convolvedFixedCodebookVector: 40 values in Q12, z in eq63 */ /* -(i) fixedCodebookVector: 40 values in Q13 */ /* -(i) xy in Q0 on 64 bits term of eq63 computed previously */ /* -(i) yy in Q0 on 64 bits term of eq63 computed previously */ /* -(o) quantizedAdaptativeCodebookGain : in Q14 */ /* -(o) quantizedFixedCodebookGain : in Q1 */ /* -(o) gainCodebookStage1 : GA parameter value (3 bits) */ /* -(o) gainCodebookStage2 : GB parameter value (4 bits) */ /* */ /*****************************************************************************/ void gainQuantization(bcg729EncoderChannelContextStruct *encoderChannelContext, word16_t targetSignal[], word16_t filteredAdaptativeCodebookVector[], word16_t convolvedFixedCodebookVector[], word16_t fixedCodebookVector[], word64_t xy64, word64_t yy64, word16_t *quantizedAdaptativeCodebookGain, word16_t *quantizedFixedCodebookGain, uint16_t *gainCodebookStage1, uint16_t *gainCodebookStage2) { int i,j; word64_t xz64=0, yz64=0, zz64=0; word32_t xy; word32_t yy; word32_t xz; word32_t yz; word32_t zz; uint16_t minNormalization = 31; uint16_t currentNormalization; word32_t bestAdaptativeCodebookGain, bestFixedCodebookGain; word64_t denominator; word16_t predictedFixedCodebookGain; uint16_t indexBaseGa=0; uint16_t indexBaseGb=0; uint16_t indexGa=0, indexGb=0; word64_t distanceMin = MAXINT64; /*** compute spec 3.9 eq63 terms first on 64 bits and then scale them if needed to fit on 32 ***/ /* Xy64 and Yy64 already computed during adaptativeCodebookGain computation */ for (i=0; i= 0)*/ /* avoid division by zero */ if (denominator==0) { /* consider it to be one */ bestAdaptativeCodebookGain = (word32_t)(SHR64(MAC64(MULT32_32(zz, xy), -xz, yz), 15)); /* MAC in Q24 -> Q9 */ bestFixedCodebookGain = (word32_t)(SHR64(MAC64(MULT32_32(yy, xz), -xy, yz), 10)); /* MAC in Q12 -> Q2 */ } else { /* bestAdaptativeCodebookGain in Q9 */ uint16_t numeratorNorm; word64_t numerator = MAC64(MULT32_32(zz, xy), -xz, yz); /* in Q24 */ /* check if we can shift it by 9 without overflow as the bestAdaptativeCodebookGain in computed in Q9 */ word32_t numeratorH = (word32_t)(SHR64(numerator,32)); numeratorH = (numeratorH>0)?numeratorH:-numeratorH; numeratorNorm = countLeadingZeros(numeratorH); if (numeratorNorm >= 9) { bestAdaptativeCodebookGain = (word32_t)(DIV64(SHL64(numerator,9), denominator)); /* bestAdaptativeCodebookGain in Q9 */ } else { word64_t shiftedDenominator = SHR64(denominator, 9-numeratorNorm); if (shiftedDenominator>0) { /* can't shift left by 9 the numerator, can we shift right by 9-numeratorNorm the denominator without hiting 0 */ bestAdaptativeCodebookGain = (word32_t)(DIV64(SHL64(numerator, numeratorNorm),shiftedDenominator)); /* bestAdaptativeCodebookGain in Q9 */ } else { bestAdaptativeCodebookGain = SHL((word32_t)(DIV64(SHL64(numerator, numeratorNorm), denominator)), 9-numeratorNorm); /* shift left the division result to reach Q9 */ } } numerator = MAC64(MULT32_32(yy, xz), -xy, yz); /* in Q12 */ /* check if we can shift it by 14(it's in Q12 and denominator in Q24) without overflow as the bestFixedCodebookGain in computed in Q2 */ numeratorH = (word32_t)(SHR64(numerator,32)); numeratorH = (numeratorH>0)?numeratorH:-numeratorH; numeratorNorm = countLeadingZeros(numeratorH); if (numeratorNorm >= 14) { bestFixedCodebookGain = (word32_t)(DIV64(SHL64(numerator,14), denominator)); } else { word64_t shiftedDenominator = SHR64(denominator, 14-numeratorNorm); /* bestFixedCodebookGain in Q14 */ if (shiftedDenominator>0) { /* can't shift left by 9 the numerator, can we shift right by 9-numeratorNorm the denominator without hiting 0 */ bestFixedCodebookGain = (word32_t)(DIV64(SHL64(numerator, numeratorNorm),shiftedDenominator)); /* bestFixedCodebookGain in Q14 */ } else { bestFixedCodebookGain = SHL((word32_t)(DIV64(SHL64(numerator, numeratorNorm), denominator)), 14-numeratorNorm); /* shift left the division result to reach Q14 */ } } } /*** Compute the predicted gain as in spec 3.9.1 eq71 in Q6 ***/ predictedFixedCodebookGain = (word16_t)(SHR32(MACodeGainPrediction(encoderChannelContext->previousGainPredictionError, fixedCodebookVector), 12)); /* in Q16 -> Q4 range [3,1830] */ /*** preselection spec 3.9.2 ***/ /* Note: spec just says to select the best 50% of each vector, ITU code go through magical constant computation to select the begining of a continuous range */ /* much more simple here : vector are ordened in growing order so just select 2 (4 for Gb) indexes before the first value to be superior to the best gain previously computed */ while (indexBaseGa<6 && bestFixedCodebookGain>(MULT16_16_Q14(GACodebook[indexBaseGa][1],predictedFixedCodebookGain))) { /* bestFixedCodebookGain> in Q2, GACodebook in Q12 *predictedFixedCodebookGain in Q4 -> Q16-14 */ indexBaseGa++; } if (indexBaseGa>0) indexBaseGa--; if (indexBaseGa>0) indexBaseGa--; while (indexBaseGb<12 && bestAdaptativeCodebookGain>(SHR(GBCodebook[indexBaseGb][0],5))) { indexBaseGb++; } if (indexBaseGb>0) indexBaseGb--; if (indexBaseGb>0) indexBaseGb--; if (indexBaseGb>0) indexBaseGb--; if (indexBaseGb>0) indexBaseGb--; /*** test all possibilities of Ga and Gb indexes and select the best one ***/ xy = -SHL(xy,1); /* xy term is always used with a -2 factor */ xz = -SHL(xz,1); /* xz term is always used with a -2 factor */ yz = SHL(yz,1); /* yz term is always used with a 2 factor */ for (i=0; i<4; i++) { for (j=0; j<8; j++) { /* compute gamma->gc and gp */ word16_t gp = ADD16(GACodebook[i+indexBaseGa][0], GBCodebook[j+indexBaseGb][0]); /* result in Q14 */ word16_t gamma = ADD16(GACodebook[i+indexBaseGa][1], GBCodebook[j+indexBaseGb][1]); /* result in Q3.12 (range [0.185, 5.05])*/ word32_t gc = MULT16_16_Q14(gamma, predictedFixedCodebookGain); /* gamma in Q12, predictedFixedCodebookGain in Q4 -> Q16 -14 -> Q2 */ /* compute E as in eq63 (first term excluded) */ word64_t acc = MULT32_32(MULT16_16(gp, gp), yy); /* acc = gp^2*yy gp in Q14, yy in Q0 -> acc in Q28 */ acc = MAC64(acc, MULT16_16(gc, gc), zz); /* gc in Q2, zz in Q24 -> acc in Q28, note gc is on 32 bits but in a range making gc^2 fitting on 32 bits */ acc = MAC64(acc, SHL32((word32_t)gp, 14), xy); /* gp in Q14 shifted to Q28, xy in Q0 -> acc in Q28 */ acc = MAC64(acc, SHL32(gc, 14), xz); /* gc in Q2 shifted to Q16, xz in Q12 -> acc in Q28 */ acc = MAC64(acc, MULT16_16(gp,gc), yz); /* gp in Q14, gc in Q2 yz in Q12 -> acc in Q28 */ if (accpreviousGainPredictionError); /* mapping of indexes */ *gainCodebookStage1 = indexMappingGA[indexGa]; *gainCodebookStage2 = indexMappingGB[indexGb]; return; }