niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 1 | /* |
| 2 | * SpanDSP - a series of DSP components for telephony |
| 3 | * |
| 4 | * g722_decode.c - The ITU G.722 codec, decode part. |
| 5 | * |
| 6 | * Written by Steve Underwood <steveu@coppice.org> |
| 7 | * |
| 8 | * Copyright (C) 2005 Steve Underwood |
| 9 | * |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 10 | * Despite my general liking of the GPL, I place my own contributions |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 11 | * to this code in the public domain for the benefit of all mankind - |
| 12 | * even the slimy ones who might try to proprietize my work and use it |
| 13 | * to my detriment. |
| 14 | * |
| 15 | * Based in part on a single channel G.722 codec which is: |
| 16 | * |
| 17 | * Copyright (c) CMU 1993 |
| 18 | * Computer Science, Speech Group |
| 19 | * Chengxiang Lu and Alex Hauptmann |
| 20 | * |
| 21 | * $Id: g722_decode.c,v 1.15 2006/07/07 16:37:49 steveu Exp $ |
| 22 | * |
| 23 | * Modifications for WebRtc, 2011/04/28, by tlegrand: |
| 24 | * -Removed usage of inttypes.h and tgmath.h |
| 25 | * -Changed to use WebRtc types |
| 26 | * -Changed __inline__ to __inline |
| 27 | * -Added saturation check on output |
| 28 | */ |
| 29 | |
| 30 | /*! \file */ |
| 31 | |
| 32 | |
henrike@webrtc.org | 1b8b4c4 | 2014-09-03 19:42:16 +0000 | [diff] [blame] | 33 | #include <memory.h> |
andresp@webrtc.org | 262e676 | 2014-09-04 13:28:48 +0000 | [diff] [blame] | 34 | #include <stdio.h> |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 35 | #include <stdlib.h> |
| 36 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 37 | #include "g722_enc_dec.h" |
Mirko Bonadei | 7120742 | 2017-09-15 13:58:09 +0200 | [diff] [blame] | 38 | #include "typedefs.h" // NOLINT(build/include) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 39 | |
| 40 | #if !defined(FALSE) |
| 41 | #define FALSE 0 |
| 42 | #endif |
| 43 | #if !defined(TRUE) |
| 44 | #define TRUE (!FALSE) |
| 45 | #endif |
| 46 | |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 47 | static __inline int16_t saturate(int32_t amp) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 48 | { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 49 | int16_t amp16; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 50 | |
| 51 | /* Hopefully this is optimised for the common case - not clipping */ |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 52 | amp16 = (int16_t) amp; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 53 | if (amp == amp16) |
| 54 | return amp16; |
| 55 | if (amp > WEBRTC_INT16_MAX) |
| 56 | return WEBRTC_INT16_MAX; |
| 57 | return WEBRTC_INT16_MIN; |
| 58 | } |
| 59 | /*- End of function --------------------------------------------------------*/ |
| 60 | |
pbos@webrtc.org | eb54446 | 2014-12-17 15:23:29 +0000 | [diff] [blame] | 61 | static void block4(G722DecoderState *s, int band, int d); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 62 | |
pbos@webrtc.org | eb54446 | 2014-12-17 15:23:29 +0000 | [diff] [blame] | 63 | static void block4(G722DecoderState *s, int band, int d) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 64 | { |
| 65 | int wd1; |
| 66 | int wd2; |
| 67 | int wd3; |
| 68 | int i; |
| 69 | |
| 70 | /* Block 4, RECONS */ |
| 71 | s->band[band].d[0] = d; |
| 72 | s->band[band].r[0] = saturate(s->band[band].s + d); |
| 73 | |
| 74 | /* Block 4, PARREC */ |
| 75 | s->band[band].p[0] = saturate(s->band[band].sz + d); |
| 76 | |
| 77 | /* Block 4, UPPOL2 */ |
| 78 | for (i = 0; i < 3; i++) |
| 79 | s->band[band].sg[i] = s->band[band].p[i] >> 15; |
kwiberg | bc80744 | 2016-10-31 02:26:10 -0700 | [diff] [blame] | 80 | wd1 = saturate(s->band[band].a[1] * 4); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 81 | |
| 82 | wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1; |
| 83 | if (wd2 > 32767) |
| 84 | wd2 = 32767; |
| 85 | wd3 = (s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128; |
| 86 | wd3 += (wd2 >> 7); |
| 87 | wd3 += (s->band[band].a[2]*32512) >> 15; |
| 88 | if (wd3 > 12288) |
| 89 | wd3 = 12288; |
| 90 | else if (wd3 < -12288) |
| 91 | wd3 = -12288; |
| 92 | s->band[band].ap[2] = wd3; |
| 93 | |
| 94 | /* Block 4, UPPOL1 */ |
| 95 | s->band[band].sg[0] = s->band[band].p[0] >> 15; |
| 96 | s->band[band].sg[1] = s->band[band].p[1] >> 15; |
| 97 | wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192; |
| 98 | wd2 = (s->band[band].a[1]*32640) >> 15; |
| 99 | |
| 100 | s->band[band].ap[1] = saturate(wd1 + wd2); |
| 101 | wd3 = saturate(15360 - s->band[band].ap[2]); |
| 102 | if (s->band[band].ap[1] > wd3) |
| 103 | s->band[band].ap[1] = wd3; |
| 104 | else if (s->band[band].ap[1] < -wd3) |
| 105 | s->band[band].ap[1] = -wd3; |
| 106 | |
| 107 | /* Block 4, UPZERO */ |
| 108 | wd1 = (d == 0) ? 0 : 128; |
| 109 | s->band[band].sg[0] = d >> 15; |
| 110 | for (i = 1; i < 7; i++) |
| 111 | { |
| 112 | s->band[band].sg[i] = s->band[band].d[i] >> 15; |
| 113 | wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1; |
| 114 | wd3 = (s->band[band].b[i]*32640) >> 15; |
| 115 | s->band[band].bp[i] = saturate(wd2 + wd3); |
| 116 | } |
| 117 | |
| 118 | /* Block 4, DELAYA */ |
| 119 | for (i = 6; i > 0; i--) |
| 120 | { |
| 121 | s->band[band].d[i] = s->band[band].d[i - 1]; |
| 122 | s->band[band].b[i] = s->band[band].bp[i]; |
| 123 | } |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 124 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 125 | for (i = 2; i > 0; i--) |
| 126 | { |
| 127 | s->band[band].r[i] = s->band[band].r[i - 1]; |
| 128 | s->band[band].p[i] = s->band[band].p[i - 1]; |
| 129 | s->band[band].a[i] = s->band[band].ap[i]; |
| 130 | } |
| 131 | |
| 132 | /* Block 4, FILTEP */ |
| 133 | wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]); |
| 134 | wd1 = (s->band[band].a[1]*wd1) >> 15; |
| 135 | wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]); |
| 136 | wd2 = (s->band[band].a[2]*wd2) >> 15; |
| 137 | s->band[band].sp = saturate(wd1 + wd2); |
| 138 | |
| 139 | /* Block 4, FILTEZ */ |
| 140 | s->band[band].sz = 0; |
| 141 | for (i = 6; i > 0; i--) |
| 142 | { |
| 143 | wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]); |
| 144 | s->band[band].sz += (s->band[band].b[i]*wd1) >> 15; |
| 145 | } |
| 146 | s->band[band].sz = saturate(s->band[band].sz); |
| 147 | |
| 148 | /* Block 4, PREDIC */ |
| 149 | s->band[band].s = saturate(s->band[band].sp + s->band[band].sz); |
| 150 | } |
| 151 | /*- End of function --------------------------------------------------------*/ |
| 152 | |
pbos@webrtc.org | eb54446 | 2014-12-17 15:23:29 +0000 | [diff] [blame] | 153 | G722DecoderState* WebRtc_g722_decode_init(G722DecoderState* s, |
| 154 | int rate, |
| 155 | int options) { |
Karl Wiberg | 4376648 | 2015-08-27 15:22:11 +0200 | [diff] [blame] | 156 | s = s ? s : malloc(sizeof(*s)); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 157 | memset(s, 0, sizeof(*s)); |
| 158 | if (rate == 48000) |
| 159 | s->bits_per_sample = 6; |
| 160 | else if (rate == 56000) |
| 161 | s->bits_per_sample = 7; |
| 162 | else |
| 163 | s->bits_per_sample = 8; |
| 164 | if ((options & G722_SAMPLE_RATE_8000)) |
| 165 | s->eight_k = TRUE; |
| 166 | if ((options & G722_PACKED) && s->bits_per_sample != 8) |
| 167 | s->packed = TRUE; |
| 168 | else |
| 169 | s->packed = FALSE; |
| 170 | s->band[0].det = 32; |
| 171 | s->band[1].det = 8; |
| 172 | return s; |
| 173 | } |
| 174 | /*- End of function --------------------------------------------------------*/ |
| 175 | |
pbos@webrtc.org | eb54446 | 2014-12-17 15:23:29 +0000 | [diff] [blame] | 176 | int WebRtc_g722_decode_release(G722DecoderState *s) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 177 | { |
| 178 | free(s); |
| 179 | return 0; |
| 180 | } |
| 181 | /*- End of function --------------------------------------------------------*/ |
| 182 | |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 183 | size_t WebRtc_g722_decode(G722DecoderState *s, int16_t amp[], |
| 184 | const uint8_t g722_data[], size_t len) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 185 | { |
| 186 | static const int wl[8] = {-60, -30, 58, 172, 334, 538, 1198, 3042 }; |
pwestin@webrtc.org | ebcb642 | 2011-12-22 12:20:06 +0000 | [diff] [blame] | 187 | static const int rl42[16] = {0, 7, 6, 5, 4, 3, 2, 1, |
| 188 | 7, 6, 5, 4, 3, 2, 1, 0 }; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 189 | static const int ilb[32] = |
| 190 | { |
| 191 | 2048, 2093, 2139, 2186, 2233, 2282, 2332, |
| 192 | 2383, 2435, 2489, 2543, 2599, 2656, 2714, |
| 193 | 2774, 2834, 2896, 2960, 3025, 3091, 3158, |
| 194 | 3228, 3298, 3371, 3444, 3520, 3597, 3676, |
| 195 | 3756, 3838, 3922, 4008 |
| 196 | }; |
| 197 | static const int wh[3] = {0, -214, 798}; |
| 198 | static const int rh2[4] = {2, 1, 2, 1}; |
| 199 | static const int qm2[4] = {-7408, -1616, 7408, 1616}; |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 200 | static const int qm4[16] = |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 201 | { |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 202 | 0, -20456, -12896, -8968, |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 203 | -6288, -4240, -2584, -1200, |
| 204 | 20456, 12896, 8968, 6288, |
| 205 | 4240, 2584, 1200, 0 |
| 206 | }; |
| 207 | static const int qm5[32] = |
| 208 | { |
| 209 | -280, -280, -23352, -17560, |
| 210 | -14120, -11664, -9752, -8184, |
| 211 | -6864, -5712, -4696, -3784, |
| 212 | -2960, -2208, -1520, -880, |
| 213 | 23352, 17560, 14120, 11664, |
| 214 | 9752, 8184, 6864, 5712, |
| 215 | 4696, 3784, 2960, 2208, |
| 216 | 1520, 880, 280, -280 |
| 217 | }; |
| 218 | static const int qm6[64] = |
| 219 | { |
| 220 | -136, -136, -136, -136, |
| 221 | -24808, -21904, -19008, -16704, |
| 222 | -14984, -13512, -12280, -11192, |
| 223 | -10232, -9360, -8576, -7856, |
| 224 | -7192, -6576, -6000, -5456, |
| 225 | -4944, -4464, -4008, -3576, |
| 226 | -3168, -2776, -2400, -2032, |
| 227 | -1688, -1360, -1040, -728, |
| 228 | 24808, 21904, 19008, 16704, |
| 229 | 14984, 13512, 12280, 11192, |
| 230 | 10232, 9360, 8576, 7856, |
| 231 | 7192, 6576, 6000, 5456, |
| 232 | 4944, 4464, 4008, 3576, |
| 233 | 3168, 2776, 2400, 2032, |
| 234 | 1688, 1360, 1040, 728, |
| 235 | 432, 136, -432, -136 |
| 236 | }; |
| 237 | static const int qmf_coeffs[12] = |
| 238 | { |
| 239 | 3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11, |
| 240 | }; |
| 241 | |
| 242 | int dlowt; |
| 243 | int rlow; |
| 244 | int ihigh; |
| 245 | int dhigh; |
| 246 | int rhigh; |
| 247 | int xout1; |
| 248 | int xout2; |
| 249 | int wd1; |
| 250 | int wd2; |
| 251 | int wd3; |
| 252 | int code; |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 253 | size_t outlen; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 254 | int i; |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 255 | size_t j; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 256 | |
| 257 | outlen = 0; |
| 258 | rhigh = 0; |
| 259 | for (j = 0; j < len; ) |
| 260 | { |
| 261 | if (s->packed) |
| 262 | { |
| 263 | /* Unpack the code bits */ |
| 264 | if (s->in_bits < s->bits_per_sample) |
| 265 | { |
| 266 | s->in_buffer |= (g722_data[j++] << s->in_bits); |
| 267 | s->in_bits += 8; |
| 268 | } |
| 269 | code = s->in_buffer & ((1 << s->bits_per_sample) - 1); |
| 270 | s->in_buffer >>= s->bits_per_sample; |
| 271 | s->in_bits -= s->bits_per_sample; |
| 272 | } |
| 273 | else |
| 274 | { |
| 275 | code = g722_data[j++]; |
| 276 | } |
| 277 | |
| 278 | switch (s->bits_per_sample) |
| 279 | { |
| 280 | default: |
| 281 | case 8: |
| 282 | wd1 = code & 0x3F; |
| 283 | ihigh = (code >> 6) & 0x03; |
| 284 | wd2 = qm6[wd1]; |
| 285 | wd1 >>= 2; |
| 286 | break; |
| 287 | case 7: |
| 288 | wd1 = code & 0x1F; |
| 289 | ihigh = (code >> 5) & 0x03; |
| 290 | wd2 = qm5[wd1]; |
| 291 | wd1 >>= 1; |
| 292 | break; |
| 293 | case 6: |
| 294 | wd1 = code & 0x0F; |
| 295 | ihigh = (code >> 4) & 0x03; |
| 296 | wd2 = qm4[wd1]; |
| 297 | break; |
| 298 | } |
| 299 | /* Block 5L, LOW BAND INVQBL */ |
| 300 | wd2 = (s->band[0].det*wd2) >> 15; |
| 301 | /* Block 5L, RECONS */ |
| 302 | rlow = s->band[0].s + wd2; |
| 303 | /* Block 6L, LIMIT */ |
| 304 | if (rlow > 16383) |
| 305 | rlow = 16383; |
| 306 | else if (rlow < -16384) |
| 307 | rlow = -16384; |
| 308 | |
| 309 | /* Block 2L, INVQAL */ |
| 310 | wd2 = qm4[wd1]; |
| 311 | dlowt = (s->band[0].det*wd2) >> 15; |
| 312 | |
| 313 | /* Block 3L, LOGSCL */ |
| 314 | wd2 = rl42[wd1]; |
| 315 | wd1 = (s->band[0].nb*127) >> 7; |
| 316 | wd1 += wl[wd2]; |
| 317 | if (wd1 < 0) |
| 318 | wd1 = 0; |
| 319 | else if (wd1 > 18432) |
| 320 | wd1 = 18432; |
| 321 | s->band[0].nb = wd1; |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 322 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 323 | /* Block 3L, SCALEL */ |
| 324 | wd1 = (s->band[0].nb >> 6) & 31; |
| 325 | wd2 = 8 - (s->band[0].nb >> 11); |
| 326 | wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); |
| 327 | s->band[0].det = wd3 << 2; |
| 328 | |
| 329 | block4(s, 0, dlowt); |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 330 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 331 | if (!s->eight_k) |
| 332 | { |
| 333 | /* Block 2H, INVQAH */ |
| 334 | wd2 = qm2[ihigh]; |
| 335 | dhigh = (s->band[1].det*wd2) >> 15; |
| 336 | /* Block 5H, RECONS */ |
| 337 | rhigh = dhigh + s->band[1].s; |
| 338 | /* Block 6H, LIMIT */ |
| 339 | if (rhigh > 16383) |
| 340 | rhigh = 16383; |
| 341 | else if (rhigh < -16384) |
| 342 | rhigh = -16384; |
| 343 | |
| 344 | /* Block 2H, INVQAH */ |
| 345 | wd2 = rh2[ihigh]; |
| 346 | wd1 = (s->band[1].nb*127) >> 7; |
| 347 | wd1 += wh[wd2]; |
| 348 | if (wd1 < 0) |
| 349 | wd1 = 0; |
| 350 | else if (wd1 > 22528) |
| 351 | wd1 = 22528; |
| 352 | s->band[1].nb = wd1; |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 353 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 354 | /* Block 3H, SCALEH */ |
| 355 | wd1 = (s->band[1].nb >> 6) & 31; |
| 356 | wd2 = 10 - (s->band[1].nb >> 11); |
| 357 | wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); |
| 358 | s->band[1].det = wd3 << 2; |
| 359 | |
| 360 | block4(s, 1, dhigh); |
| 361 | } |
| 362 | |
| 363 | if (s->itu_test_mode) |
| 364 | { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 365 | amp[outlen++] = (int16_t) (rlow << 1); |
| 366 | amp[outlen++] = (int16_t) (rhigh << 1); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 367 | } |
| 368 | else |
| 369 | { |
| 370 | if (s->eight_k) |
| 371 | { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 372 | amp[outlen++] = (int16_t) (rlow << 1); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 373 | } |
| 374 | else |
| 375 | { |
| 376 | /* Apply the receive QMF */ |
| 377 | for (i = 0; i < 22; i++) |
| 378 | s->x[i] = s->x[i + 2]; |
| 379 | s->x[22] = rlow + rhigh; |
| 380 | s->x[23] = rlow - rhigh; |
| 381 | |
| 382 | xout1 = 0; |
| 383 | xout2 = 0; |
| 384 | for (i = 0; i < 12; i++) |
| 385 | { |
| 386 | xout2 += s->x[2*i]*qmf_coeffs[i]; |
| 387 | xout1 += s->x[2*i + 1]*qmf_coeffs[11 - i]; |
| 388 | } |
| 389 | /* We shift by 12 to allow for the QMF filters (DC gain = 4096), less 1 |
| 390 | to allow for the 15 bit input to the G.722 algorithm. */ |
| 391 | /* WebRtc, tlegrand: added saturation */ |
| 392 | amp[outlen++] = saturate(xout1 >> 11); |
| 393 | amp[outlen++] = saturate(xout2 >> 11); |
| 394 | } |
| 395 | } |
| 396 | } |
| 397 | return outlen; |
| 398 | } |
| 399 | /*- End of function --------------------------------------------------------*/ |
| 400 | /*- End of file ------------------------------------------------------------*/ |