/* * 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. */ /****************************************************************** iLBC Speech Coder ANSI-C Source Code WebRtcIlbcfix_Smooth.c ******************************************************************/ #include "defines.h" #include "constants.h" #include "smooth_out_data.h" /*----------------------------------------------------------------* * find the smoothed output data *---------------------------------------------------------------*/ void WebRtcIlbcfix_Smooth( int16_t *odata, /* (o) smoothed output */ int16_t *current, /* (i) the un enhanced residual for this block */ int16_t *surround /* (i) The approximation from the surrounding sequences */ ) { int16_t maxtot, scale, scale1, scale2; int16_t A, B, C, denomW16; int32_t B_W32, denom, num; int32_t errs; int32_t w00,w10,w11, endiff, crit; int32_t w00prim, w10prim, w11_div_w00; int16_t w11prim; int16_t bitsw00, bitsw10, bitsw11; int32_t w11w00, w10w10, w00w00; int16_t max1, max2; /* compute some inner products (ensure no overflow by first calculating proper scale factor) */ w00 = w10 = w11 = 0; max1=WebRtcSpl_MaxAbsValueW16(current, ENH_BLOCKL); max2=WebRtcSpl_MaxAbsValueW16(surround, ENH_BLOCKL); maxtot=WEBRTC_SPL_MAX(max1, max2); scale=WebRtcSpl_GetSizeInBits(maxtot); scale = (int16_t)(2 * scale) - 26; scale=WEBRTC_SPL_MAX(0, scale); w00=WebRtcSpl_DotProductWithScale(current,current,ENH_BLOCKL,scale); w11=WebRtcSpl_DotProductWithScale(surround,surround,ENH_BLOCKL,scale); w10=WebRtcSpl_DotProductWithScale(surround,current,ENH_BLOCKL,scale); if (w00<0) w00 = WEBRTC_SPL_WORD32_MAX; if (w11<0) w11 = WEBRTC_SPL_WORD32_MAX; /* Rescale w00 and w11 to w00prim and w11prim, so that w00prim/w11prim is in Q16 */ bitsw00 = WebRtcSpl_GetSizeInBits(w00); bitsw11 = WebRtcSpl_GetSizeInBits(w11); bitsw10 = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(w10)); scale1 = 31 - bitsw00; scale2 = 15 - bitsw11; if (scale2>(scale1-16)) { scale2 = scale1 - 16; } else { scale1 = scale2 + 16; } w00prim = w00 << scale1; w11prim = (int16_t) WEBRTC_SPL_SHIFT_W32(w11, scale2); /* Perform C = sqrt(w11/w00) (C is in Q11 since (16+6)/2=11) */ if (w11prim>64) { endiff = WebRtcSpl_DivW32W16(w00prim, w11prim) << 6; C = (int16_t)WebRtcSpl_SqrtFloor(endiff); /* C is in Q11 */ } else { C = 1; } /* first try enhancement without power-constraint */ errs = WebRtcIlbcfix_Smooth_odata(odata, current, surround, C); /* if constraint violated by first try, add constraint */ if ( (6-scale+scale1) > 31) { crit=0; } else { /* crit = 0.05 * w00 (Result in Q-6) */ crit = WEBRTC_SPL_SHIFT_W32( WEBRTC_SPL_MUL(ENH_A0, w00prim >> 14), -(6-scale+scale1)); } if (errs > crit) { if( w00 < 1) { w00=1; } /* Calculate w11*w00, w10*w10 and w00*w00 in the same Q domain */ scale1 = bitsw00-15; scale2 = bitsw11-15; if (scale2>scale1) { scale = scale2; } else { scale = scale1; } w11w00 = (int16_t)WEBRTC_SPL_SHIFT_W32(w11, -scale) * (int16_t)WEBRTC_SPL_SHIFT_W32(w00, -scale); w10w10 = (int16_t)WEBRTC_SPL_SHIFT_W32(w10, -scale) * (int16_t)WEBRTC_SPL_SHIFT_W32(w10, -scale); w00w00 = (int16_t)WEBRTC_SPL_SHIFT_W32(w00, -scale) * (int16_t)WEBRTC_SPL_SHIFT_W32(w00, -scale); /* Calculate (w11*w00-w10*w10)/(w00*w00) in Q16 */ if (w00w00>65536) { endiff = (w11w00-w10w10); endiff = WEBRTC_SPL_MAX(0, endiff); /* denom is in Q16 */ denom = WebRtcSpl_DivW32W16(endiff, (int16_t)(w00w00 >> 16)); } else { denom = 65536; } if( denom > 7){ /* eliminates numerical problems for if smooth */ scale=WebRtcSpl_GetSizeInBits(denom)-15; if (scale>0) { /* denomW16 is in Q(16+scale) */ denomW16 = (int16_t)(denom >> scale); /* num in Q(34-scale) */ num = ENH_A0_MINUS_A0A0DIV4 >> scale; } else { /* denomW16 is in Q16 */ denomW16=(int16_t)denom; /* num in Q34 */ num=ENH_A0_MINUS_A0A0DIV4; } /* A sqrt( (ENH_A0-(ENH_A0^2)/4)*(w00*w00)/(w11*w00 + w10*w10) ) in Q9 */ A = (int16_t)WebRtcSpl_SqrtFloor(WebRtcSpl_DivW32W16(num, denomW16)); /* B_W32 is in Q30 ( B = 1 - ENH_A0/2 - A * w10/w00 ) */ scale1 = 31-bitsw10; scale2 = 21-scale1; w10prim = w10 << scale1; w00prim = WEBRTC_SPL_SHIFT_W32(w00, -scale2); scale = bitsw00-scale2-15; if (scale>0) { w10prim >>= scale; w00prim >>= scale; } if ((w00prim>0)&&(w10prim>0)) { w11_div_w00=WebRtcSpl_DivW32W16(w10prim, (int16_t)w00prim); if (WebRtcSpl_GetSizeInBits(w11_div_w00)+WebRtcSpl_GetSizeInBits(A)>31) { B_W32 = 0; } else { B_W32 = (int32_t)1073741824 - (int32_t)ENH_A0DIV2 - WEBRTC_SPL_MUL(A, w11_div_w00); } B = (int16_t)(B_W32 >> 16); /* B in Q14. */ } else { /* No smoothing */ A = 0; B = 16384; /* 1 in Q14 */ } } else{ /* essentially no difference between cycles; smoothing not needed */ A = 0; B = 16384; /* 1 in Q14 */ } /* create smoothed sequence */ WebRtcSpl_ScaleAndAddVectors(surround, A, 9, current, B, 14, odata, ENH_BLOCKL); } return; }