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