| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| /* |
| * entropy_coding.c |
| * |
| * This file contains all functions used to arithmetically |
| * encode the iSAC bistream. |
| * |
| */ |
| |
| #include <stddef.h> |
| |
| #include "arith_routins.h" |
| #include "spectrum_ar_model_tables.h" |
| #include "pitch_gain_tables.h" |
| #include "pitch_lag_tables.h" |
| #include "entropy_coding.h" |
| #include "lpc_tables.h" |
| #include "settings.h" |
| #include "signal_processing_library.h" |
| |
| |
| /* |
| This function implements the fix-point correspondant function to lrint. |
| |
| FLP: (WebRtc_Word32)floor(flt+.499999999999) |
| FIP: (fixVal+roundVal)>>qDomain |
| |
| where roundVal = 2^(qDomain-1) = 1<<(qDomain-1) |
| |
| */ |
| static __inline WebRtc_Word32 CalcLrIntQ(WebRtc_Word32 fixVal, WebRtc_Word16 qDomain) { |
| WebRtc_Word32 intgr; |
| WebRtc_Word32 roundVal; |
| |
| roundVal = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, qDomain-1); |
| intgr = WEBRTC_SPL_RSHIFT_W32(fixVal+roundVal, qDomain); |
| |
| return intgr; |
| } |
| |
| /* |
| __inline WebRtc_UWord32 stepwise(WebRtc_Word32 dinQ10) { |
| |
| WebRtc_Word32 ind, diQ10, dtQ10; |
| |
| diQ10 = dinQ10; |
| if (diQ10 < DPMIN_Q10) |
| diQ10 = DPMIN_Q10; |
| if (diQ10 >= DPMAX_Q10) |
| diQ10 = DPMAX_Q10 - 1; |
| |
| dtQ10 = diQ10 - DPMIN_Q10;*/ /* Q10 + Q10 = Q10 */ |
| /* ind = (dtQ10 * 5) >> 10; */ /* 2^10 / 5 = 0.2 in Q10 */ |
| /* Q10 -> Q0 */ |
| |
| /* return rpointsFIX_Q10[ind]; |
| |
| } |
| */ |
| |
| /* logN(x) = logN(2)*log2(x) = 0.6931*log2(x). Output in Q8. */ |
| /* The input argument X to logN(X) is 2^17 times higher than the |
| input floating point argument Y to log(Y), since the X value |
| is a Q17 value. This can be compensated for after the call, by |
| subraction a value Z for each Q-step. One Q-step means that |
| X gets 2 thimes higher, i.e. Z = logN(2)*256 = 0.693147180559*256 = |
| 177.445678 should be subtracted (since logN() returns a Q8 value). |
| For a X value in Q17, the value 177.445678*17 = 3017 should be |
| subtracted */ |
| static WebRtc_Word16 CalcLogN(WebRtc_Word32 arg) { |
| WebRtc_Word16 zeros, log2, frac, logN; |
| |
| zeros=WebRtcSpl_NormU32(arg); |
| frac=(WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_LSHIFT_W32(arg, zeros)&0x7FFFFFFF, 23); |
| log2=(WebRtc_Word16)(WEBRTC_SPL_LSHIFT_W32(31-zeros, 8)+frac); // log2(x) in Q8 |
| logN=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(log2,22713,15); //Q8*Q15 log(2) = 0.693147 = 22713 in Q15 |
| logN=logN+11; //Scalar compensation which minimizes the (log(x)-logN(x))^2 error over all x. |
| |
| return logN; |
| } |
| |
| |
| /* |
| expN(x) = 2^(a*x), where a = log2(e) ~= 1.442695 |
| |
| Input: Q8 (WebRtc_Word16) |
| Output: Q17 (WebRtc_Word32) |
| |
| a = log2(e) = log2(exp(1)) ~= 1.442695 ==> a = 23637 in Q14 (1.442688) |
| To this value, 700 is added or subtracted in order to get an average error |
| nearer zero, instead of always same-sign. |
| */ |
| |
| static WebRtc_Word32 CalcExpN(WebRtc_Word16 x) { |
| WebRtc_Word16 ax, axINT, axFRAC; |
| WebRtc_Word16 exp16; |
| WebRtc_Word32 exp; |
| |
| if (x>=0) { |
| // ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637-700, 14); //Q8 |
| ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637, 14); //Q8 |
| axINT = WEBRTC_SPL_RSHIFT_W16(ax, 8); //Q0 |
| axFRAC = ax&0x00FF; |
| exp16 = WEBRTC_SPL_LSHIFT_W32(1, axINT); //Q0 |
| axFRAC = axFRAC+256; //Q8 |
| exp = WEBRTC_SPL_MUL_16_16(exp16, axFRAC); // Q0*Q8 = Q8 |
| exp = WEBRTC_SPL_LSHIFT_W32(exp, 9); //Q17 |
| } else { |
| // ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637+700, 14); //Q8 |
| ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637, 14); //Q8 |
| ax = -ax; |
| axINT = 1 + WEBRTC_SPL_RSHIFT_W16(ax, 8); //Q0 |
| axFRAC = 0x00FF - (ax&0x00FF); |
| exp16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(32768, axINT); //Q15 |
| axFRAC = axFRAC+256; //Q8 |
| exp = WEBRTC_SPL_MUL_16_16(exp16, axFRAC); // Q15*Q8 = Q23 |
| exp = WEBRTC_SPL_RSHIFT_W32(exp, 6); //Q17 |
| } |
| |
| return exp; |
| } |
| |
| |
| /* compute correlation from power spectrum */ |
| static void CalcCorrelation(WebRtc_Word32 *PSpecQ12, WebRtc_Word32 *CorrQ7) |
| { |
| WebRtc_Word32 summ[FRAMESAMPLES/8]; |
| WebRtc_Word32 diff[FRAMESAMPLES/8]; |
| WebRtc_Word32 sum; |
| int k, n; |
| |
| for (k = 0; k < FRAMESAMPLES/8; k++) { |
| summ[k] = WEBRTC_SPL_RSHIFT_W32(PSpecQ12[k] + PSpecQ12[FRAMESAMPLES/4-1 - k] + 16, 5); |
| diff[k] = WEBRTC_SPL_RSHIFT_W32(PSpecQ12[k] - PSpecQ12[FRAMESAMPLES/4-1 - k] + 16, 5); |
| } |
| |
| sum = 2; |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| sum += summ[n]; |
| CorrQ7[0] = sum; |
| |
| for (k = 0; k < AR_ORDER; k += 2) { |
| sum = 0; |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| sum += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], diff[n]) + 256, 9); |
| CorrQ7[k+1] = sum; |
| } |
| |
| for (k=1; k<AR_ORDER; k+=2) { |
| sum = 0; |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| sum += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], summ[n]) + 256, 9); |
| CorrQ7[k+1] = sum; |
| } |
| } |
| |
| |
| /* compute inverse AR power spectrum */ |
| static void CalcInvArSpec(const WebRtc_Word16 *ARCoefQ12, |
| const WebRtc_Word32 gainQ10, |
| WebRtc_Word32 *CurveQ16) |
| { |
| WebRtc_Word32 CorrQ11[AR_ORDER+1]; |
| WebRtc_Word32 sum, tmpGain; |
| WebRtc_Word32 diffQ16[FRAMESAMPLES/8]; |
| const WebRtc_Word16 *CS_ptrQ9; |
| int k, n; |
| WebRtc_Word16 round, shftVal = 0, sh; |
| |
| sum = 0; |
| for (n = 0; n < AR_ORDER+1; n++) |
| sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]); /* Q24 */ |
| sum = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(sum, 6), 65) + 32768, 16); /* result in Q8 */ |
| CorrQ11[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, gainQ10) + 256, 9); |
| |
| /* To avoid overflow, we shift down gainQ10 if it is large. We will not lose any precision */ |
| if(gainQ10>400000){ |
| tmpGain = WEBRTC_SPL_RSHIFT_W32(gainQ10, 3); |
| round = 32; |
| shftVal = 6; |
| } else { |
| tmpGain = gainQ10; |
| round = 256; |
| shftVal = 9; |
| } |
| |
| for (k = 1; k < AR_ORDER+1; k++) { |
| sum = 16384; |
| for (n = k; n < AR_ORDER+1; n++) |
| sum += WEBRTC_SPL_MUL(ARCoefQ12[n-k], ARCoefQ12[n]); /* Q24 */ |
| sum = WEBRTC_SPL_RSHIFT_W32(sum, 15); |
| CorrQ11[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, tmpGain) + round, shftVal); |
| } |
| sum = WEBRTC_SPL_LSHIFT_W32(CorrQ11[0], 7); |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| CurveQ16[n] = sum; |
| |
| for (k = 1; k < AR_ORDER; k += 2) { |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| CurveQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], CorrQ11[k+1]) + 2, 2); |
| } |
| |
| CS_ptrQ9 = WebRtcIsacfix_kCos[0]; |
| |
| /* If CorrQ11[1] too large we avoid getting overflow in the calculation by shifting */ |
| sh=WebRtcSpl_NormW32(CorrQ11[1]); |
| if (CorrQ11[1]==0) /* Use next correlation */ |
| sh=WebRtcSpl_NormW32(CorrQ11[2]); |
| |
| if (sh<9) |
| shftVal = 9 - sh; |
| else |
| shftVal = 0; |
| |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| diffQ16[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[1], shftVal)) + 2, 2); |
| for (k = 2; k < AR_ORDER; k += 2) { |
| CS_ptrQ9 = WebRtcIsacfix_kCos[k]; |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| diffQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[k+1], shftVal)) + 2, 2); |
| } |
| |
| for (k=0; k<FRAMESAMPLES/8; k++) { |
| CurveQ16[FRAMESAMPLES/4-1 - k] = CurveQ16[k] - WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal); |
| CurveQ16[k] += WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal); |
| } |
| } |
| |
| static void CalcRootInvArSpec(const WebRtc_Word16 *ARCoefQ12, |
| const WebRtc_Word32 gainQ10, |
| WebRtc_UWord16 *CurveQ8) |
| { |
| WebRtc_Word32 CorrQ11[AR_ORDER+1]; |
| WebRtc_Word32 sum, tmpGain; |
| WebRtc_Word32 summQ16[FRAMESAMPLES/8]; |
| WebRtc_Word32 diffQ16[FRAMESAMPLES/8]; |
| |
| const WebRtc_Word16 *CS_ptrQ9; |
| int k, n, i; |
| WebRtc_Word16 round, shftVal = 0, sh; |
| WebRtc_Word32 res, in_sqrt, newRes; |
| |
| sum = 0; |
| for (n = 0; n < AR_ORDER+1; n++) |
| sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]); /* Q24 */ |
| sum = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(sum, 6), 65) + 32768, 16); /* result in Q8 */ |
| CorrQ11[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, gainQ10) + 256, 9); |
| |
| /* To avoid overflow, we shift down gainQ10 if it is large. We will not lose any precision */ |
| if(gainQ10>400000){ |
| tmpGain = WEBRTC_SPL_RSHIFT_W32(gainQ10, 3); |
| round = 32; |
| shftVal = 6; |
| } else { |
| tmpGain = gainQ10; |
| round = 256; |
| shftVal = 9; |
| } |
| |
| for (k = 1; k < AR_ORDER+1; k++) { |
| sum = 16384; |
| for (n = k; n < AR_ORDER+1; n++) |
| sum += WEBRTC_SPL_MUL(ARCoefQ12[n-k], ARCoefQ12[n]); /* Q24 */ |
| sum = WEBRTC_SPL_RSHIFT_W32(sum, 15); |
| CorrQ11[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, tmpGain) + round, shftVal); |
| } |
| sum = WEBRTC_SPL_LSHIFT_W32(CorrQ11[0], 7); |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| summQ16[n] = sum; |
| |
| for (k = 1; k < (AR_ORDER); k += 2) { |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| summQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(CorrQ11[k+1],WebRtcIsacfix_kCos[k][n]) + 2, 2); |
| } |
| |
| CS_ptrQ9 = WebRtcIsacfix_kCos[0]; |
| |
| /* If CorrQ11[1] too large we avoid getting overflow in the calculation by shifting */ |
| sh=WebRtcSpl_NormW32(CorrQ11[1]); |
| if (CorrQ11[1]==0) /* Use next correlation */ |
| sh=WebRtcSpl_NormW32(CorrQ11[2]); |
| |
| if (sh<9) |
| shftVal = 9 - sh; |
| else |
| shftVal = 0; |
| |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| diffQ16[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[1], shftVal)) + 2, 2); |
| for (k = 2; k < AR_ORDER; k += 2) { |
| CS_ptrQ9 = WebRtcIsacfix_kCos[k]; |
| for (n = 0; n < FRAMESAMPLES/8; n++) |
| diffQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[k+1], shftVal)) + 2, 2); |
| } |
| |
| in_sqrt = summQ16[0] + WEBRTC_SPL_LSHIFT_W32(diffQ16[0], shftVal); |
| |
| /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB) */ |
| res = WEBRTC_SPL_LSHIFT_W32(1, WEBRTC_SPL_RSHIFT_W16(WebRtcSpl_GetSizeInBits(in_sqrt), 1)); |
| |
| for (k = 0; k < FRAMESAMPLES/8; k++) |
| { |
| in_sqrt = summQ16[k] + WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal); |
| i = 10; |
| |
| /* make in_sqrt positive to prohibit sqrt of negative values */ |
| if(in_sqrt<0) |
| in_sqrt=-in_sqrt; |
| |
| newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1); |
| do |
| { |
| res = newRes; |
| newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1); |
| } while (newRes != res && i-- > 0); |
| |
| CurveQ8[k] = (WebRtc_Word16)newRes; |
| } |
| for (k = FRAMESAMPLES/8; k < FRAMESAMPLES/4; k++) { |
| |
| in_sqrt = summQ16[FRAMESAMPLES/4-1 - k] - WEBRTC_SPL_LSHIFT_W32(diffQ16[FRAMESAMPLES/4-1 - k], shftVal); |
| i = 10; |
| |
| /* make in_sqrt positive to prohibit sqrt of negative values */ |
| if(in_sqrt<0) |
| in_sqrt=-in_sqrt; |
| |
| newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1); |
| do |
| { |
| res = newRes; |
| newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1); |
| } while (newRes != res && i-- > 0); |
| |
| CurveQ8[k] = (WebRtc_Word16)newRes; |
| } |
| |
| } |
| |
| |
| |
| /* generate array of dither samples in Q7 */ |
| static void GenerateDitherQ7(WebRtc_Word16 *bufQ7, |
| WebRtc_UWord32 seed, |
| WebRtc_Word16 length, |
| WebRtc_Word16 AvgPitchGain_Q12) |
| { |
| int k; |
| WebRtc_Word16 dither1_Q7, dither2_Q7, dither_gain_Q14, shft; |
| |
| if (AvgPitchGain_Q12 < 614) /* this threshold should be equal to that in decode_spec() */ |
| { |
| for (k = 0; k < length-2; k += 3) |
| { |
| /* new random unsigned WebRtc_Word32 */ |
| seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515; |
| |
| /* fixed-point dither sample between -64 and 64 (Q7) */ |
| dither1_Q7 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)seed + 16777216, 25); // * 128/4294967295 |
| |
| /* new random unsigned WebRtc_Word32 */ |
| seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515; |
| |
| /* fixed-point dither sample between -64 and 64 */ |
| dither2_Q7 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(seed + 16777216, 25); |
| |
| shft = (WebRtc_Word16)(WEBRTC_SPL_RSHIFT_U32(seed, 25) & 15); |
| if (shft < 5) |
| { |
| bufQ7[k] = dither1_Q7; |
| bufQ7[k+1] = dither2_Q7; |
| bufQ7[k+2] = 0; |
| } |
| else if (shft < 10) |
| { |
| bufQ7[k] = dither1_Q7; |
| bufQ7[k+1] = 0; |
| bufQ7[k+2] = dither2_Q7; |
| } |
| else |
| { |
| bufQ7[k] = 0; |
| bufQ7[k+1] = dither1_Q7; |
| bufQ7[k+2] = dither2_Q7; |
| } |
| } |
| } |
| else |
| { |
| dither_gain_Q14 = (WebRtc_Word16)(22528 - WEBRTC_SPL_MUL(10, AvgPitchGain_Q12)); |
| |
| /* dither on half of the coefficients */ |
| for (k = 0; k < length-1; k += 2) |
| { |
| /* new random unsigned WebRtc_Word32 */ |
| seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515; |
| |
| /* fixed-point dither sample between -64 and 64 */ |
| dither1_Q7 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)seed + 16777216, 25); |
| |
| /* dither sample is placed in either even or odd index */ |
| shft = (WebRtc_Word16)(WEBRTC_SPL_RSHIFT_U32(seed, 25) & 1); /* either 0 or 1 */ |
| |
| bufQ7[k + shft] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(dither_gain_Q14, dither1_Q7) + 8192, 14); |
| bufQ7[k + 1 - shft] = 0; |
| } |
| } |
| } |
| |
| |
| |
| |
| /* |
| * function to decode the complex spectrum from the bitstream |
| * returns the total number of bytes in the stream |
| */ |
| WebRtc_Word16 WebRtcIsacfix_DecodeSpec(Bitstr_dec *streamdata, |
| WebRtc_Word16 *frQ7, |
| WebRtc_Word16 *fiQ7, |
| WebRtc_Word16 AvgPitchGain_Q12) |
| { |
| WebRtc_Word16 data[FRAMESAMPLES]; |
| WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES/4]; |
| WebRtc_Word16 ARCoefQ12[AR_ORDER+1]; |
| WebRtc_Word16 RCQ15[AR_ORDER]; |
| WebRtc_Word16 gainQ10; |
| WebRtc_Word32 gain2_Q10; |
| WebRtc_Word16 len; |
| int k; |
| |
| /* create dither signal */ |
| GenerateDitherQ7(data, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12); /* Dither is output in vector 'Data' */ |
| |
| /* decode model parameters */ |
| if (WebRtcIsacfix_DecodeRcCoef(streamdata, RCQ15) < 0) |
| return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; |
| |
| |
| WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); |
| |
| if (WebRtcIsacfix_DecodeGain2(streamdata, &gain2_Q10) < 0) |
| return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; |
| |
| /* compute inverse AR power spectrum */ |
| CalcInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); |
| |
| /* arithmetic decoding of spectrum */ |
| /* 'data' input and output. Input = Dither */ |
| len = WebRtcIsacfix_DecLogisticMulti2(data, streamdata, invARSpec2_Q16, (WebRtc_Word16)FRAMESAMPLES); |
| |
| if (len<1) |
| return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; |
| |
| /* subtract dither and scale down spectral samples with low SNR */ |
| if (AvgPitchGain_Q12 <= 614) |
| { |
| for (k = 0; k < FRAMESAMPLES; k += 4) |
| { |
| gainQ10 = WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)30, 10), |
| (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(invARSpec2_Q16[k>>2] + (WebRtc_UWord32)2195456, 16)); |
| *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[ k ], gainQ10) + 512, 10); |
| *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+1], gainQ10) + 512, 10); |
| *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+2], gainQ10) + 512, 10); |
| *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+3], gainQ10) + 512, 10); |
| } |
| } |
| else |
| { |
| for (k = 0; k < FRAMESAMPLES; k += 4) |
| { |
| gainQ10 = WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)36, 10), |
| (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(invARSpec2_Q16[k>>2] + (WebRtc_UWord32)2654208, 16)); |
| *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[ k ], gainQ10) + 512, 10); |
| *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+1], gainQ10) + 512, 10); |
| *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+2], gainQ10) + 512, 10); |
| *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+3], gainQ10) + 512, 10); |
| } |
| } |
| |
| return len; |
| } |
| |
| |
| int WebRtcIsacfix_EncodeSpec(const WebRtc_Word16 *fr, |
| const WebRtc_Word16 *fi, |
| Bitstr_enc *streamdata, |
| WebRtc_Word16 AvgPitchGain_Q12) |
| { |
| WebRtc_Word16 dataQ7[FRAMESAMPLES]; |
| WebRtc_Word32 PSpec[FRAMESAMPLES/4]; |
| WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES/4]; |
| WebRtc_Word32 CorrQ7[AR_ORDER+1]; |
| WebRtc_Word32 CorrQ7_norm[AR_ORDER+1]; |
| WebRtc_Word16 RCQ15[AR_ORDER]; |
| WebRtc_Word16 ARCoefQ12[AR_ORDER+1]; |
| WebRtc_Word32 gain2_Q10; |
| WebRtc_Word16 val; |
| WebRtc_Word32 nrg; |
| WebRtc_UWord32 sum; |
| WebRtc_Word16 lft_shft; |
| WebRtc_Word16 status; |
| int k, n, j; |
| |
| |
| /* create dither_float signal */ |
| GenerateDitherQ7(dataQ7, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12); |
| |
| /* add dither and quantize, and compute power spectrum */ |
| /* Vector dataQ7 contains Dither in Q7 */ |
| for (k = 0; k < FRAMESAMPLES; k += 4) |
| { |
| val = ((*fr++ + dataQ7[k] + 64) & 0xFF80) - dataQ7[k]; /* Data = Dither */ |
| dataQ7[k] = val; /* New value in Data */ |
| sum = WEBRTC_SPL_UMUL(val, val); |
| |
| val = ((*fi++ + dataQ7[k+1] + 64) & 0xFF80) - dataQ7[k+1]; /* Data = Dither */ |
| dataQ7[k+1] = val; /* New value in Data */ |
| sum += WEBRTC_SPL_UMUL(val, val); |
| |
| val = ((*fr++ + dataQ7[k+2] + 64) & 0xFF80) - dataQ7[k+2]; /* Data = Dither */ |
| dataQ7[k+2] = val; /* New value in Data */ |
| sum += WEBRTC_SPL_UMUL(val, val); |
| |
| val = ((*fi++ + dataQ7[k+3] + 64) & 0xFF80) - dataQ7[k+3]; /* Data = Dither */ |
| dataQ7[k+3] = val; /* New value in Data */ |
| sum += WEBRTC_SPL_UMUL(val, val); |
| |
| PSpec[k>>2] = WEBRTC_SPL_RSHIFT_U32(sum, 2); |
| } |
| |
| /* compute correlation from power spectrum */ |
| CalcCorrelation(PSpec, CorrQ7); |
| |
| |
| /* find AR coefficients */ |
| /* number of bit shifts to 14-bit normalize CorrQ7[0] (leaving room for sign) */ |
| lft_shft = WebRtcSpl_NormW32(CorrQ7[0]) - 18; |
| |
| if (lft_shft > 0) { |
| for (k=0; k<AR_ORDER+1; k++) |
| CorrQ7_norm[k] = WEBRTC_SPL_LSHIFT_W32(CorrQ7[k], lft_shft); |
| } else { |
| for (k=0; k<AR_ORDER+1; k++) |
| CorrQ7_norm[k] = WEBRTC_SPL_RSHIFT_W32(CorrQ7[k], -lft_shft); |
| } |
| |
| /* find RC coefficients */ |
| WebRtcSpl_AutoCorrToReflCoef(CorrQ7_norm, AR_ORDER, RCQ15); |
| |
| /* quantize & code RC Coef */ |
| status = WebRtcIsacfix_EncodeRcCoef(RCQ15, streamdata); |
| if (status < 0) { |
| return status; |
| } |
| |
| /* RC -> AR coefficients */ |
| WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); |
| |
| /* compute ARCoef' * Corr * ARCoef in Q19 */ |
| nrg = 0; |
| for (j = 0; j <= AR_ORDER; j++) { |
| for (n = 0; n <= j; n++) |
| nrg += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(ARCoefQ12[j], WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CorrQ7_norm[j-n], ARCoefQ12[n]) + 256, 9)) + 4, 3); |
| for (n = j+1; n <= AR_ORDER; n++) |
| nrg += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(ARCoefQ12[j], WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CorrQ7_norm[n-j], ARCoefQ12[n]) + 256, 9)) + 4, 3); |
| } |
| |
| if (lft_shft > 0) |
| nrg = WEBRTC_SPL_RSHIFT_W32(nrg, lft_shft); |
| else |
| nrg = WEBRTC_SPL_LSHIFT_W32(nrg, -lft_shft); |
| |
| if(nrg>131072) |
| gain2_Q10 = WebRtcSpl_DivResultInQ31(FRAMESAMPLES >> 2, nrg); /* also shifts 31 bits to the left! */ |
| else |
| gain2_Q10 = WEBRTC_SPL_RSHIFT_W32(FRAMESAMPLES, 2); |
| |
| /* quantize & code gain2_Q10 */ |
| if (WebRtcIsacfix_EncodeGain2(&gain2_Q10, streamdata)) |
| return -1; |
| |
| /* compute inverse AR magnitude spectrum */ |
| CalcRootInvArSpec(ARCoefQ12, gain2_Q10, invARSpecQ8); |
| |
| |
| /* arithmetic coding of spectrum */ |
| status = WebRtcIsacfix_EncLogisticMulti2(streamdata, dataQ7, invARSpecQ8, (WebRtc_Word16)FRAMESAMPLES); |
| if ( status ) |
| return( status ); |
| |
| return 0; |
| } |
| |
| |
| /* Matlab's LAR definition */ |
| static void Rc2LarFix(const WebRtc_Word16 *rcQ15, WebRtc_Word32 *larQ17, WebRtc_Word16 order) { |
| |
| /* |
| |
| This is a piece-wise implemenetation of a rc2lar-function (all values in the comment |
| are Q15 values and are based on [0 24956/32768 30000/32768 32500/32768], i.e. |
| [0.76159667968750 0.91552734375000 0.99182128906250] |
| |
| x0 x1 a k x0(again) b |
| ================================================================================== |
| 0.00 0.76: 0 2.625997508581 0 0 |
| 0.76 0.91: 2.000012018559 7.284502668663 0.761596679688 -3.547841027073 |
| 0.91 0.99: 3.121320351712 31.115835041229 0.915527343750 -25.366077452148 |
| 0.99 1.00: 5.495270168700 686.663805654056 0.991821289063 -675.552510708011 |
| |
| The implementation is y(x)= a + (x-x0)*k, but this can be simplified to |
| |
| y(x) = a-x0*k + x*k = b + x*k, where b = a-x0*k |
| |
| akx=[0 2.625997508581 0 |
| 2.000012018559 7.284502668663 0.761596679688 |
| 3.121320351712 31.115835041229 0.915527343750 |
| 5.495270168700 686.663805654056 0.991821289063]; |
| |
| b = akx(:,1) - akx(:,3).*akx(:,2) |
| |
| [ 0.0 |
| -3.547841027073 |
| -25.366077452148 |
| -675.552510708011] |
| |
| */ |
| |
| int k; |
| WebRtc_Word16 rc; |
| WebRtc_Word32 larAbsQ17; |
| |
| for (k = 0; k < order; k++) { |
| |
| rc = WEBRTC_SPL_ABS_W16(rcQ15[k]); //Q15 |
| |
| /* Calculate larAbsQ17 in Q17 from rc in Q15 */ |
| |
| if (rc<24956) { //0.7615966 in Q15 |
| // (Q15*Q13)>>11 = Q17 |
| larAbsQ17 = WEBRTC_SPL_MUL_16_16_RSFT(rc, 21512, 11); |
| } else if (rc<30000) { //0.91552734375 in Q15 |
| // Q17 + (Q15*Q12)>>10 = Q17 |
| larAbsQ17 = -465024 + WEBRTC_SPL_MUL_16_16_RSFT(rc, 29837, 10); |
| } else if (rc<32500) { //0.99182128906250 in Q15 |
| // Q17 + (Q15*Q10)>>8 = Q17 |
| larAbsQ17 = -3324784 + WEBRTC_SPL_MUL_16_16_RSFT(rc, 31863, 8); |
| } else { |
| // Q17 + (Q15*Q5)>>3 = Q17 |
| larAbsQ17 = -88546020 + WEBRTC_SPL_MUL_16_16_RSFT(rc, 21973, 3); |
| } |
| |
| if (rcQ15[k]>0) { |
| larQ17[k] = larAbsQ17; |
| } else { |
| larQ17[k] = -larAbsQ17; |
| } |
| } |
| } |
| |
| |
| static void Lar2RcFix(const WebRtc_Word32 *larQ17, WebRtc_Word16 *rcQ15, WebRtc_Word16 order) { |
| |
| /* |
| This is a piece-wise implemenetation of a lar2rc-function |
| See comment in Rc2LarFix() about details. |
| */ |
| |
| int k; |
| WebRtc_Word16 larAbsQ11; |
| WebRtc_Word32 rc; |
| |
| for (k = 0; k < order; k++) { |
| |
| larAbsQ11 = (WebRtc_Word16) WEBRTC_SPL_ABS_W32(WEBRTC_SPL_RSHIFT_W32(larQ17[k]+32,6)); //Q11 |
| |
| if (larAbsQ11<4097) { //2.000012018559 in Q11 |
| // Q11*Q16>>12 = Q15 |
| rc = WEBRTC_SPL_MUL_16_16_RSFT(larAbsQ11, 24957, 12); |
| } else if (larAbsQ11<6393) { //3.121320351712 in Q11 |
| // (Q11*Q17 + Q13)>>13 = Q15 |
| rc = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(larAbsQ11, 17993) + 130738688), 13); |
| } else if (larAbsQ11<11255) { //5.495270168700 in Q11 |
| // (Q11*Q19 + Q30)>>15 = Q15 |
| rc = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(larAbsQ11, 16850) + 875329820), 15); |
| } else { |
| // (Q11*Q24>>16 + Q19)>>4 = Q15 |
| rc = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16_RSFT(larAbsQ11, 24433, 16)) + 515804), 4); |
| } |
| |
| if (larQ17[k]<=0) { |
| rc = -rc; |
| } |
| |
| rcQ15[k] = (WebRtc_Word16) rc; // Q15 |
| } |
| } |
| |
| static void Poly2LarFix(WebRtc_Word16 *lowbandQ15, |
| WebRtc_Word16 orderLo, |
| WebRtc_Word16 *hibandQ15, |
| WebRtc_Word16 orderHi, |
| WebRtc_Word16 Nsub, |
| WebRtc_Word32 *larsQ17) { |
| |
| int k, n; |
| WebRtc_Word32 *outpQ17; |
| WebRtc_Word16 orderTot; |
| WebRtc_Word32 larQ17[MAX_ORDER]; // Size 7+6 is enough |
| |
| orderTot = (orderLo + orderHi); |
| outpQ17 = larsQ17; |
| for (k = 0; k < Nsub; k++) { |
| |
| Rc2LarFix(lowbandQ15, larQ17, orderLo); |
| |
| for (n = 0; n < orderLo; n++) |
| outpQ17[n] = larQ17[n]; //Q17 |
| |
| Rc2LarFix(hibandQ15, larQ17, orderHi); |
| |
| for (n = 0; n < orderHi; n++) |
| outpQ17[n + orderLo] = larQ17[n]; //Q17; |
| |
| outpQ17 += orderTot; |
| lowbandQ15 += orderLo; |
| hibandQ15 += orderHi; |
| } |
| } |
| |
| |
| static void Lar2polyFix(WebRtc_Word32 *larsQ17, |
| WebRtc_Word16 *lowbandQ15, |
| WebRtc_Word16 orderLo, |
| WebRtc_Word16 *hibandQ15, |
| WebRtc_Word16 orderHi, |
| WebRtc_Word16 Nsub) { |
| |
| int k, n; |
| WebRtc_Word16 orderTot; |
| WebRtc_Word16 *outplQ15, *outphQ15; |
| WebRtc_Word32 *inpQ17; |
| WebRtc_Word16 rcQ15[7+6]; |
| |
| orderTot = (orderLo + orderHi); |
| outplQ15 = lowbandQ15; |
| outphQ15 = hibandQ15; |
| inpQ17 = larsQ17; |
| for (k = 0; k < Nsub; k++) { |
| |
| /* gains not handled here as in the FLP version */ |
| |
| /* Low band */ |
| Lar2RcFix(&inpQ17[0], rcQ15, orderLo); |
| for (n = 0; n < orderLo; n++) |
| outplQ15[n] = rcQ15[n]; // Refl. coeffs |
| |
| /* High band */ |
| Lar2RcFix(&inpQ17[orderLo], rcQ15, orderHi); |
| for (n = 0; n < orderHi; n++) |
| outphQ15[n] = rcQ15[n]; // Refl. coeffs |
| |
| inpQ17 += orderTot; |
| outplQ15 += orderLo; |
| outphQ15 += orderHi; |
| } |
| } |
| |
| int WebRtcIsacfix_DecodeLpc(WebRtc_Word32 *gain_lo_hiQ17, |
| WebRtc_Word16 *LPCCoef_loQ15, |
| WebRtc_Word16 *LPCCoef_hiQ15, |
| Bitstr_dec *streamdata, |
| WebRtc_Word16 *outmodel) { |
| |
| WebRtc_Word32 larsQ17[KLT_ORDER_SHAPE]; // KLT_ORDER_GAIN+KLT_ORDER_SHAPE == (ORDERLO+ORDERHI)*SUBFRAMES |
| int err; |
| |
| err = WebRtcIsacfix_DecodeLpcCoef(streamdata, larsQ17, gain_lo_hiQ17, outmodel); |
| if (err<0) // error check |
| return -ISAC_RANGE_ERROR_DECODE_LPC; |
| |
| Lar2polyFix(larsQ17, LPCCoef_loQ15, ORDERLO, LPCCoef_hiQ15, ORDERHI, SUBFRAMES); |
| |
| return 0; |
| } |
| |
| /* decode & dequantize LPC Coef */ |
| int WebRtcIsacfix_DecodeLpcCoef(Bitstr_dec *streamdata, |
| WebRtc_Word32 *LPCCoefQ17, |
| WebRtc_Word32 *gain_lo_hiQ17, |
| WebRtc_Word16 *outmodel) |
| { |
| int j, k, n; |
| int err; |
| WebRtc_Word16 pos, pos2, posg, poss, offsg, offss, offs2; |
| WebRtc_Word16 gainpos; |
| WebRtc_Word16 model; |
| WebRtc_Word16 index_QQ[KLT_ORDER_SHAPE]; |
| WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN]; |
| WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN]; |
| WebRtc_Word16 tmpcoeffs_sQ10[KLT_ORDER_SHAPE]; |
| WebRtc_Word32 tmpcoeffs_sQ17[KLT_ORDER_SHAPE]; |
| WebRtc_Word32 tmpcoeffs2_sQ18[KLT_ORDER_SHAPE]; |
| WebRtc_Word32 sumQQ; |
| WebRtc_Word16 sumQQ16; |
| WebRtc_Word32 tmp32; |
| |
| |
| |
| /* entropy decoding of model number */ |
| err = WebRtcIsacfix_DecHistOneStepMulti(&model, streamdata, WebRtcIsacfix_kModelCdfPtr, WebRtcIsacfix_kModelInitIndex, 1); |
| if (err<0) // error check |
| return err; |
| |
| /* entropy decoding of quantization indices */ |
| err = WebRtcIsacfix_DecHistOneStepMulti(index_QQ, streamdata, WebRtcIsacfix_kCdfShapePtr[model], WebRtcIsacfix_kInitIndexShape[model], KLT_ORDER_SHAPE); |
| if (err<0) // error check |
| return err; |
| /* find quantization levels for coefficients */ |
| for (k=0; k<KLT_ORDER_SHAPE; k++) { |
| tmpcoeffs_sQ10[WebRtcIsacfix_kSelIndShape[k]] = WebRtcIsacfix_kLevelsShapeQ10[WebRtcIsacfix_kOfLevelsShape[model]+WebRtcIsacfix_kOffsetShape[model][k] + index_QQ[k]]; |
| } |
| |
| err = WebRtcIsacfix_DecHistOneStepMulti(index_QQ, streamdata, WebRtcIsacfix_kCdfGainPtr[model], WebRtcIsacfix_kInitIndexGain[model], KLT_ORDER_GAIN); |
| if (err<0) // error check |
| return err; |
| /* find quantization levels for coefficients */ |
| for (k=0; k<KLT_ORDER_GAIN; k++) { |
| tmpcoeffs_gQ17[WebRtcIsacfix_kSelIndGain[k]] = WebRtcIsacfix_kLevelsGainQ17[WebRtcIsacfix_kOfLevelsGain[model]+ WebRtcIsacfix_kOffsetGain[model][k] + index_QQ[k]]; |
| } |
| |
| |
| /* inverse KLT */ |
| |
| /* left transform */ // Transpose matrix! |
| offsg = 0; |
| offss = 0; |
| posg = 0; |
| poss = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| offs2 = 0; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = offsg; |
| pos2 = offs2; |
| for (n=0; n<2; n++) { |
| sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1GainQ15[model][pos2], tmpcoeffs_gQ17[pos]<<5)); // (Q15*Q17)>>(16-5) = Q21 |
| pos++; |
| pos2++; |
| } |
| tmpcoeffs2_gQ21[posg] = sumQQ; //Q21 |
| posg++; |
| offs2 += 2; |
| } |
| offs2 = 0; |
| |
| for (k=0; k<LPC_SHAPE_ORDER; k++) { |
| sumQQ = 0; |
| pos = offss; |
| pos2 = offs2; |
| for (n=0; n<LPC_SHAPE_ORDER; n++) { |
| sumQQ += WEBRTC_SPL_MUL_16_16_RSFT(tmpcoeffs_sQ10[pos], WebRtcIsacfix_kT1ShapeQ15[model][pos2], 7); // (Q10*Q15)>>7 = Q18 |
| pos++; |
| pos2++; |
| } |
| tmpcoeffs2_sQ18[poss] = sumQQ; //Q18 |
| poss++; |
| offs2 += LPC_SHAPE_ORDER; |
| } |
| offsg += 2; |
| offss += LPC_SHAPE_ORDER; |
| } |
| |
| /* right transform */ // Transpose matrix |
| offsg = 0; |
| offss = 0; |
| posg = 0; |
| poss = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| posg = offsg; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = k; |
| pos2 = j; |
| for (n=0; n<SUBFRAMES; n++) { |
| sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[model][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 |
| pos += 2; |
| pos2 += SUBFRAMES; |
| |
| } |
| tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); |
| posg++; |
| } |
| poss = offss; |
| for (k=0; k<LPC_SHAPE_ORDER; k++) { |
| sumQQ = 0; |
| pos = k; |
| pos2 = j; |
| for (n=0; n<SUBFRAMES; n++) { |
| sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2ShapeQ15[model][pos2], tmpcoeffs2_sQ18[pos])); // (Q15*Q18)>>16 = Q17 |
| pos += LPC_SHAPE_ORDER; |
| pos2 += SUBFRAMES; |
| } |
| tmpcoeffs_sQ17[poss] = sumQQ; |
| poss++; |
| } |
| offsg += 2; |
| offss += LPC_SHAPE_ORDER; |
| } |
| |
| /* scaling, mean addition, and gain restoration */ |
| gainpos = 0; |
| posg = 0;poss = 0;pos=0; |
| for (k=0; k<SUBFRAMES; k++) { |
| |
| /* log gains */ |
| sumQQ16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9 |
| sumQQ16 += WebRtcIsacfix_kMeansGainQ8[model][posg]; |
| sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out |
| gain_lo_hiQ17[gainpos] = sumQQ; //Q17 |
| gainpos++; |
| posg++; |
| |
| sumQQ16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9 |
| sumQQ16 += WebRtcIsacfix_kMeansGainQ8[model][posg]; |
| sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out |
| gain_lo_hiQ17[gainpos] = sumQQ; //Q17 |
| gainpos++; |
| posg++; |
| |
| /* lo band LAR coeffs */ |
| for (n=0; n<ORDERLO; n++, pos++, poss++) { |
| tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(31208, tmpcoeffs_sQ17[poss]); // (Q16*Q17)>>16 = Q17, with 1/2.1 = 0.47619047619 ~= 31208 in Q16 |
| tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[model][poss]; // Q17+Q17 = Q17 |
| LPCCoefQ17[pos] = tmp32; |
| } |
| |
| /* hi band LAR coeffs */ |
| for (n=0; n<ORDERHI; n++, pos++, poss++) { |
| tmp32 = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(18204, tmpcoeffs_sQ17[poss]), 3); // ((Q13*Q17)>>16)<<3 = Q17, with 1/0.45 = 2.222222222222 ~= 18204 in Q13 |
| tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[model][poss]; // Q17+Q17 = Q17 |
| LPCCoefQ17[pos] = tmp32; |
| } |
| } |
| |
| |
| *outmodel=model; |
| |
| return 0; |
| } |
| |
| /* estimate codel length of LPC Coef */ |
| static int EstCodeLpcCoef(WebRtc_Word32 *LPCCoefQ17, |
| WebRtc_Word32 *gain_lo_hiQ17, |
| WebRtc_Word16 *model, |
| WebRtc_Word32 *sizeQ11, |
| Bitstr_enc *streamdata, |
| ISAC_SaveEncData_t* encData, |
| transcode_obj *transcodingParam) { |
| int j, k, n; |
| WebRtc_Word16 posQQ, pos2QQ, gainpos; |
| WebRtc_Word16 pos, pos2, poss, posg, offsg, offss, offs2; |
| WebRtc_Word16 index_gQQ[KLT_ORDER_GAIN], index_sQQ[KLT_ORDER_SHAPE]; |
| WebRtc_Word16 index_ovr_gQQ[KLT_ORDER_GAIN], index_ovr_sQQ[KLT_ORDER_SHAPE]; |
| WebRtc_Word32 BitsQQ; |
| |
| WebRtc_Word16 tmpcoeffs_gQ6[KLT_ORDER_GAIN]; |
| WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN]; |
| WebRtc_Word32 tmpcoeffs_sQ17[KLT_ORDER_SHAPE]; |
| WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN]; |
| WebRtc_Word32 tmpcoeffs2_sQ17[KLT_ORDER_SHAPE]; |
| WebRtc_Word32 sumQQ; |
| WebRtc_Word32 tmp32; |
| WebRtc_Word16 sumQQ16; |
| int status = 0; |
| |
| /* write LAR coefficients to statistics file */ |
| /* Save data for creation of multiple bitstreams (and transcoding) */ |
| if (encData != NULL) { |
| for (k=0; k<KLT_ORDER_GAIN; k++) { |
| encData->LPCcoeffs_g[KLT_ORDER_GAIN*encData->startIdx + k] = gain_lo_hiQ17[k]; |
| } |
| } |
| |
| /* log gains, mean removal and scaling */ |
| posg = 0;poss = 0;pos=0; gainpos=0; |
| |
| for (k=0; k<SUBFRAMES; k++) { |
| /* log gains */ |
| |
| /* The input argument X to logN(X) is 2^17 times higher than the |
| input floating point argument Y to log(Y), since the X value |
| is a Q17 value. This can be compensated for after the call, by |
| subraction a value Z for each Q-step. One Q-step means that |
| X gets 2 times higher, i.e. Z = logN(2)*256 = 0.693147180559*256 = |
| 177.445678 should be subtracted (since logN() returns a Q8 value). |
| For a X value in Q17, the value 177.445678*17 = 3017 should be |
| subtracted */ |
| tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 |
| tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 |
| posg++; gainpos++; |
| |
| tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 |
| tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 |
| posg++; gainpos++; |
| |
| /* lo band LAR coeffs */ |
| for (n=0; n<ORDERLO; n++, poss++, pos++) { |
| tmp32 = LPCCoefQ17[pos] - WebRtcIsacfix_kMeansShapeQ17[0][poss]; //Q17 |
| tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(17203, tmp32<<3); // tmp32 = 2.1*tmp32 |
| tmpcoeffs_sQ17[poss] = tmp32; //Q17 |
| } |
| |
| /* hi band LAR coeffs */ |
| for (n=0; n<ORDERHI; n++, poss++, pos++) { |
| tmp32 = LPCCoefQ17[pos] - WebRtcIsacfix_kMeansShapeQ17[0][poss]; //Q17 |
| tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(14746, tmp32<<1); // tmp32 = 0.45*tmp32 |
| tmpcoeffs_sQ17[poss] = tmp32; //Q17 |
| } |
| |
| } |
| |
| |
| /* KLT */ |
| |
| /* left transform */ |
| offsg = 0; |
| offss = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| posg = offsg; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = offsg; |
| pos2 = k; |
| for (n=0; n<2; n++) { |
| sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[pos], WebRtcIsacfix_kT1GainQ15[0][pos2]); //Q21 = Q6*Q15 |
| pos++; |
| pos2 += 2; |
| } |
| tmpcoeffs2_gQ21[posg] = sumQQ; |
| posg++; |
| } |
| poss = offss; |
| for (k=0; k<LPC_SHAPE_ORDER; k++) { |
| sumQQ = 0; |
| pos = offss; |
| pos2 = k; |
| for (n=0; n<LPC_SHAPE_ORDER; n++) { |
| sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1ShapeQ15[0][pos2], tmpcoeffs_sQ17[pos]<<1)); // (Q15*Q17)>>(16-1) = Q17 |
| pos++; |
| pos2 += LPC_SHAPE_ORDER; |
| } |
| tmpcoeffs2_sQ17[poss] = sumQQ; //Q17 |
| poss++; |
| } |
| offsg += 2; |
| offss += LPC_SHAPE_ORDER; |
| } |
| |
| /* right transform */ |
| offsg = 0; |
| offss = 0; |
| offs2 = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| posg = offsg; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = k; |
| pos2 = offs2; |
| for (n=0; n<SUBFRAMES; n++) { |
| sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[0][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 |
| pos += 2; |
| pos2++; |
| } |
| tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); |
| posg++; |
| } |
| poss = offss; |
| for (k=0; k<LPC_SHAPE_ORDER; k++) { |
| sumQQ = 0; |
| pos = k; |
| pos2 = offs2; |
| for (n=0; n<SUBFRAMES; n++) { |
| sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2ShapeQ15[0][pos2], tmpcoeffs2_sQ17[pos]<<1)); // (Q15*Q17)>>(16-1) = Q17 |
| pos += LPC_SHAPE_ORDER; |
| pos2++; |
| } |
| tmpcoeffs_sQ17[poss] = sumQQ; |
| poss++; |
| } |
| offs2 += SUBFRAMES; |
| offsg += 2; |
| offss += LPC_SHAPE_ORDER; |
| } |
| |
| /* quantize coefficients */ |
| |
| BitsQQ = 0; |
| for (k=0; k<KLT_ORDER_GAIN; k++) //ATTN: ok? |
| { |
| posQQ = WebRtcIsacfix_kSelIndGain[k]; |
| pos2QQ= (WebRtc_Word16)CalcLrIntQ(tmpcoeffs_gQ17[posQQ], 17); |
| |
| index_gQQ[k] = pos2QQ + WebRtcIsacfix_kQuantMinGain[k]; //ATTN: ok? |
| if (index_gQQ[k] < 0) { |
| index_gQQ[k] = 0; |
| } |
| else if (index_gQQ[k] > WebRtcIsacfix_kMaxIndGain[k]) { |
| index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k]; |
| } |
| index_ovr_gQQ[k] = WebRtcIsacfix_kOffsetGain[0][k]+index_gQQ[k]; |
| posQQ = WebRtcIsacfix_kOfLevelsGain[0] + index_ovr_gQQ[k]; |
| |
| /* Save data for creation of multiple bitstreams */ |
| if (encData != NULL) { |
| encData->LPCindex_g[KLT_ORDER_GAIN*encData->startIdx + k] = index_gQQ[k]; |
| } |
| |
| /* determine number of bits */ |
| sumQQ = WebRtcIsacfix_kCodeLenGainQ11[posQQ]; //Q11 |
| BitsQQ += sumQQ; |
| } |
| |
| for (k=0; k<KLT_ORDER_SHAPE; k++) //ATTN: ok? |
| { |
| index_sQQ[k] = (WebRtc_Word16)(CalcLrIntQ(tmpcoeffs_sQ17[WebRtcIsacfix_kSelIndShape[k]], 17) + WebRtcIsacfix_kQuantMinShape[k]); //ATTN: ok? |
| |
| if (index_sQQ[k] < 0) |
| index_sQQ[k] = 0; |
| else if (index_sQQ[k] > WebRtcIsacfix_kMaxIndShape[k]) |
| index_sQQ[k] = WebRtcIsacfix_kMaxIndShape[k]; |
| index_ovr_sQQ[k] = WebRtcIsacfix_kOffsetShape[0][k]+index_sQQ[k]; |
| |
| posQQ = WebRtcIsacfix_kOfLevelsShape[0] + index_ovr_sQQ[k]; |
| sumQQ = WebRtcIsacfix_kCodeLenShapeQ11[posQQ]; //Q11 |
| BitsQQ += sumQQ; |
| } |
| |
| |
| |
| *model = 0; |
| *sizeQ11=BitsQQ; |
| |
| /* entropy coding of model number */ |
| status = WebRtcIsacfix_EncHistMulti(streamdata, model, WebRtcIsacfix_kModelCdfPtr, 1); |
| if (status < 0) { |
| return status; |
| } |
| |
| /* entropy coding of quantization indices - shape only */ |
| status = WebRtcIsacfix_EncHistMulti(streamdata, index_sQQ, WebRtcIsacfix_kCdfShapePtr[0], KLT_ORDER_SHAPE); |
| if (status < 0) { |
| return status; |
| } |
| |
| /* Save data for creation of multiple bitstreams */ |
| if (encData != NULL) { |
| for (k=0; k<KLT_ORDER_SHAPE; k++) |
| { |
| encData->LPCindex_s[KLT_ORDER_SHAPE*encData->startIdx + k] = index_sQQ[k]; |
| } |
| } |
| /* save the state of the bitstream object 'streamdata' for the possible bit-rate reduction */ |
| transcodingParam->full = streamdata->full; |
| transcodingParam->stream_index = streamdata->stream_index; |
| transcodingParam->streamval = streamdata->streamval; |
| transcodingParam->W_upper = streamdata->W_upper; |
| transcodingParam->beforeLastWord = streamdata->stream[streamdata->stream_index-1]; |
| transcodingParam->lastWord = streamdata->stream[streamdata->stream_index]; |
| |
| /* entropy coding of index */ |
| status = WebRtcIsacfix_EncHistMulti(streamdata, index_gQQ, WebRtcIsacfix_kCdfGainPtr[0], KLT_ORDER_GAIN); |
| if (status < 0) { |
| return status; |
| } |
| |
| /* find quantization levels for shape coefficients */ |
| for (k=0; k<KLT_ORDER_SHAPE; k++) { |
| tmpcoeffs_sQ17[WebRtcIsacfix_kSelIndShape[k]] = WEBRTC_SPL_MUL(128, WebRtcIsacfix_kLevelsShapeQ10[WebRtcIsacfix_kOfLevelsShape[0]+index_ovr_sQQ[k]]); |
| |
| } |
| /* inverse KLT */ |
| |
| /* left transform */ // Transpose matrix! |
| offss = 0; |
| poss = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| offs2 = 0; |
| for (k=0; k<LPC_SHAPE_ORDER; k++) { |
| sumQQ = 0; |
| pos = offss; |
| pos2 = offs2; |
| for (n=0; n<LPC_SHAPE_ORDER; n++) { |
| sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1ShapeQ15[0][pos2], tmpcoeffs_sQ17[pos]<<1)); // (Q15*Q17)>>(16-1) = Q17 |
| pos++; |
| pos2++; |
| } |
| tmpcoeffs2_sQ17[poss] = sumQQ; |
| |
| poss++; |
| offs2 += LPC_SHAPE_ORDER; |
| } |
| offss += LPC_SHAPE_ORDER; |
| } |
| |
| |
| /* right transform */ // Transpose matrix |
| offss = 0; |
| poss = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| poss = offss; |
| for (k=0; k<LPC_SHAPE_ORDER; k++) { |
| sumQQ = 0; |
| pos = k; |
| pos2 = j; |
| for (n=0; n<SUBFRAMES; n++) { |
| sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2ShapeQ15[0][pos2], tmpcoeffs2_sQ17[pos]<<1)); // (Q15*Q17)>>(16-1) = Q17 |
| pos += LPC_SHAPE_ORDER; |
| pos2 += SUBFRAMES; |
| } |
| tmpcoeffs_sQ17[poss] = sumQQ; |
| poss++; |
| } |
| offss += LPC_SHAPE_ORDER; |
| } |
| |
| /* scaling, mean addition, and gain restoration */ |
| poss = 0;pos=0; |
| for (k=0; k<SUBFRAMES; k++) { |
| |
| /* lo band LAR coeffs */ |
| for (n=0; n<ORDERLO; n++, pos++, poss++) { |
| tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(31208, tmpcoeffs_sQ17[poss]); // (Q16*Q17)>>16 = Q17, with 1/2.1 = 0.47619047619 ~= 31208 in Q16 |
| tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[0][poss]; // Q17+Q17 = Q17 |
| LPCCoefQ17[pos] = tmp32; |
| } |
| |
| /* hi band LAR coeffs */ |
| for (n=0; n<ORDERHI; n++, pos++, poss++) { |
| tmp32 = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(18204, tmpcoeffs_sQ17[poss]), 3); // ((Q13*Q17)>>16)<<3 = Q17, with 1/0.45 = 2.222222222222 ~= 18204 in Q13 |
| tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[0][poss]; // Q17+Q17 = Q17 |
| LPCCoefQ17[pos] = tmp32; |
| } |
| |
| } |
| |
| //to update tmpcoeffs_gQ17 to the proper state |
| for (k=0; k<KLT_ORDER_GAIN; k++) { |
| tmpcoeffs_gQ17[WebRtcIsacfix_kSelIndGain[k]] = WebRtcIsacfix_kLevelsGainQ17[WebRtcIsacfix_kOfLevelsGain[0]+index_ovr_gQQ[k]]; |
| } |
| |
| |
| |
| /* find quantization levels for coefficients */ |
| |
| /* left transform */ |
| offsg = 0; |
| posg = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| offs2 = 0; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = offsg; |
| pos2 = offs2; |
| for (n=0; n<2; n++) { |
| sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1GainQ15[0][pos2], tmpcoeffs_gQ17[pos])<<1); // (Q15*Q17)>>(16-1) = Q17 |
| pos++; |
| pos2++; |
| } |
| tmpcoeffs2_gQ21[posg] = WEBRTC_SPL_LSHIFT_W32(sumQQ, 4); //Q17<<4 = Q21 |
| posg++; |
| offs2 += 2; |
| } |
| offsg += 2; |
| } |
| |
| /* right transform */ // Transpose matrix |
| offsg = 0; |
| posg = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| posg = offsg; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = k; |
| pos2 = j; |
| for (n=0; n<SUBFRAMES; n++) { |
| sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[0][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 |
| pos += 2; |
| pos2 += SUBFRAMES; |
| } |
| tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); |
| posg++; |
| } |
| offsg += 2; |
| } |
| |
| /* scaling, mean addition, and gain restoration */ |
| posg = 0; |
| gainpos = 0; |
| for (k=0; k<2*SUBFRAMES; k++) { |
| |
| sumQQ16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9 |
| sumQQ16 += WebRtcIsacfix_kMeansGainQ8[0][posg]; |
| sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out |
| gain_lo_hiQ17[gainpos] = sumQQ; //Q17 |
| |
| gainpos++; |
| pos++;posg++; |
| } |
| |
| return 0; |
| } |
| |
| int WebRtcIsacfix_EstCodeLpcGain(WebRtc_Word32 *gain_lo_hiQ17, |
| Bitstr_enc *streamdata, |
| ISAC_SaveEncData_t* encData) { |
| int j, k, n; |
| WebRtc_Word16 posQQ, pos2QQ, gainpos; |
| WebRtc_Word16 pos, pos2, posg, offsg, offs2; |
| WebRtc_Word16 index_gQQ[KLT_ORDER_GAIN]; |
| |
| WebRtc_Word16 tmpcoeffs_gQ6[KLT_ORDER_GAIN]; |
| WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN]; |
| WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN]; |
| WebRtc_Word32 sumQQ; |
| int status = 0; |
| |
| /* write LAR coefficients to statistics file */ |
| /* Save data for creation of multiple bitstreams (and transcoding) */ |
| if (encData != NULL) { |
| for (k=0; k<KLT_ORDER_GAIN; k++) { |
| encData->LPCcoeffs_g[KLT_ORDER_GAIN*encData->startIdx + k] = gain_lo_hiQ17[k]; |
| } |
| } |
| |
| /* log gains, mean removal and scaling */ |
| posg = 0; pos = 0; gainpos = 0; |
| |
| for (k=0; k<SUBFRAMES; k++) { |
| /* log gains */ |
| |
| /* The input argument X to logN(X) is 2^17 times higher than the |
| input floating point argument Y to log(Y), since the X value |
| is a Q17 value. This can be compensated for after the call, by |
| subraction a value Z for each Q-step. One Q-step means that |
| X gets 2 times higher, i.e. Z = logN(2)*256 = 0.693147180559*256 = |
| 177.445678 should be subtracted (since logN() returns a Q8 value). |
| For a X value in Q17, the value 177.445678*17 = 3017 should be |
| subtracted */ |
| tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 |
| tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 |
| posg++; gainpos++; |
| |
| tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 |
| tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 |
| posg++; gainpos++; |
| } |
| |
| |
| /* KLT */ |
| |
| /* left transform */ |
| offsg = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| posg = offsg; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = offsg; |
| pos2 = k; |
| for (n=0; n<2; n++) { |
| sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[pos], WebRtcIsacfix_kT1GainQ15[0][pos2]); //Q21 = Q6*Q15 |
| pos++; |
| pos2 += 2; |
| } |
| tmpcoeffs2_gQ21[posg] = sumQQ; |
| posg++; |
| } |
| offsg += 2; |
| } |
| |
| /* right transform */ |
| offsg = 0; |
| offs2 = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| posg = offsg; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = k; |
| pos2 = offs2; |
| for (n=0; n<SUBFRAMES; n++) { |
| sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[0][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 |
| pos += 2; |
| pos2++; |
| } |
| tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); |
| posg++; |
| } |
| offsg += 2; |
| offs2 += SUBFRAMES; |
| } |
| |
| /* quantize coefficients */ |
| |
| for (k=0; k<KLT_ORDER_GAIN; k++) //ATTN: ok? |
| { |
| posQQ = WebRtcIsacfix_kSelIndGain[k]; |
| pos2QQ= (WebRtc_Word16)CalcLrIntQ(tmpcoeffs_gQ17[posQQ], 17); |
| |
| index_gQQ[k] = pos2QQ + WebRtcIsacfix_kQuantMinGain[k]; //ATTN: ok? |
| if (index_gQQ[k] < 0) { |
| index_gQQ[k] = 0; |
| } |
| else if (index_gQQ[k] > WebRtcIsacfix_kMaxIndGain[k]) { |
| index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k]; |
| } |
| |
| /* Save data for creation of multiple bitstreams */ |
| if (encData != NULL) { |
| encData->LPCindex_g[KLT_ORDER_GAIN*encData->startIdx + k] = index_gQQ[k]; |
| } |
| } |
| |
| /* entropy coding of index */ |
| status = WebRtcIsacfix_EncHistMulti(streamdata, index_gQQ, WebRtcIsacfix_kCdfGainPtr[0], KLT_ORDER_GAIN); |
| if (status < 0) { |
| return status; |
| } |
| |
| return 0; |
| } |
| |
| |
| int WebRtcIsacfix_EncodeLpc(WebRtc_Word32 *gain_lo_hiQ17, |
| WebRtc_Word16 *LPCCoef_loQ15, |
| WebRtc_Word16 *LPCCoef_hiQ15, |
| WebRtc_Word16 *model, |
| WebRtc_Word32 *sizeQ11, |
| Bitstr_enc *streamdata, |
| ISAC_SaveEncData_t* encData, |
| transcode_obj *transcodeParam) |
| { |
| int status = 0; |
| WebRtc_Word32 larsQ17[KLT_ORDER_SHAPE]; // KLT_ORDER_SHAPE == (ORDERLO+ORDERHI)*SUBFRAMES |
| // = (6+12)*6 == 108 |
| |
| Poly2LarFix(LPCCoef_loQ15, ORDERLO, LPCCoef_hiQ15, ORDERHI, SUBFRAMES, larsQ17); |
| |
| status = EstCodeLpcCoef(larsQ17, gain_lo_hiQ17, model, sizeQ11, streamdata, encData, transcodeParam); |
| if (status < 0) { |
| return (status); |
| } |
| |
| Lar2polyFix(larsQ17, LPCCoef_loQ15, ORDERLO, LPCCoef_hiQ15, ORDERHI, SUBFRAMES); |
| |
| return 0; |
| } |
| |
| |
| /* decode & dequantize RC */ |
| int WebRtcIsacfix_DecodeRcCoef(Bitstr_dec *streamdata, WebRtc_Word16 *RCQ15) |
| { |
| int k, err; |
| WebRtc_Word16 index[AR_ORDER]; |
| |
| /* entropy decoding of quantization indices */ |
| err = WebRtcIsacfix_DecHistOneStepMulti(index, streamdata, WebRtcIsacfix_kRcCdfPtr, WebRtcIsacfix_kRcInitInd, AR_ORDER); |
| if (err<0) // error check |
| return err; |
| |
| /* find quantization levels for reflection coefficients */ |
| for (k=0; k<AR_ORDER; k++) |
| { |
| RCQ15[k] = *(WebRtcIsacfix_kRcLevPtr[k] + index[k]); |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| /* quantize & code RC */ |
| int WebRtcIsacfix_EncodeRcCoef(WebRtc_Word16 *RCQ15, Bitstr_enc *streamdata) |
| { |
| int k; |
| WebRtc_Word16 index[AR_ORDER]; |
| int status; |
| |
| /* quantize reflection coefficients (add noise feedback?) */ |
| for (k=0; k<AR_ORDER; k++) |
| { |
| index[k] = WebRtcIsacfix_kRcInitInd[k]; |
| |
| if (RCQ15[k] > WebRtcIsacfix_kRcBound[index[k]]) |
| { |
| while (RCQ15[k] > WebRtcIsacfix_kRcBound[index[k] + 1]) |
| index[k]++; |
| } |
| else |
| { |
| while (RCQ15[k] < WebRtcIsacfix_kRcBound[--index[k]]) ; |
| } |
| |
| RCQ15[k] = *(WebRtcIsacfix_kRcLevPtr[k] + index[k]); |
| } |
| |
| |
| /* entropy coding of quantization indices */ |
| status = WebRtcIsacfix_EncHistMulti(streamdata, index, WebRtcIsacfix_kRcCdfPtr, AR_ORDER); |
| |
| /* If error in WebRtcIsacfix_EncHistMulti(), status will be negative, otherwise 0 */ |
| return status; |
| } |
| |
| |
| /* decode & dequantize squared Gain */ |
| int WebRtcIsacfix_DecodeGain2(Bitstr_dec *streamdata, WebRtc_Word32 *gainQ10) |
| { |
| int err; |
| WebRtc_Word16 index; |
| |
| /* entropy decoding of quantization index */ |
| err = WebRtcIsacfix_DecHistOneStepMulti( |
| &index, |
| streamdata, |
| WebRtcIsacfix_kGainPtr, |
| WebRtcIsacfix_kGainInitInd, |
| 1); |
| /* error check */ |
| if (err<0) { |
| return err; |
| } |
| |
| /* find quantization level */ |
| *gainQ10 = WebRtcIsacfix_kGain2Lev[index]; |
| |
| return 0; |
| } |
| |
| |
| |
| /* quantize & code squared Gain */ |
| int WebRtcIsacfix_EncodeGain2(WebRtc_Word32 *gainQ10, Bitstr_enc *streamdata) |
| { |
| WebRtc_Word16 index; |
| int status = 0; |
| |
| /* find quantization index */ |
| index = WebRtcIsacfix_kGainInitInd[0]; |
| if (*gainQ10 > WebRtcIsacfix_kGain2Bound[index]) |
| { |
| while (*gainQ10 > WebRtcIsacfix_kGain2Bound[index + 1]) |
| index++; |
| } |
| else |
| { |
| while (*gainQ10 < WebRtcIsacfix_kGain2Bound[--index]) ; |
| } |
| |
| /* dequantize */ |
| *gainQ10 = WebRtcIsacfix_kGain2Lev[index]; |
| |
| /* entropy coding of quantization index */ |
| status = WebRtcIsacfix_EncHistMulti(streamdata, &index, WebRtcIsacfix_kGainPtr, 1); |
| |
| /* If error in WebRtcIsacfix_EncHistMulti(), status will be negative, otherwise 0 */ |
| return status; |
| } |
| |
| |
| /* code and decode Pitch Gains and Lags functions */ |
| |
| /* decode & dequantize Pitch Gains */ |
| int WebRtcIsacfix_DecodePitchGain(Bitstr_dec *streamdata, WebRtc_Word16 *PitchGains_Q12) |
| { |
| int err; |
| WebRtc_Word16 index_comb; |
| const WebRtc_UWord16 *pitch_gain_cdf_ptr[1]; |
| |
| /* entropy decoding of quantization indices */ |
| *pitch_gain_cdf_ptr = WebRtcIsacfix_kPitchGainCdf; |
| err = WebRtcIsacfix_DecHistBisectMulti(&index_comb, streamdata, pitch_gain_cdf_ptr, WebRtcIsacfix_kCdfTableSizeGain, 1); |
| /* error check, Q_mean_Gain.. tables are of size 144 */ |
| if ((err < 0) || (index_comb < 0) || (index_comb >= 144)) |
| return -ISAC_RANGE_ERROR_DECODE_PITCH_GAIN; |
| |
| /* unquantize back to pitch gains by table look-up */ |
| PitchGains_Q12[0] = WebRtcIsacfix_kPitchGain1[index_comb]; |
| PitchGains_Q12[1] = WebRtcIsacfix_kPitchGain2[index_comb]; |
| PitchGains_Q12[2] = WebRtcIsacfix_kPitchGain3[index_comb]; |
| PitchGains_Q12[3] = WebRtcIsacfix_kPitchGain4[index_comb]; |
| |
| return 0; |
| } |
| |
| |
| /* quantize & code Pitch Gains */ |
| int WebRtcIsacfix_EncodePitchGain(WebRtc_Word16 *PitchGains_Q12, Bitstr_enc *streamdata, ISAC_SaveEncData_t* encData) |
| { |
| int k,j; |
| WebRtc_Word16 SQ15[PITCH_SUBFRAMES]; |
| WebRtc_Word16 index[3]; |
| WebRtc_Word16 index_comb; |
| const WebRtc_UWord16 *pitch_gain_cdf_ptr[1]; |
| WebRtc_Word32 CQ17; |
| int status = 0; |
| |
| |
| /* get the approximate arcsine (almost linear)*/ |
| for (k=0; k<PITCH_SUBFRAMES; k++) |
| SQ15[k] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(PitchGains_Q12[k],33,2); //Q15 |
| |
| |
| /* find quantization index; only for the first three transform coefficients */ |
| for (k=0; k<3; k++) |
| { |
| /* transform */ |
| CQ17=0; |
| for (j=0; j<PITCH_SUBFRAMES; j++) { |
| CQ17 += WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIsacfix_kTransform[k][j], SQ15[j],10); // Q17 |
| } |
| |
| index[k] = (WebRtc_Word16)((CQ17 + 8192)>>14); // Rounding and scaling with stepsize (=1/0.125=8) |
| |
| /* check that the index is not outside the boundaries of the table */ |
| if (index[k] < WebRtcIsacfix_kLowerlimiGain[k]) index[k] = WebRtcIsacfix_kLowerlimiGain[k]; |
| else if (index[k] > WebRtcIsacfix_kUpperlimitGain[k]) index[k] = WebRtcIsacfix_kUpperlimitGain[k]; |
| index[k] -= WebRtcIsacfix_kLowerlimiGain[k]; |
| } |
| |
| /* calculate unique overall index */ |
| index_comb = (WebRtc_Word16)(WEBRTC_SPL_MUL(WebRtcIsacfix_kMultsGain[0], index[0]) + |
| WEBRTC_SPL_MUL(WebRtcIsacfix_kMultsGain[1], index[1]) + index[2]); |
| |
| /* unquantize back to pitch gains by table look-up */ |
| // (Y) |
| PitchGains_Q12[0] = WebRtcIsacfix_kPitchGain1[index_comb]; |
| PitchGains_Q12[1] = WebRtcIsacfix_kPitchGain2[index_comb]; |
| PitchGains_Q12[2] = WebRtcIsacfix_kPitchGain3[index_comb]; |
| PitchGains_Q12[3] = WebRtcIsacfix_kPitchGain4[index_comb]; |
| |
| |
| /* entropy coding of quantization pitch gains */ |
| *pitch_gain_cdf_ptr = WebRtcIsacfix_kPitchGainCdf; |
| status = WebRtcIsacfix_EncHistMulti(streamdata, &index_comb, pitch_gain_cdf_ptr, 1); |
| if (status < 0) { |
| return status; |
| } |
| |
| /* Save data for creation of multiple bitstreams */ |
| if (encData != NULL) { |
| encData->pitchGain_index[encData->startIdx] = index_comb; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| /* Pitch LAG */ |
| |
| |
| /* decode & dequantize Pitch Lags */ |
| int WebRtcIsacfix_DecodePitchLag(Bitstr_dec *streamdata, |
| WebRtc_Word16 *PitchGain_Q12, |
| WebRtc_Word16 *PitchLags_Q7) |
| { |
| int k, err; |
| WebRtc_Word16 index[PITCH_SUBFRAMES]; |
| const WebRtc_Word16 *mean_val2Q10, *mean_val4Q10; |
| |
| const WebRtc_Word16 *lower_limit; |
| const WebRtc_UWord16 *init_index; |
| const WebRtc_UWord16 *cdf_size; |
| const WebRtc_UWord16 **cdf; |
| |
| WebRtc_Word32 meangainQ12; |
| WebRtc_Word32 CQ11, CQ10,tmp32a,tmp32b; |
| WebRtc_Word16 shft,tmp16a,tmp16c; |
| |
| meangainQ12=0; |
| for (k = 0; k < 4; k++) |
| meangainQ12 += PitchGain_Q12[k]; |
| |
| meangainQ12 = WEBRTC_SPL_RSHIFT_W32(meangainQ12, 2); // Get average |
| |
| /* voicing classificiation */ |
| if (meangainQ12 <= 819) { // mean_gain < 0.2 |
| shft = -1; // StepSize=2.0; |
| cdf = WebRtcIsacfix_kPitchLagPtrLo; |
| cdf_size = WebRtcIsacfix_kPitchLagSizeLo; |
| mean_val2Q10 = WebRtcIsacfix_kMeanLag2Lo; |
| mean_val4Q10 = WebRtcIsacfix_kMeanLag4Lo; |
| lower_limit = WebRtcIsacfix_kLowerLimitLo; |
| init_index = WebRtcIsacfix_kInitIndLo; |
| } else if (meangainQ12 <= 1638) { // mean_gain < 0.4 |
| shft = 0; // StepSize=1.0; |
| cdf = WebRtcIsacfix_kPitchLagPtrMid; |
| cdf_size = WebRtcIsacfix_kPitchLagSizeMid; |
| mean_val2Q10 = WebRtcIsacfix_kMeanLag2Mid; |
| mean_val4Q10 = WebRtcIsacfix_kMeanLag4Mid; |
| lower_limit = WebRtcIsacfix_kLowerLimitMid; |
| init_index = WebRtcIsacfix_kInitIndMid; |
| } else { |
| shft = 1; // StepSize=0.5; |
| cdf = WebRtcIsacfix_kPitchLagPtrHi; |
| cdf_size = WebRtcIsacfix_kPitchLagSizeHi; |
| mean_val2Q10 = WebRtcIsacfix_kMeanLag2Hi; |
| mean_val4Q10 = WebRtcIsacfix_kMeanLag4Hi; |
| lower_limit = WebRtcIsacfix_kLowerLimitHi; |
| init_index = WebRtcIsacfix_kInitIndHi; |
| } |
| |
| /* entropy decoding of quantization indices */ |
| err = WebRtcIsacfix_DecHistBisectMulti(index, streamdata, cdf, cdf_size, 1); |
| if ((err<0) || (index[0]<0)) // error check |
| return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG; |
| |
| err = WebRtcIsacfix_DecHistOneStepMulti(index+1, streamdata, cdf+1, init_index, 3); |
| if (err<0) // error check |
| return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG; |
| |
| |
| /* unquantize back to transform coefficients and do the inverse transform: S = T'*C */ |
| CQ11 = ((WebRtc_Word32)index[0] + lower_limit[0]); // Q0 |
| CQ11 = WEBRTC_SPL_SHIFT_W32(CQ11,11-shft); // Scale with StepSize, Q11 |
| for (k=0; k<PITCH_SUBFRAMES; k++) { |
| tmp32a = WEBRTC_SPL_MUL_16_32_RSFT11(WebRtcIsacfix_kTransform[0][k], CQ11); |
| tmp16a = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32a, 5); |
| PitchLags_Q7[k] = tmp16a; |
| } |
| |
| CQ10 = mean_val2Q10[index[1]]; |
| for (k=0; k<PITCH_SUBFRAMES; k++) { |
| tmp32b = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[1][k], (WebRtc_Word16) CQ10,10); |
| tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); |
| PitchLags_Q7[k] += tmp16c; |
| } |
| |
| CQ10 = mean_val4Q10[index[3]]; |
| for (k=0; k<PITCH_SUBFRAMES; k++) { |
| tmp32b = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[3][k], (WebRtc_Word16) CQ10,10); |
| tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); |
| PitchLags_Q7[k] += tmp16c; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| /* quantize & code Pitch Lags */ |
| int WebRtcIsacfix_EncodePitchLag(WebRtc_Word16 *PitchLagsQ7,WebRtc_Word16 *PitchGain_Q12, |
| Bitstr_enc *streamdata, ISAC_SaveEncData_t* encData) |
| { |
| int k, j; |
| WebRtc_Word16 index[PITCH_SUBFRAMES]; |
| WebRtc_Word32 meangainQ12, CQ17; |
| WebRtc_Word32 CQ11, CQ10,tmp32a; |
| |
| const WebRtc_Word16 *mean_val2Q10,*mean_val4Q10; |
| const WebRtc_Word16 *lower_limit, *upper_limit; |
| const WebRtc_UWord16 **cdf; |
| WebRtc_Word16 shft, tmp16a, tmp16b, tmp16c; |
| WebRtc_Word32 tmp32b; |
| int status = 0; |
| |
| /* compute mean pitch gain */ |
| meangainQ12=0; |
| for (k = 0; k < 4; k++) |
| meangainQ12 += PitchGain_Q12[k]; |
| |
| meangainQ12 = WEBRTC_SPL_RSHIFT_W32(meangainQ12, 2); |
| |
| /* Save data for creation of multiple bitstreams */ |
| if (encData != NULL) { |
| encData->meanGain[encData->startIdx] = meangainQ12; |
| } |
| |
| /* voicing classificiation */ |
| if (meangainQ12 <= 819) { // mean_gain < 0.2 |
| shft = -1; // StepSize=2.0; |
| cdf = WebRtcIsacfix_kPitchLagPtrLo; |
| mean_val2Q10 = WebRtcIsacfix_kMeanLag2Lo; |
| mean_val4Q10 = WebRtcIsacfix_kMeanLag4Lo; |
| lower_limit = WebRtcIsacfix_kLowerLimitLo; |
| upper_limit = WebRtcIsacfix_kUpperLimitLo; |
| } else if (meangainQ12 <= 1638) { // mean_gain < 0.4 |
| shft = 0; // StepSize=1.0; |
| cdf = WebRtcIsacfix_kPitchLagPtrMid; |
| mean_val2Q10 = WebRtcIsacfix_kMeanLag2Mid; |
| mean_val4Q10 = WebRtcIsacfix_kMeanLag4Mid; |
| lower_limit = WebRtcIsacfix_kLowerLimitMid; |
| upper_limit = WebRtcIsacfix_kUpperLimitMid; |
| } else { |
| shft = 1; // StepSize=0.5; |
| cdf = WebRtcIsacfix_kPitchLagPtrHi; |
| mean_val2Q10 = WebRtcIsacfix_kMeanLag2Hi; |
| mean_val4Q10 = WebRtcIsacfix_kMeanLag4Hi; |
| lower_limit = WebRtcIsacfix_kLowerLimitHi; |
| upper_limit = WebRtcIsacfix_kUpperLimitHi; |
| } |
| |
| /* find quantization index */ |
| for (k=0; k<4; k++) |
| { |
| /* transform */ |
| CQ17=0; |
| for (j=0; j<PITCH_SUBFRAMES; j++) |
| CQ17 += WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIsacfix_kTransform[k][j], PitchLagsQ7[j],2); // Q17 |
| |
| CQ17 = WEBRTC_SPL_SHIFT_W32(CQ17,shft); // Scale with StepSize |
| |
| /* quantize */ |
| tmp16b = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(CQ17 + 65536, 17 ); |
| index[k] = tmp16b; |
| |
| /* check that the index is not outside the boundaries of the table */ |
| if (index[k] < lower_limit[k]) index[k] = lower_limit[k]; |
| else if (index[k] > upper_limit[k]) index[k] = upper_limit[k]; |
| index[k] -= lower_limit[k]; |
| |
| /* Save data for creation of multiple bitstreams */ |
| if(encData != NULL) { |
| encData->pitchIndex[PITCH_SUBFRAMES*encData->startIdx + k] = index[k]; |
| } |
| } |
| |
| /* unquantize back to transform coefficients and do the inverse transform: S = T'*C */ |
| CQ11 = (index[0] + lower_limit[0]); // Q0 |
| CQ11 = WEBRTC_SPL_SHIFT_W32(CQ11,11-shft); // Scale with StepSize, Q11 |
| |
| for (k=0; k<PITCH_SUBFRAMES; k++) { |
| tmp32a = WEBRTC_SPL_MUL_16_32_RSFT11(WebRtcIsacfix_kTransform[0][k], CQ11); // Q12 |
| tmp16a = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32a, 5);// Q7 |
| PitchLagsQ7[k] = tmp16a; |
| } |
| |
| CQ10 = mean_val2Q10[index[1]]; |
| for (k=0; k<PITCH_SUBFRAMES; k++) { |
| tmp32b = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[1][k], (WebRtc_Word16) CQ10,10); |
| tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q7 |
| PitchLagsQ7[k] += tmp16c; |
| } |
| |
| CQ10 = mean_val4Q10[index[3]]; |
| for (k=0; k<PITCH_SUBFRAMES; k++) { |
| tmp32b = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[3][k], (WebRtc_Word16) CQ10,10); |
| tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q7 |
| PitchLagsQ7[k] += tmp16c; |
| } |
| |
| /* entropy coding of quantization pitch lags */ |
| status = WebRtcIsacfix_EncHistMulti(streamdata, index, cdf, PITCH_SUBFRAMES); |
| |
| /* If error in WebRtcIsacfix_EncHistMulti(), status will be negative, otherwise 0 */ |
| return status; |
| } |
| |
| |
| |
| /* Routines for inband signaling of bandwitdh estimation */ |
| /* Histograms based on uniform distribution of indices */ |
| /* Move global variables later! */ |
| |
| |
| /* cdf array for frame length indicator */ |
| const WebRtc_UWord16 kFrameLenCdf[4] = { |
| 0, 21845, 43690, 65535}; |
| |
| /* pointer to cdf array for frame length indicator */ |
| const WebRtc_UWord16 *kFrameLenCdfPtr[1] = {kFrameLenCdf}; |
| |
| /* initial cdf index for decoder of frame length indicator */ |
| const WebRtc_UWord16 kFrameLenInitIndex[1] = {1}; |
| |
| |
| int WebRtcIsacfix_DecodeFrameLen(Bitstr_dec *streamdata, |
| WebRtc_Word16 *framesamples) |
| { |
| |
| int err; |
| WebRtc_Word16 frame_mode; |
| |
| err = 0; |
| /* entropy decoding of frame length [1:30ms,2:60ms] */ |
| err = WebRtcIsacfix_DecHistOneStepMulti(&frame_mode, streamdata, kFrameLenCdfPtr, kFrameLenInitIndex, 1); |
| if (err<0) // error check |
| return -ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH; |
| |
| switch(frame_mode) { |
| case 1: |
| *framesamples = 480; /* 30ms */ |
| break; |
| case 2: |
| *framesamples = 960; /* 60ms */ |
| break; |
| default: |
| err = -ISAC_DISALLOWED_FRAME_MODE_DECODER; |
| } |
| |
| return err; |
| } |
| |
| |
| int WebRtcIsacfix_EncodeFrameLen(WebRtc_Word16 framesamples, Bitstr_enc *streamdata) { |
| |
| int status; |
| WebRtc_Word16 frame_mode; |
| |
| status = 0; |
| frame_mode = 0; |
| /* entropy coding of frame length [1:480 samples,2:960 samples] */ |
| switch(framesamples) { |
| case 480: |
| frame_mode = 1; |
| break; |
| case 960: |
| frame_mode = 2; |
| break; |
| default: |
| status = - ISAC_DISALLOWED_FRAME_MODE_ENCODER; |
| } |
| |
| if (status < 0) |
| return status; |
| |
| status = WebRtcIsacfix_EncHistMulti(streamdata, &frame_mode, kFrameLenCdfPtr, 1); |
| |
| return status; |
| } |
| |
| /* cdf array for estimated bandwidth */ |
| const WebRtc_UWord16 kBwCdf[25] = { |
| 0, 2731, 5461, 8192, 10923, 13653, 16384, 19114, 21845, 24576, 27306, 30037, |
| 32768, 35498, 38229, 40959, 43690, 46421, 49151, 51882, 54613, 57343, 60074, |
| 62804, 65535}; |
| |
| /* pointer to cdf array for estimated bandwidth */ |
| const WebRtc_UWord16 *kBwCdfPtr[1] = {kBwCdf}; |
| |
| /* initial cdf index for decoder of estimated bandwidth*/ |
| const WebRtc_UWord16 kBwInitIndex[1] = {7}; |
| |
| |
| int WebRtcIsacfix_DecodeSendBandwidth(Bitstr_dec *streamdata, WebRtc_Word16 *BWno) { |
| |
| int err; |
| WebRtc_Word16 BWno32; |
| |
| /* entropy decoding of sender's BW estimation [0..23] */ |
| err = WebRtcIsacfix_DecHistOneStepMulti(&BWno32, streamdata, kBwCdfPtr, kBwInitIndex, 1); |
| if (err<0) // error check |
| return -ISAC_RANGE_ERROR_DECODE_BANDWIDTH; |
| *BWno = (WebRtc_Word16)BWno32; |
| return err; |
| |
| } |
| |
| |
| int WebRtcIsacfix_EncodeReceiveBandwidth(WebRtc_Word16 *BWno, Bitstr_enc *streamdata) |
| { |
| int status = 0; |
| /* entropy encoding of receiver's BW estimation [0..23] */ |
| status = WebRtcIsacfix_EncHistMulti(streamdata, BWno, kBwCdfPtr, 1); |
| |
| return status; |
| } |
| |
| /* estimate codel length of LPC Coef */ |
| void WebRtcIsacfix_TranscodeLpcCoef(WebRtc_Word32 *gain_lo_hiQ17, |
| WebRtc_Word16 *index_gQQ) { |
| int j, k, n; |
| WebRtc_Word16 posQQ, pos2QQ; |
| WebRtc_Word16 pos, pos2, posg, offsg, offs2, gainpos; |
| WebRtc_Word32 tmpcoeffs_gQ6[KLT_ORDER_GAIN]; |
| WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN]; |
| WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN]; |
| WebRtc_Word32 sumQQ; |
| |
| |
| /* log gains, mean removal and scaling */ |
| posg = 0;pos=0; gainpos=0; |
| |
| for (k=0; k<SUBFRAMES; k++) { |
| /* log gains */ |
| |
| /* The input argument X to logN(X) is 2^17 times higher than the |
| input floating point argument Y to log(Y), since the X value |
| is a Q17 value. This can be compensated for after the call, by |
| subraction a value Z for each Q-step. One Q-step means that |
| X gets 2 times higher, i.e. Z = logN(2)*256 = 0.693147180559*256 = |
| 177.445678 should be subtracted (since logN() returns a Q8 value). |
| For a X value in Q17, the value 177.445678*17 = 3017 should be |
| subtracted */ |
| tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 |
| tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 |
| posg++; gainpos++; |
| |
| tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 |
| tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 |
| posg++; gainpos++; |
| |
| } |
| |
| |
| /* KLT */ |
| |
| /* left transform */ |
| offsg = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| posg = offsg; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = offsg; |
| pos2 = k; |
| for (n=0; n<2; n++) { |
| sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[pos], WebRtcIsacfix_kT1GainQ15[0][pos2]); //Q21 = Q6*Q15 |
| pos++; |
| pos2 += 2; |
| } |
| tmpcoeffs2_gQ21[posg] = sumQQ; |
| posg++; |
| } |
| |
| offsg += 2; |
| } |
| |
| /* right transform */ |
| offsg = 0; |
| offs2 = 0; |
| for (j=0; j<SUBFRAMES; j++) { |
| posg = offsg; |
| for (k=0; k<2; k++) { |
| sumQQ = 0; |
| pos = k; |
| pos2 = offs2; |
| for (n=0; n<SUBFRAMES; n++) { |
| sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[0][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 |
| pos += 2; |
| pos2++; |
| } |
| tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); |
| posg++; |
| } |
| offsg += 2; |
| offs2 += SUBFRAMES; |
| } |
| |
| /* quantize coefficients */ |
| for (k=0; k<KLT_ORDER_GAIN; k++) //ATTN: ok? |
| { |
| posQQ = WebRtcIsacfix_kSelIndGain[k]; |
| pos2QQ= (WebRtc_Word16)CalcLrIntQ(tmpcoeffs_gQ17[posQQ], 17); |
| |
| index_gQQ[k] = pos2QQ + WebRtcIsacfix_kQuantMinGain[k]; //ATTN: ok? |
| if (index_gQQ[k] < 0) { |
| index_gQQ[k] = 0; |
| } |
| else if (index_gQQ[k] > WebRtcIsacfix_kMaxIndGain[k]) { |
| index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k]; |
| } |
| } |
| } |