niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | /****************************************************************** |
| 12 | |
| 13 | iLBC Speech Coder ANSI-C Source Code |
| 14 | |
| 15 | WebRtcIlbcfix_Smooth.c |
| 16 | |
| 17 | ******************************************************************/ |
| 18 | |
| 19 | #include "defines.h" |
| 20 | #include "constants.h" |
| 21 | #include "smooth_out_data.h" |
| 22 | |
| 23 | /*----------------------------------------------------------------* |
| 24 | * find the smoothed output data |
| 25 | *---------------------------------------------------------------*/ |
| 26 | |
| 27 | void WebRtcIlbcfix_Smooth( |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 28 | int16_t *odata, /* (o) smoothed output */ |
| 29 | int16_t *current, /* (i) the un enhanced residual for |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 30 | this block */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 31 | int16_t *surround /* (i) The approximation from the |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 32 | surrounding sequences */ |
| 33 | ) { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 34 | int16_t maxtot, scale, scale1, scale2; |
| 35 | int16_t A, B, C, denomW16; |
| 36 | int32_t B_W32, denom, num; |
| 37 | int32_t errs; |
| 38 | int32_t w00,w10,w11, endiff, crit; |
| 39 | int32_t w00prim, w10prim, w11_div_w00; |
| 40 | int16_t w11prim; |
| 41 | int16_t bitsw00, bitsw10, bitsw11; |
| 42 | int32_t w11w00, w10w10, w00w00; |
| 43 | int16_t max1, max2; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 44 | |
| 45 | /* compute some inner products (ensure no overflow by first calculating proper scale factor) */ |
| 46 | |
| 47 | w00 = w10 = w11 = 0; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 48 | |
| 49 | max1=WebRtcSpl_MaxAbsValueW16(current, ENH_BLOCKL); |
| 50 | max2=WebRtcSpl_MaxAbsValueW16(surround, ENH_BLOCKL); |
| 51 | maxtot=WEBRTC_SPL_MAX(max1, max2); |
| 52 | |
| 53 | scale=WebRtcSpl_GetSizeInBits(maxtot); |
bjornv@webrtc.org | ba97ea6 | 2015-02-13 09:51:40 +0000 | [diff] [blame^] | 54 | scale = (int16_t)(2 * scale) - 26; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 55 | scale=WEBRTC_SPL_MAX(0, scale); |
| 56 | |
| 57 | w00=WebRtcSpl_DotProductWithScale(current,current,ENH_BLOCKL,scale); |
| 58 | w11=WebRtcSpl_DotProductWithScale(surround,surround,ENH_BLOCKL,scale); |
| 59 | w10=WebRtcSpl_DotProductWithScale(surround,current,ENH_BLOCKL,scale); |
| 60 | |
| 61 | if (w00<0) w00 = WEBRTC_SPL_WORD32_MAX; |
| 62 | if (w11<0) w11 = WEBRTC_SPL_WORD32_MAX; |
| 63 | |
| 64 | /* Rescale w00 and w11 to w00prim and w11prim, so that w00prim/w11prim |
| 65 | is in Q16 */ |
| 66 | |
| 67 | bitsw00 = WebRtcSpl_GetSizeInBits(w00); |
| 68 | bitsw11 = WebRtcSpl_GetSizeInBits(w11); |
| 69 | bitsw10 = WebRtcSpl_GetSizeInBits(WEBRTC_SPL_ABS_W32(w10)); |
| 70 | scale1 = 31 - bitsw00; |
| 71 | scale2 = 15 - bitsw11; |
| 72 | |
| 73 | if (scale2>(scale1-16)) { |
| 74 | scale2 = scale1 - 16; |
| 75 | } else { |
| 76 | scale1 = scale2 + 16; |
| 77 | } |
| 78 | |
| 79 | w00prim = WEBRTC_SPL_LSHIFT_W32(w00, scale1); |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 80 | w11prim = (int16_t) WEBRTC_SPL_SHIFT_W32(w11, scale2); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 81 | |
| 82 | /* Perform C = sqrt(w11/w00) (C is in Q11 since (16+6)/2=11) */ |
| 83 | if (w11prim>64) { |
| 84 | endiff = WEBRTC_SPL_LSHIFT_W32( |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 85 | (int32_t)WebRtcSpl_DivW32W16(w00prim, w11prim), 6); |
| 86 | C = (int16_t)WebRtcSpl_SqrtFloor(endiff); /* C is in Q11 */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 87 | } else { |
| 88 | C = 1; |
| 89 | } |
| 90 | |
| 91 | /* first try enhancement without power-constraint */ |
| 92 | |
| 93 | errs = WebRtcIlbcfix_Smooth_odata(odata, current, surround, C); |
| 94 | |
| 95 | |
| 96 | |
| 97 | /* if constraint violated by first try, add constraint */ |
| 98 | |
| 99 | if ( (6-scale+scale1) > 31) { |
| 100 | crit=0; |
| 101 | } else { |
| 102 | /* crit = 0.05 * w00 (Result in Q-6) */ |
| 103 | crit = WEBRTC_SPL_SHIFT_W32( |
bjornv@webrtc.org | 78ea06d | 2014-10-21 07:17:24 +0000 | [diff] [blame] | 104 | WEBRTC_SPL_MUL(ENH_A0, w00prim >> 14), |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 105 | -(6-scale+scale1)); |
| 106 | } |
| 107 | |
| 108 | if (errs > crit) { |
| 109 | |
| 110 | if( w00 < 1) { |
| 111 | w00=1; |
| 112 | } |
| 113 | |
| 114 | /* Calculate w11*w00, w10*w10 and w00*w00 in the same Q domain */ |
| 115 | |
| 116 | scale1 = bitsw00-15; |
| 117 | scale2 = bitsw11-15; |
| 118 | |
| 119 | if (scale2>scale1) { |
| 120 | scale = scale2; |
| 121 | } else { |
| 122 | scale = scale1; |
| 123 | } |
| 124 | |
bjornv@webrtc.org | ba97ea6 | 2015-02-13 09:51:40 +0000 | [diff] [blame^] | 125 | w11w00 = (int16_t)WEBRTC_SPL_SHIFT_W32(w11, -scale) * |
| 126 | (int16_t)WEBRTC_SPL_SHIFT_W32(w00, -scale); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 127 | |
bjornv@webrtc.org | ba97ea6 | 2015-02-13 09:51:40 +0000 | [diff] [blame^] | 128 | w10w10 = (int16_t)WEBRTC_SPL_SHIFT_W32(w10, -scale) * |
| 129 | (int16_t)WEBRTC_SPL_SHIFT_W32(w10, -scale); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 130 | |
bjornv@webrtc.org | ba97ea6 | 2015-02-13 09:51:40 +0000 | [diff] [blame^] | 131 | w00w00 = (int16_t)WEBRTC_SPL_SHIFT_W32(w00, -scale) * |
| 132 | (int16_t)WEBRTC_SPL_SHIFT_W32(w00, -scale); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 133 | |
| 134 | /* Calculate (w11*w00-w10*w10)/(w00*w00) in Q16 */ |
| 135 | if (w00w00>65536) { |
| 136 | endiff = (w11w00-w10w10); |
| 137 | endiff = WEBRTC_SPL_MAX(0, endiff); |
| 138 | /* denom is in Q16 */ |
bjornv@webrtc.org | 78ea06d | 2014-10-21 07:17:24 +0000 | [diff] [blame] | 139 | denom = WebRtcSpl_DivW32W16(endiff, (int16_t)(w00w00 >> 16)); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 140 | } else { |
| 141 | denom = 65536; |
| 142 | } |
| 143 | |
| 144 | if( denom > 7){ /* eliminates numerical problems |
| 145 | for if smooth */ |
| 146 | |
| 147 | scale=WebRtcSpl_GetSizeInBits(denom)-15; |
| 148 | |
| 149 | if (scale>0) { |
| 150 | /* denomW16 is in Q(16+scale) */ |
bjornv@webrtc.org | 78ea06d | 2014-10-21 07:17:24 +0000 | [diff] [blame] | 151 | denomW16 = (int16_t)(denom >> scale); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 152 | |
| 153 | /* num in Q(34-scale) */ |
bjornv@webrtc.org | 78ea06d | 2014-10-21 07:17:24 +0000 | [diff] [blame] | 154 | num = ENH_A0_MINUS_A0A0DIV4 >> scale; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 155 | } else { |
| 156 | /* denomW16 is in Q16 */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 157 | denomW16=(int16_t)denom; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 158 | |
| 159 | /* num in Q34 */ |
| 160 | num=ENH_A0_MINUS_A0A0DIV4; |
| 161 | } |
| 162 | |
| 163 | /* A sqrt( (ENH_A0-(ENH_A0^2)/4)*(w00*w00)/(w11*w00 + w10*w10) ) in Q9 */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 164 | A = (int16_t)WebRtcSpl_SqrtFloor(WebRtcSpl_DivW32W16(num, denomW16)); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 165 | |
| 166 | /* B_W32 is in Q30 ( B = 1 - ENH_A0/2 - A * w10/w00 ) */ |
| 167 | scale1 = 31-bitsw10; |
| 168 | scale2 = 21-scale1; |
| 169 | w10prim = WEBRTC_SPL_LSHIFT_W32(w10, scale1); |
| 170 | w00prim = WEBRTC_SPL_SHIFT_W32(w00, -scale2); |
| 171 | scale = bitsw00-scale2-15; |
| 172 | |
| 173 | if (scale>0) { |
bjornv@webrtc.org | 78ea06d | 2014-10-21 07:17:24 +0000 | [diff] [blame] | 174 | w10prim >>= scale; |
| 175 | w00prim >>= scale; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | if ((w00prim>0)&&(w10prim>0)) { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 179 | w11_div_w00=WebRtcSpl_DivW32W16(w10prim, (int16_t)w00prim); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 180 | |
| 181 | if (WebRtcSpl_GetSizeInBits(w11_div_w00)+WebRtcSpl_GetSizeInBits(A)>31) { |
| 182 | B_W32 = 0; |
| 183 | } else { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 184 | B_W32 = (int32_t)1073741824 - (int32_t)ENH_A0DIV2 - |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 185 | WEBRTC_SPL_MUL(A, w11_div_w00); |
| 186 | } |
bjornv@webrtc.org | 78ea06d | 2014-10-21 07:17:24 +0000 | [diff] [blame] | 187 | B = (int16_t)(B_W32 >> 16); /* B in Q14. */ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 188 | } else { |
| 189 | /* No smoothing */ |
| 190 | A = 0; |
| 191 | B = 16384; /* 1 in Q14 */ |
| 192 | } |
| 193 | } |
| 194 | else{ /* essentially no difference between cycles; |
| 195 | smoothing not needed */ |
| 196 | |
| 197 | A = 0; |
| 198 | B = 16384; /* 1 in Q14 */ |
| 199 | } |
| 200 | |
| 201 | /* create smoothed sequence */ |
| 202 | |
| 203 | WebRtcSpl_ScaleAndAddVectors(surround, A, 9, |
| 204 | current, B, 14, |
| 205 | odata, ENH_BLOCKL); |
| 206 | } |
| 207 | return; |
| 208 | } |