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_encode.c - The ITU G.722 codec, encode part. |
| 5 | * |
| 6 | * Written by Steve Underwood <steveu@coppice.org> |
| 7 | * |
| 8 | * Copyright (C) 2005 Steve Underwood |
| 9 | * |
| 10 | * All rights reserved. |
| 11 | * |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 12 | * 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] | 13 | * to this code in the public domain for the benefit of all mankind - |
| 14 | * even the slimy ones who might try to proprietize my work and use it |
| 15 | * to my detriment. |
| 16 | * |
| 17 | * Based on a single channel 64kbps only G.722 codec which is: |
| 18 | * |
| 19 | ***** Copyright (c) CMU 1993 ***** |
| 20 | * Computer Science, Speech Group |
| 21 | * Chengxiang Lu and Alex Hauptmann |
| 22 | * |
| 23 | * $Id: g722_encode.c,v 1.14 2006/07/07 16:37:49 steveu Exp $ |
| 24 | * |
| 25 | * Modifications for WebRtc, 2011/04/28, by tlegrand: |
| 26 | * -Removed usage of inttypes.h and tgmath.h |
| 27 | * -Changed to use WebRtc types |
| 28 | * -Added option to run encoder bitexact with ITU-T reference implementation |
| 29 | */ |
| 30 | |
| 31 | /*! \file */ |
| 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(G722EncoderState *s, int band, int d) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 62 | { |
| 63 | int wd1; |
| 64 | int wd2; |
| 65 | int wd3; |
| 66 | int i; |
| 67 | |
| 68 | /* Block 4, RECONS */ |
| 69 | s->band[band].d[0] = d; |
| 70 | s->band[band].r[0] = saturate(s->band[band].s + d); |
| 71 | |
| 72 | /* Block 4, PARREC */ |
| 73 | s->band[band].p[0] = saturate(s->band[band].sz + d); |
| 74 | |
| 75 | /* Block 4, UPPOL2 */ |
| 76 | for (i = 0; i < 3; i++) |
| 77 | s->band[band].sg[i] = s->band[band].p[i] >> 15; |
| 78 | wd1 = saturate(s->band[band].a[1] << 2); |
| 79 | |
| 80 | wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1; |
| 81 | if (wd2 > 32767) |
| 82 | wd2 = 32767; |
| 83 | wd3 = (wd2 >> 7) + ((s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128); |
| 84 | wd3 += (s->band[band].a[2]*32512) >> 15; |
| 85 | if (wd3 > 12288) |
| 86 | wd3 = 12288; |
| 87 | else if (wd3 < -12288) |
| 88 | wd3 = -12288; |
| 89 | s->band[band].ap[2] = wd3; |
| 90 | |
| 91 | /* Block 4, UPPOL1 */ |
| 92 | s->band[band].sg[0] = s->band[band].p[0] >> 15; |
| 93 | s->band[band].sg[1] = s->band[band].p[1] >> 15; |
| 94 | wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192; |
| 95 | wd2 = (s->band[band].a[1]*32640) >> 15; |
| 96 | |
| 97 | s->band[band].ap[1] = saturate(wd1 + wd2); |
| 98 | wd3 = saturate(15360 - s->band[band].ap[2]); |
| 99 | if (s->band[band].ap[1] > wd3) |
| 100 | s->band[band].ap[1] = wd3; |
| 101 | else if (s->band[band].ap[1] < -wd3) |
| 102 | s->band[band].ap[1] = -wd3; |
| 103 | |
| 104 | /* Block 4, UPZERO */ |
| 105 | wd1 = (d == 0) ? 0 : 128; |
| 106 | s->band[band].sg[0] = d >> 15; |
| 107 | for (i = 1; i < 7; i++) |
| 108 | { |
| 109 | s->band[band].sg[i] = s->band[band].d[i] >> 15; |
| 110 | wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1; |
| 111 | wd3 = (s->band[band].b[i]*32640) >> 15; |
| 112 | s->band[band].bp[i] = saturate(wd2 + wd3); |
| 113 | } |
| 114 | |
| 115 | /* Block 4, DELAYA */ |
| 116 | for (i = 6; i > 0; i--) |
| 117 | { |
| 118 | s->band[band].d[i] = s->band[band].d[i - 1]; |
| 119 | s->band[band].b[i] = s->band[band].bp[i]; |
| 120 | } |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 121 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 122 | for (i = 2; i > 0; i--) |
| 123 | { |
| 124 | s->band[band].r[i] = s->band[band].r[i - 1]; |
| 125 | s->band[band].p[i] = s->band[band].p[i - 1]; |
| 126 | s->band[band].a[i] = s->band[band].ap[i]; |
| 127 | } |
| 128 | |
| 129 | /* Block 4, FILTEP */ |
| 130 | wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]); |
| 131 | wd1 = (s->band[band].a[1]*wd1) >> 15; |
| 132 | wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]); |
| 133 | wd2 = (s->band[band].a[2]*wd2) >> 15; |
| 134 | s->band[band].sp = saturate(wd1 + wd2); |
| 135 | |
| 136 | /* Block 4, FILTEZ */ |
| 137 | s->band[band].sz = 0; |
| 138 | for (i = 6; i > 0; i--) |
| 139 | { |
| 140 | wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]); |
| 141 | s->band[band].sz += (s->band[band].b[i]*wd1) >> 15; |
| 142 | } |
| 143 | s->band[band].sz = saturate(s->band[band].sz); |
| 144 | |
| 145 | /* Block 4, PREDIC */ |
| 146 | s->band[band].s = saturate(s->band[band].sp + s->band[band].sz); |
| 147 | } |
| 148 | /*- End of function --------------------------------------------------------*/ |
| 149 | |
pbos@webrtc.org | eb54446 | 2014-12-17 15:23:29 +0000 | [diff] [blame] | 150 | G722EncoderState* WebRtc_g722_encode_init(G722EncoderState* s, |
| 151 | int rate, |
| 152 | int options) { |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 153 | if (s == NULL) |
| 154 | { |
pbos@webrtc.org | eb54446 | 2014-12-17 15:23:29 +0000 | [diff] [blame] | 155 | if ((s = (G722EncoderState *) malloc(sizeof(*s))) == NULL) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 156 | return NULL; |
| 157 | } |
| 158 | memset(s, 0, sizeof(*s)); |
| 159 | if (rate == 48000) |
| 160 | s->bits_per_sample = 6; |
| 161 | else if (rate == 56000) |
| 162 | s->bits_per_sample = 7; |
| 163 | else |
| 164 | s->bits_per_sample = 8; |
| 165 | if ((options & G722_SAMPLE_RATE_8000)) |
| 166 | s->eight_k = TRUE; |
| 167 | if ((options & G722_PACKED) && s->bits_per_sample != 8) |
| 168 | s->packed = TRUE; |
| 169 | else |
| 170 | s->packed = FALSE; |
| 171 | s->band[0].det = 32; |
| 172 | s->band[1].det = 8; |
| 173 | return s; |
| 174 | } |
| 175 | /*- End of function --------------------------------------------------------*/ |
| 176 | |
pbos@webrtc.org | eb54446 | 2014-12-17 15:23:29 +0000 | [diff] [blame] | 177 | int WebRtc_g722_encode_release(G722EncoderState *s) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 178 | { |
| 179 | free(s); |
| 180 | return 0; |
| 181 | } |
| 182 | /*- End of function --------------------------------------------------------*/ |
| 183 | |
| 184 | /* WebRtc, tlegrand: |
| 185 | * Only define the following if bit-exactness with reference implementation |
| 186 | * is needed. Will only have any effect if input signal is saturated. |
| 187 | */ |
| 188 | //#define RUN_LIKE_REFERENCE_G722 |
| 189 | #ifdef RUN_LIKE_REFERENCE_G722 |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 190 | int16_t limitValues (int16_t rl) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 191 | { |
| 192 | |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 193 | int16_t yl; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 194 | |
| 195 | yl = (rl > 16383) ? 16383 : ((rl < -16384) ? -16384 : rl); |
| 196 | |
| 197 | return (yl); |
| 198 | } |
| 199 | #endif |
| 200 | |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 201 | size_t WebRtc_g722_encode(G722EncoderState *s, uint8_t g722_data[], |
| 202 | const int16_t amp[], size_t len) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 203 | { |
| 204 | static const int q6[32] = |
| 205 | { |
| 206 | 0, 35, 72, 110, 150, 190, 233, 276, |
| 207 | 323, 370, 422, 473, 530, 587, 650, 714, |
| 208 | 786, 858, 940, 1023, 1121, 1219, 1339, 1458, |
| 209 | 1612, 1765, 1980, 2195, 2557, 2919, 0, 0 |
| 210 | }; |
| 211 | static const int iln[32] = |
| 212 | { |
| 213 | 0, 63, 62, 31, 30, 29, 28, 27, |
| 214 | 26, 25, 24, 23, 22, 21, 20, 19, |
| 215 | 18, 17, 16, 15, 14, 13, 12, 11, |
| 216 | 10, 9, 8, 7, 6, 5, 4, 0 |
| 217 | }; |
| 218 | static const int ilp[32] = |
| 219 | { |
| 220 | 0, 61, 60, 59, 58, 57, 56, 55, |
| 221 | 54, 53, 52, 51, 50, 49, 48, 47, |
| 222 | 46, 45, 44, 43, 42, 41, 40, 39, |
| 223 | 38, 37, 36, 35, 34, 33, 32, 0 |
| 224 | }; |
| 225 | static const int wl[8] = |
| 226 | { |
| 227 | -60, -30, 58, 172, 334, 538, 1198, 3042 |
| 228 | }; |
| 229 | static const int rl42[16] = |
| 230 | { |
| 231 | 0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0 |
| 232 | }; |
| 233 | static const int ilb[32] = |
| 234 | { |
| 235 | 2048, 2093, 2139, 2186, 2233, 2282, 2332, |
| 236 | 2383, 2435, 2489, 2543, 2599, 2656, 2714, |
| 237 | 2774, 2834, 2896, 2960, 3025, 3091, 3158, |
| 238 | 3228, 3298, 3371, 3444, 3520, 3597, 3676, |
| 239 | 3756, 3838, 3922, 4008 |
| 240 | }; |
| 241 | static const int qm4[16] = |
| 242 | { |
| 243 | 0, -20456, -12896, -8968, |
| 244 | -6288, -4240, -2584, -1200, |
| 245 | 20456, 12896, 8968, 6288, |
| 246 | 4240, 2584, 1200, 0 |
| 247 | }; |
| 248 | static const int qm2[4] = |
| 249 | { |
| 250 | -7408, -1616, 7408, 1616 |
| 251 | }; |
| 252 | static const int qmf_coeffs[12] = |
| 253 | { |
| 254 | 3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11, |
| 255 | }; |
| 256 | static const int ihn[3] = {0, 1, 0}; |
| 257 | static const int ihp[3] = {0, 3, 2}; |
| 258 | static const int wh[3] = {0, -214, 798}; |
| 259 | static const int rh2[4] = {2, 1, 2, 1}; |
| 260 | |
| 261 | int dlow; |
| 262 | int dhigh; |
| 263 | int el; |
| 264 | int wd; |
| 265 | int wd1; |
| 266 | int ril; |
| 267 | int wd2; |
| 268 | int il4; |
| 269 | int ih2; |
| 270 | int wd3; |
| 271 | int eh; |
| 272 | int mih; |
| 273 | int i; |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 274 | size_t j; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 275 | /* Low and high band PCM from the QMF */ |
| 276 | int xlow; |
| 277 | int xhigh; |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 278 | size_t g722_bytes; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 279 | /* Even and odd tap accumulators */ |
| 280 | int sumeven; |
| 281 | int sumodd; |
| 282 | int ihigh; |
| 283 | int ilow; |
| 284 | int code; |
| 285 | |
| 286 | g722_bytes = 0; |
| 287 | xhigh = 0; |
| 288 | for (j = 0; j < len; ) |
| 289 | { |
| 290 | if (s->itu_test_mode) |
| 291 | { |
| 292 | xlow = |
| 293 | xhigh = amp[j++] >> 1; |
| 294 | } |
| 295 | else |
| 296 | { |
| 297 | if (s->eight_k) |
| 298 | { |
| 299 | /* We shift by 1 to allow for the 15 bit input to the G.722 algorithm. */ |
| 300 | xlow = amp[j++] >> 1; |
| 301 | } |
| 302 | else |
| 303 | { |
| 304 | /* Apply the transmit QMF */ |
| 305 | /* Shuffle the buffer down */ |
| 306 | for (i = 0; i < 22; i++) |
| 307 | s->x[i] = s->x[i + 2]; |
| 308 | s->x[22] = amp[j++]; |
| 309 | s->x[23] = amp[j++]; |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 310 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 311 | /* Discard every other QMF output */ |
| 312 | sumeven = 0; |
| 313 | sumodd = 0; |
| 314 | for (i = 0; i < 12; i++) |
| 315 | { |
| 316 | sumodd += s->x[2*i]*qmf_coeffs[i]; |
| 317 | sumeven += s->x[2*i + 1]*qmf_coeffs[11 - i]; |
| 318 | } |
| 319 | /* We shift by 12 to allow for the QMF filters (DC gain = 4096), plus 1 |
| 320 | to allow for us summing two filters, plus 1 to allow for the 15 bit |
| 321 | input to the G.722 algorithm. */ |
| 322 | xlow = (sumeven + sumodd) >> 14; |
| 323 | xhigh = (sumeven - sumodd) >> 14; |
| 324 | |
| 325 | #ifdef RUN_LIKE_REFERENCE_G722 |
| 326 | /* The following lines are only used to verify bit-exactness |
| 327 | * with reference implementation of G.722. Higher precision |
| 328 | * is achieved without limiting the values. |
| 329 | */ |
| 330 | xlow = limitValues(xlow); |
| 331 | xhigh = limitValues(xhigh); |
| 332 | #endif |
| 333 | } |
| 334 | } |
| 335 | /* Block 1L, SUBTRA */ |
| 336 | el = saturate(xlow - s->band[0].s); |
| 337 | |
| 338 | /* Block 1L, QUANTL */ |
| 339 | wd = (el >= 0) ? el : -(el + 1); |
| 340 | |
| 341 | for (i = 1; i < 30; i++) |
| 342 | { |
| 343 | wd1 = (q6[i]*s->band[0].det) >> 12; |
| 344 | if (wd < wd1) |
| 345 | break; |
| 346 | } |
| 347 | ilow = (el < 0) ? iln[i] : ilp[i]; |
| 348 | |
| 349 | /* Block 2L, INVQAL */ |
| 350 | ril = ilow >> 2; |
| 351 | wd2 = qm4[ril]; |
| 352 | dlow = (s->band[0].det*wd2) >> 15; |
| 353 | |
| 354 | /* Block 3L, LOGSCL */ |
| 355 | il4 = rl42[ril]; |
| 356 | wd = (s->band[0].nb*127) >> 7; |
| 357 | s->band[0].nb = wd + wl[il4]; |
| 358 | if (s->band[0].nb < 0) |
| 359 | s->band[0].nb = 0; |
| 360 | else if (s->band[0].nb > 18432) |
| 361 | s->band[0].nb = 18432; |
| 362 | |
| 363 | /* Block 3L, SCALEL */ |
| 364 | wd1 = (s->band[0].nb >> 6) & 31; |
| 365 | wd2 = 8 - (s->band[0].nb >> 11); |
| 366 | wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); |
| 367 | s->band[0].det = wd3 << 2; |
| 368 | |
| 369 | block4(s, 0, dlow); |
Henrik Kjellander | b252856 | 2016-03-29 17:47:19 +0200 | [diff] [blame] | 370 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 371 | if (s->eight_k) |
| 372 | { |
| 373 | /* Just leave the high bits as zero */ |
| 374 | code = (0xC0 | ilow) >> (8 - s->bits_per_sample); |
| 375 | } |
| 376 | else |
| 377 | { |
| 378 | /* Block 1H, SUBTRA */ |
| 379 | eh = saturate(xhigh - s->band[1].s); |
| 380 | |
| 381 | /* Block 1H, QUANTH */ |
| 382 | wd = (eh >= 0) ? eh : -(eh + 1); |
| 383 | wd1 = (564*s->band[1].det) >> 12; |
| 384 | mih = (wd >= wd1) ? 2 : 1; |
| 385 | ihigh = (eh < 0) ? ihn[mih] : ihp[mih]; |
| 386 | |
| 387 | /* Block 2H, INVQAH */ |
| 388 | wd2 = qm2[ihigh]; |
| 389 | dhigh = (s->band[1].det*wd2) >> 15; |
| 390 | |
| 391 | /* Block 3H, LOGSCH */ |
| 392 | ih2 = rh2[ihigh]; |
| 393 | wd = (s->band[1].nb*127) >> 7; |
| 394 | s->band[1].nb = wd + wh[ih2]; |
| 395 | if (s->band[1].nb < 0) |
| 396 | s->band[1].nb = 0; |
| 397 | else if (s->band[1].nb > 22528) |
| 398 | s->band[1].nb = 22528; |
| 399 | |
| 400 | /* Block 3H, SCALEH */ |
| 401 | wd1 = (s->band[1].nb >> 6) & 31; |
| 402 | wd2 = 10 - (s->band[1].nb >> 11); |
| 403 | wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2); |
| 404 | s->band[1].det = wd3 << 2; |
| 405 | |
| 406 | block4(s, 1, dhigh); |
| 407 | code = ((ihigh << 6) | ilow) >> (8 - s->bits_per_sample); |
| 408 | } |
| 409 | |
| 410 | if (s->packed) |
| 411 | { |
| 412 | /* Pack the code bits */ |
| 413 | s->out_buffer |= (code << s->out_bits); |
| 414 | s->out_bits += s->bits_per_sample; |
| 415 | if (s->out_bits >= 8) |
| 416 | { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 417 | g722_data[g722_bytes++] = (uint8_t) (s->out_buffer & 0xFF); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 418 | s->out_bits -= 8; |
| 419 | s->out_buffer >>= 8; |
| 420 | } |
| 421 | } |
| 422 | else |
| 423 | { |
pbos@webrtc.org | 0946a56 | 2013-04-09 00:28:06 +0000 | [diff] [blame] | 424 | g722_data[g722_bytes++] = (uint8_t) code; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 425 | } |
| 426 | } |
| 427 | return g722_bytes; |
| 428 | } |
| 429 | /*- End of function --------------------------------------------------------*/ |
| 430 | /*- End of file ------------------------------------------------------------*/ |