1# 2# Copyright 2022 Google LLC 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16 17import numpy as np 18 19import lc3 20import tables as T, appendix_c as C 21 22import bwdet as m_bwdet 23import ltpf as m_ltpf 24import sns as m_sns 25import tns as m_tns 26 27### ------------------------------------------------------------------------ ### 28 29class SpectrumQuantization: 30 31 def __init__(self, dt, sr): 32 33 self.dt = dt 34 self.sr = sr 35 36 def get_gain_offset(self, nbytes): 37 38 g_off = (nbytes * 8) // (10 * (1 + self.sr)) 39 g_off = -min(115, g_off) - (105 + 5*(1 + self.sr)) 40 41 return g_off 42 43 def get_noise_indices(self, bw, xq, lastnz): 44 45 nf_start = [ 18, 24 ][self.dt] 46 nf_width = [ 2, 3 ][self.dt] 47 48 bw_stop = int([ 80, 160, 240, 320, 400 ][bw] * (T.DT_MS[self.dt] / 10)) 49 50 xq = np.append(xq[:lastnz], np.zeros(len(xq) - lastnz)) 51 52 i_nf = [ np.all(xq[k-nf_width:min(bw_stop, k+nf_width+1)] == 0) 53 for k in range(nf_start, bw_stop) ] 54 55 return (i_nf, nf_start, bw_stop) 56 57 58class SpectrumAnalysis(SpectrumQuantization): 59 60 def __init__(self, dt, sr): 61 62 super().__init__(dt, sr) 63 64 self.reset_off = 0 65 self.nbits_off = 0 66 self.nbits_spec = 0 67 self.nbits_est = 0 68 69 (self.g_idx, self.noise_factor, self.xq, self.lastnz, 70 self.nbits_residual_max, self.xg) = \ 71 (None, None, None, None, None, None) 72 73 def estimate_gain(self, x, nbits_spec, nbits_off, g_off): 74 75 nbits = int(nbits_spec + nbits_off + 0.5) 76 77 ### Energy (dB) by 4 MDCT coefficients 78 79 e = [ np.sum(x[4*k:4*(k+1)] ** 2) for k in range(len(x) // 4) ] 80 e = 10 * np.log10(2**-31 + np.array(e)) 81 82 ### Compute gain index 83 84 g_idx = 255 85 86 for i in range(8): 87 factor = 1 << (7 - i) 88 g_idx -= factor 89 tmp = 0 90 iszero = 1 91 92 for ei in e[-1::-1]: 93 94 if ei * 28/20 < g_idx + g_off: 95 if iszero == 0: 96 tmp += 2.7*28/20 97 else: 98 if g_idx + g_off < (ei - 43) * 28/20: 99 tmp += 2*ei*28/20 - 2*(g_idx + g_off) - 36*28/20 100 else: 101 tmp += ei*28/20 - (g_idx + g_off) + 7*28/20 102 iszero = 0 103 104 if tmp > nbits * 1.4 * 28/20 and iszero == 0: 105 g_idx += factor 106 107 ### Limit gain index 108 109 x_max = np.amax(np.abs(x)) 110 if x_max > 0: 111 g_min = 28 * np.log10(x_max / (32768 - 0.375)) 112 g_min = np.ceil(g_min).astype(int) - g_off 113 reset_off = g_idx < g_min 114 else: 115 g_min = 0 116 reset_off = True 117 118 if reset_off: 119 g_idx = g_min 120 121 return (g_idx + g_off, reset_off) 122 123 def quantize(self, g_int, x): 124 125 xg = x / 10 ** (g_int / 28) 126 127 xq = np.where(xg < 0, np.ceil(xg - 0.375), np.floor(xg + 0.375)) 128 xq = xq.astype(int) 129 xq = np.fmin(np.fmax(xq, -32768), 32767) 130 131 nz_pairs = np.any([ xq[::2] != 0, xq[1::2] != 0 ], axis=0) 132 lastnz = len(xq) - 2 * np.argmax(nz_pairs[-1::-1]) 133 if not np.any(nz_pairs): 134 lastnz = 0 135 136 return (xg, xq, lastnz) 137 138 def compute_nbits(self, nbytes, x, lastnz, nbits_spec): 139 140 mode = 1 if nbytes >= 20 * (3 + self.sr) else 0 141 rate = 512 if nbytes > 20 * (1 + self.sr) else 0 142 143 nbits_est = 0 144 nbits_trunc = 0 145 nbits_lsb = 0 146 lastnz_trunc = 2 147 c = 0 148 149 for n in range(0, lastnz, 2): 150 t = c + rate 151 if n > len(x) // 2: 152 t += 256 153 154 a = abs(x[n ]) 155 b = abs(x[n+1]) 156 lev = 0 157 while max(a, b) >= 4: 158 nbits_est += \ 159 T.AC_SPEC_BITS[T.AC_SPEC_LOOKUP[t + lev*1024]][16]; 160 if lev == 0 and mode == 1: 161 nbits_lsb += 2 162 else: 163 nbits_est += 2 * 2048 164 165 a >>= 1 166 b >>= 1 167 lev = min(lev + 1, 3) 168 169 nbits_est += \ 170 T.AC_SPEC_BITS[T.AC_SPEC_LOOKUP[t + lev*1024]][a + 4*b] 171 172 a_lsb = abs(x[n ]) 173 b_lsb = abs(x[n+1]) 174 nbits_est += (min(a_lsb, 1) + min(b_lsb, 1)) * 2048 175 if lev > 0 and mode == 1: 176 a_lsb >>= 1; 177 b_lsb >>= 1; 178 nbits_lsb += int(a_lsb == 0 and x[n ] != 0) 179 nbits_lsb += int(b_lsb == 0 and x[n+1] != 0) 180 181 if (x[n] != 0 or x[n+1] != 0) and \ 182 (nbits_est <= nbits_spec * 2048): 183 lastnz_trunc = n + 2; 184 nbits_trunc = nbits_est 185 186 t = 1 + (a + b) * (lev + 1) if lev <= 1 else 12 + lev; 187 c = (c & 15) * 16 + t; 188 189 nbits_est = (nbits_est + 2047) // 2048 + nbits_lsb; 190 nbits_trunc = (nbits_trunc + 2047) // 2048 191 192 self.rate = rate 193 self.lsb_mode = mode == 1 and nbits_est > nbits_spec 194 195 return (nbits_est, nbits_trunc, lastnz_trunc, self.lsb_mode) 196 197 def adjust_gain(self, g_idx, nbits, nbits_spec): 198 199 T1 = [ 80, 230, 380, 530, 680 ] 200 T2 = [ 500, 1025, 1550, 2075, 2600 ] 201 T3 = [ 850, 1700, 2550, 3400, 4250 ] 202 203 sr = self.sr 204 205 if nbits < T1[sr]: 206 delta = (nbits + 48) / 16 207 208 elif nbits < T2[sr]: 209 a = T1[sr] / 16 + 3 210 b = T2[sr] / 48 211 delta = a + (nbits - T1[sr]) * (b - a) / (T2[sr] - T1[sr]) 212 213 elif nbits < T3[sr]: 214 delta = nbits / 48 215 216 else: 217 delta = T3[sr] / 48; 218 219 delta = np.fix(delta + 0.5).astype(int) 220 221 if (g_idx < 255 and nbits > nbits_spec) or \ 222 (g_idx > 0 and nbits < nbits_spec - (delta + 2)): 223 224 if nbits < nbits_spec - (delta + 2): 225 return - 1 226 227 if g_idx == 254 or nbits < nbits_spec + delta: 228 return 1 229 230 else: 231 return 2 232 233 return 0 234 235 def estimate_noise(self, bw, xq, lastnz, x): 236 237 (i_nf, nf_start, nf_stop) = self.get_noise_indices(bw, xq, lastnz) 238 239 nf = 8 - 16 * sum(abs(x[nf_start:nf_stop] * i_nf)) / sum(i_nf) \ 240 if sum(i_nf) > 0 else 0 241 242 return min(max(np.rint(nf).astype(int), 0), 7) 243 244 def run(self, 245 bw, nbytes, nbits_bw, nbits_ltpf, nbits_sns, nbits_tns, x): 246 247 sr = self.sr 248 249 ### Bit budget 250 251 nbits_gain = 8 252 nbits_nf = 3 253 254 nbits_ari = np.ceil(np.log2(len(x) / 2)).astype(int) 255 nbits_ari += 3 + min((8*nbytes - 1) // 1280, 2) 256 257 nbits_spec = 8*nbytes - \ 258 nbits_bw - nbits_ltpf - nbits_sns - nbits_tns - \ 259 nbits_gain - nbits_nf - nbits_ari 260 261 ### Global gain estimation 262 263 nbits_off = self.nbits_off + self.nbits_spec - self.nbits_est 264 nbits_off = min(40, max(-40, nbits_off)) 265 266 nbits_off = 0 if self.reset_off else \ 267 0.8 * self.nbits_off + 0.2 * nbits_off 268 269 g_off = self.get_gain_offset(nbytes) 270 271 (g_int, self.reset_off) = \ 272 self.estimate_gain(x, nbits_spec, nbits_off, g_off) 273 self.nbits_off = nbits_off 274 self.nbits_spec = nbits_spec 275 276 ### Quantization 277 278 (xg, xq, lastnz) = self.quantize(g_int, x) 279 280 (nbits_est, nbits_trunc, lastnz_trunc, _) = \ 281 self.compute_nbits(nbytes, xq, lastnz, nbits_spec) 282 283 self.nbits_est = nbits_est 284 285 ### Adjust gain and requantize 286 287 g_adj = self.adjust_gain(g_int - g_off, nbits_est, nbits_spec) 288 289 (xg, xq, lastnz) = self.quantize(g_adj, xg) 290 291 (nbits_est, nbits_trunc, lastnz_trunc, lsb_mode) = \ 292 self.compute_nbits(nbytes, xq, lastnz, nbits_spec) 293 294 self.g_idx = g_int + g_adj - g_off 295 self.xq = xq 296 self.lastnz = lastnz_trunc 297 298 self.nbits_residual_max = nbits_spec - nbits_trunc + 4 299 self.xg = xg 300 301 ### Noise factor 302 303 self.noise_factor = self.estimate_noise(bw, xq, lastnz, x) 304 305 return (self.xq, self.lastnz, self.xg) 306 307 def store(self, b): 308 309 ne = T.NE[self.dt][self.sr] 310 nbits_lastnz = np.ceil(np.log2(ne/2)).astype(int) 311 312 b.write_uint((self.lastnz >> 1) - 1, nbits_lastnz) 313 b.write_uint(self.lsb_mode, 1) 314 b.write_uint(self.g_idx, 8) 315 316 def encode(self, bits): 317 318 ### Noise factor 319 320 bits.write_uint(self.noise_factor, 3) 321 322 ### Quantized data 323 324 lsbs = [] 325 326 x = self.xq 327 c = 0 328 329 for n in range(0, self.lastnz, 2): 330 t = c + self.rate 331 if n > len(x) // 2: 332 t += 256 333 334 a = abs(x[n ]) 335 b = abs(x[n+1]) 336 lev = 0 337 while max(a, b) >= 4: 338 339 bits.ac_encode( 340 T.AC_SPEC_CUMFREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][16], 341 T.AC_SPEC_FREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][16]) 342 343 if lev == 0 and self.lsb_mode: 344 lsb_0 = a & 1 345 lsb_1 = b & 1 346 else: 347 bits.write_bit(a & 1) 348 bits.write_bit(b & 1) 349 350 a >>= 1 351 b >>= 1 352 lev = min(lev + 1, 3) 353 354 bits.ac_encode( 355 T.AC_SPEC_CUMFREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][a + 4*b], 356 T.AC_SPEC_FREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][a + 4*b]) 357 358 a_lsb = abs(x[n ]) 359 b_lsb = abs(x[n+1]) 360 if lev > 0 and self.lsb_mode: 361 a_lsb >>= 1 362 b_lsb >>= 1 363 364 lsbs.append(lsb_0) 365 if a_lsb == 0 and x[n+0] != 0: 366 lsbs.append(int(x[n+0] < 0)) 367 368 lsbs.append(lsb_1) 369 if b_lsb == 0 and x[n+1] != 0: 370 lsbs.append(int(x[n+1] < 0)) 371 372 if a_lsb > 0: 373 bits.write_bit(int(x[n+0] < 0)) 374 375 if b_lsb > 0: 376 bits.write_bit(int(x[n+1] < 0)) 377 378 t = 1 + (a + b) * (lev + 1) if lev <= 1 else 12 + lev; 379 c = (c & 15) * 16 + t; 380 381 ### Residual data 382 383 if self.lsb_mode == 0: 384 nbits_residual = min(bits.get_bits_left(), self.nbits_residual_max) 385 386 for i in range(len(self.xg)): 387 388 if self.xq[i] == 0: 389 continue 390 391 bits.write_bit(self.xg[i] >= self.xq[i]) 392 nbits_residual -= 1 393 if nbits_residual <= 0: 394 break 395 396 else: 397 nbits_residual = min(bits.get_bits_left(), len(lsbs)) 398 for lsb in lsbs[:nbits_residual]: 399 bits.write_bit(lsb) 400 401 402class SpectrumSynthesis(SpectrumQuantization): 403 404 def __init__(self, dt, sr): 405 406 super().__init__(dt, sr) 407 408 (self.lastnz, self.lsb_mode, self.g_idx) = \ 409 (None, None, None) 410 411 def fill_noise(self, bw, x, lastnz, f_nf, nf_seed): 412 413 (i_nf, nf_start, nf_stop) = self.get_noise_indices(bw, x, lastnz) 414 415 k_nf = nf_start + np.argwhere(i_nf) 416 l_nf = (8 - f_nf)/16 417 418 for k in k_nf: 419 nf_seed = (13849 + nf_seed * 31821) & 0xffff 420 x[k] = [ -l_nf, l_nf ][nf_seed < 0x8000] 421 422 return x 423 424 def load(self, b): 425 426 ne = T.NE[self.dt][self.sr] 427 nbits_lastnz = np.ceil(np.log2(ne/2)).astype(int) 428 429 self.lastnz = (b.read_uint(nbits_lastnz) + 1) << 1 430 self.lsb_mode = b.read_uint(1) 431 self.g_idx = b.read_uint(8) 432 433 if self.lastnz > ne: 434 raise ValueError('Invalid count of coded samples') 435 436 def decode(self, bits, bw, nbytes): 437 438 ### Noise factor 439 440 f_nf = bits.read_uint(3) 441 442 ### Quantized data 443 444 x = np.zeros(T.NE[self.dt][self.sr]) 445 rate = 512 if nbytes > 20 * (1 + self.sr) else 0 446 447 levs = np.zeros(len(x), dtype=np.int) 448 c = 0 449 450 for n in range(0, self.lastnz, 2): 451 t = c + rate 452 if n > len(x) // 2: 453 t += 256 454 455 for lev in range(14): 456 457 s = t + min(lev, 3) * 1024 458 459 sym = bits.ac_decode( 460 T.AC_SPEC_CUMFREQ[T.AC_SPEC_LOOKUP[s]], 461 T.AC_SPEC_FREQ[T.AC_SPEC_LOOKUP[s]]) 462 463 if sym < 16: 464 break 465 466 if self.lsb_mode == 0 or lev > 0: 467 x[n ] += bits.read_bit() << lev 468 x[n+1] += bits.read_bit() << lev 469 470 if lev >= 14: 471 raise ValueError('Out of range value') 472 473 a = sym % 4 474 b = sym // 4 475 476 levs[n ] = lev 477 levs[n+1] = lev 478 479 x[n ] += a << lev 480 x[n+1] += b << lev 481 482 if x[n] and bits.read_bit(): 483 x[n] = -x[n] 484 485 if x[n+1] and bits.read_bit(): 486 x[n+1] = -x[n+1] 487 488 lev = min(lev, 3) 489 t = 1 + (a + b) * (lev + 1) if lev <= 1 else 12 + lev; 490 c = (c & 15) * 16 + t; 491 492 ### Residual data 493 494 nbits_residual = bits.get_bits_left() 495 if nbits_residual < 0: 496 raise ValueError('Out of bitstream') 497 498 if self.lsb_mode == 0: 499 500 xr = np.zeros(len(x), dtype=np.bool) 501 502 for i in range(len(x)): 503 504 if nbits_residual <= 0: 505 xr.resize(i) 506 break 507 508 if x[i] == 0: 509 continue 510 511 xr[i] = bits.read_bit() 512 nbits_residual -= 1 513 514 else: 515 516 for i in range(len(levs)): 517 518 if nbits_residual <= 0: 519 break 520 521 if levs[i] <= 0: 522 continue 523 524 lsb = bits.read_bit() 525 nbits_residual -= 1 526 if not lsb: 527 continue 528 529 sign = int(x[i] < 0) 530 531 if x[i] == 0: 532 533 if nbits_residual <= 0: 534 break 535 536 sign = bits.read_bit() 537 nbits_residual -= 1 538 539 x[i] += [ 1, -1 ][sign] 540 541 ### Set residual and noise 542 543 nf_seed = sum(abs(x.astype(np.int)) * range(len(x))) 544 545 zero_frame = (self.lastnz <= 2 and x[0] == 0 and x[1] == 0 546 and self.g_idx <= 0 and f_nf >= 7) 547 548 if self.lsb_mode == 0: 549 550 for i in range(len(xr)): 551 552 if x[i] and xr[i] == 0: 553 x[i] += [ -0.1875, -0.3125 ][x[i] < 0] 554 elif x[i]: 555 x[i] += [ 0.1875, 0.3125 ][x[i] > 0] 556 557 if not zero_frame: 558 x = self.fill_noise(bw, x, self.lastnz, f_nf, nf_seed) 559 560 ### Rescale coefficients 561 562 g_int = self.get_gain_offset(nbytes) + self.g_idx 563 x *= 10 ** (g_int / 28) 564 565 return x 566 567 568def initial_state(): 569 return { 'nbits_off' : 0.0, 'nbits_spare' : 0 } 570 571 572### ------------------------------------------------------------------------ ### 573 574def check_estimate_gain(rng, dt, sr): 575 576 ne = T.I[dt][sr][-1] 577 ok = True 578 579 analysis = SpectrumAnalysis(dt, sr) 580 581 for i in range(10): 582 x = rng.random(ne) * i * 1e2 583 584 nbytes = 20 + int(rng.random() * 100) 585 nbits_budget = 8 * nbytes - int(rng.random() * 100) 586 nbits_off = rng.random() * 10 587 g_off = 10 - int(rng.random() * 20) 588 589 (g_int, reset_off) = \ 590 analysis.estimate_gain(x, nbits_budget, nbits_off, g_off) 591 592 (g_int_c, reset_off_c) = lc3.spec_estimate_gain( 593 dt, sr, x, nbits_budget, nbits_off, -g_off) 594 595 ok = ok and g_int_c == g_int 596 ok = ok and reset_off_c == reset_off 597 598 return ok 599 600def check_quantization(rng, dt, sr): 601 602 ne = T.I[dt][sr][-1] 603 ok = True 604 605 analysis = SpectrumAnalysis(dt, sr) 606 607 for g_int in range(-128, 128): 608 609 x = rng.random(ne) * 1e2 610 nbytes = 20 + int(rng.random() * 30) 611 612 (xg, xq, nq) = analysis.quantize(g_int, x) 613 (xg_c, xq_c, nq_c) = lc3.spec_quantize(dt, sr, g_int, x) 614 615 ok = ok and np.amax(np.abs(1 - xg_c/xg)) < 1e-6 616 ok = ok and np.any(abs(xq_c - xq) < 1) 617 ok = ok and nq_c == nq 618 619 return ok 620 621def check_compute_nbits(rng, dt, sr): 622 623 ne = T.I[dt][sr][-1] 624 ok = True 625 626 analysis = SpectrumAnalysis(dt, sr) 627 628 for nbytes in range(20, 150): 629 630 nbits_budget = nbytes * 8 - int(rng.random() * 100) 631 xq = (rng.random(ne) * 8).astype(int) 632 nq = ne // 2 + int(rng.random() * ne // 2) 633 634 nq = nq - nq % 2 635 if xq[nq-2] == 0 and xq[nq-1] == 0: 636 xq[nq-2] = 1 637 638 (nbits, nbits_trunc, nq_trunc, lsb_mode) = \ 639 analysis.compute_nbits(nbytes, xq, nq, nbits_budget) 640 641 (nbits_c, nq_c, _) = \ 642 lc3.spec_compute_nbits(dt, sr, nbytes, xq, nq, 0) 643 644 (nbits_trunc_c, nq_trunc_c, lsb_mode_c) = \ 645 lc3.spec_compute_nbits(dt, sr, nbytes, xq, nq, nbits_budget) 646 647 ok = ok and nbits_c == nbits 648 ok = ok and nbits_trunc_c == nbits_trunc 649 ok = ok and nq_trunc_c == nq_trunc 650 ok = ok and lsb_mode_c == lsb_mode 651 652 return ok 653 654def check_adjust_gain(rng, dt, sr): 655 656 ne = T.I[dt][sr][-1] 657 ok = True 658 659 analysis = SpectrumAnalysis(dt, sr) 660 661 for g_idx in (0, 128, 254, 255): 662 for nbits in range(50, 5000, 5): 663 nbits_budget = int(nbits * (0.95 + (rng.random() * 0.1))) 664 665 g_adj = analysis.adjust_gain(g_idx, nbits, nbits_budget) 666 667 g_adj_c = lc3.spec_adjust_gain(sr, g_idx, nbits, nbits_budget) 668 669 ok = ok and g_adj_c == g_adj 670 671 return ok 672 673def check_unit(rng, dt, sr): 674 675 ns = T.NS[dt][sr] 676 ne = T.I[dt][sr][-1] 677 ok = True 678 679 state_c = initial_state() 680 681 bwdet = m_bwdet.BandwidthDetector(dt, sr) 682 ltpf = m_ltpf.LtpfAnalysis(dt, sr) 683 tns = m_tns.TnsAnalysis(dt) 684 sns = m_sns.SnsAnalysis(dt, sr) 685 analysis = SpectrumAnalysis(dt, sr) 686 687 nbytes = 100 688 689 for i in range(10): 690 691 x = rng.random(ns) * 1e4 692 e = rng.random(min(len(x), 64)) * 1e10 693 694 bwdet.run(e) 695 pitch_present = ltpf.run(x) 696 tns.run(x[:ne], sr, False, nbytes) 697 sns.run(e, False, x) 698 699 (xq, nq, _) = analysis.run(sr, nbytes, bwdet.get_nbits(), 700 ltpf.get_nbits(), sns.get_nbits(), tns.get_nbits(), x[:ne]) 701 702 (_, xq_c, side_c) = lc3.spec_analyze( 703 dt, sr, nbytes, pitch_present, tns.get_data(), state_c, x[:ne]) 704 705 ok = ok and side_c['g_idx'] == analysis.g_idx 706 ok = ok and side_c['nq'] == nq 707 ok = ok and np.any(abs(xq_c - xq) < 1) 708 709 return ok 710 711def check_noise(rng, dt, bw): 712 713 ne = T.NE[dt][bw] 714 ok = True 715 716 analysis = SpectrumAnalysis(dt, bw) 717 718 for i in range(10): 719 720 xq = ((rng.random(ne) - 0.5) * 10 ** (0.5)).astype(int) 721 nq = ne - int(rng.random() * 5) 722 x = rng.random(ne) * i * 1e-1 723 724 nf = analysis.estimate_noise(bw, xq, nq, x) 725 nf_c = lc3.spec_estimate_noise(dt, bw, xq, nq, x) 726 727 ok = ok and nf_c == nf 728 729 return ok 730 731def check_appendix_c(dt): 732 733 sr = T.SRATE_16K 734 ne = T.NE[dt][sr] 735 ok = True 736 737 state_c = initial_state() 738 739 for i in range(len(C.X_F[dt])): 740 741 g_int = lc3.spec_estimate_gain(dt, sr, C.X_F[dt][i], 742 C.NBITS_SPEC[dt][i], C.NBITS_OFFSET[dt][i], -C.GG_OFF[dt][i])[0] 743 ok = ok and g_int == C.GG_IND[dt][i] + C.GG_OFF[dt][i] 744 745 (_, xq, nq) = lc3.spec_quantize(dt, sr, 746 C.GG_IND[dt][i] + C.GG_OFF[dt][i], C.X_F[dt][i]) 747 ok = ok and np.any((xq - C.X_Q[dt][i]) == 0) 748 ok = ok and nq == C.LASTNZ[dt][i] 749 750 nbits = lc3.spec_compute_nbits(dt, sr, 751 C.NBYTES[dt], C.X_Q[dt][i], C.LASTNZ[dt][i], 0)[0] 752 ok = ok and nbits == C.NBITS_EST[dt][i] 753 754 g_adj = lc3.spec_adjust_gain(sr, 755 C.GG_IND[dt][i], C.NBITS_EST[dt][i], C.NBITS_SPEC[dt][i]) 756 ok = ok and g_adj == C.GG_IND_ADJ[dt][i] - C.GG_IND[dt][i] 757 758 if C.GG_IND_ADJ[dt][i] != C.GG_IND[dt][i]: 759 760 (_, xq, nq) = lc3.spec_quantize(dt, sr, 761 C.GG_IND_ADJ[dt][i] + C.GG_OFF[dt][i], C.X_F[dt][i]) 762 lastnz = C.LASTNZ_REQ[dt][i] 763 ok = ok and np.any(((xq - C.X_Q_REQ[dt][i])[:lastnz]) == 0) 764 765 tns_data = { 766 'nfilters' : C.NUM_TNS_FILTERS[dt][i], 767 'lpc_weighting' : [ True, True ], 768 'rc_order' : [ C.RC_ORDER[dt][i][0], 0 ], 769 'rc' : [ C.RC_I_1[dt][i] - 8, np.zeros(8, dtype = np.int) ] 770 } 771 772 (x, xq, side) = lc3.spec_analyze(dt, sr, C.NBYTES[dt], 773 C.PITCH_PRESENT[dt][i], tns_data, state_c, C.X_F[dt][i]) 774 775 ok = ok and np.abs(state_c['nbits_off'] - C.NBITS_OFFSET[dt][i]) < 1e-5 776 if C.GG_IND_ADJ[dt][i] != C.GG_IND[dt][i]: 777 xq = C.X_Q_REQ[dt][i] 778 nq = C.LASTNZ_REQ[dt][i] 779 ok = ok and side['g_idx'] == C.GG_IND_ADJ[dt][i] 780 ok = ok and side['nq'] == nq 781 ok = ok and np.any(((xq[:nq] - xq[:nq])) == 0) 782 else: 783 xq = C.X_Q[dt][i] 784 nq = C.LASTNZ[dt][i] 785 ok = ok and side['g_idx'] == C.GG_IND[dt][i] 786 ok = ok and side['nq'] == nq 787 ok = ok and np.any((xq[:nq] - C.X_Q[dt][i][:nq]) == 0) 788 ok = ok and side['lsb_mode'] == C.LSB_MODE[dt][i] 789 790 gg = C.GG[dt][i] if C.GG_IND_ADJ[dt][i] == C.GG_IND[dt][i] \ 791 else C.GG_ADJ[dt][i] 792 793 nf = lc3.spec_estimate_noise(dt, C.P_BW[dt][i], 794 xq, nq, C.X_F[dt][i] / gg) 795 ok = ok and nf == C.F_NF[dt][i] 796 797 return ok 798 799def check(): 800 801 rng = np.random.default_rng(1234) 802 ok = True 803 804 for dt in range(T.NUM_DT): 805 for sr in range(T.NUM_SRATE): 806 ok = ok and check_estimate_gain(rng, dt, sr) 807 ok = ok and check_quantization(rng, dt, sr) 808 ok = ok and check_compute_nbits(rng, dt, sr) 809 ok = ok and check_adjust_gain(rng, dt, sr) 810 ok = ok and check_unit(rng, dt, sr) 811 ok = ok and check_noise(rng, dt, sr) 812 813 for dt in range(T.NUM_DT): 814 ok = ok and check_appendix_c(dt) 815 816 return ok 817 818### ------------------------------------------------------------------------ ### 819