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