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 22 23BW_START = [ 24 [ [], [ 24 ], [ 24, 35 ], [ 24, 33, 39 ], [ 22, 31, 37, 41 ] ], 25 [ [], [ 39 ], [ 35, 47 ], [ 34, 44, 50 ], [ 32, 42, 48, 52 ] ], 26 [ [], [ 51 ], [ 45, 58 ], [ 42, 53, 60 ], [ 40, 51, 57, 61 ] ], 27 [ [], [ 53 ], [ 47, 59 ], [ 44, 54, 60 ], [ 41, 51, 57, 61 ] ] 28] 29 30BW_STOP = [ 31 [ [], [ 34 ], [ 32, 39 ], [ 31, 38, 42 ], [ 29, 35, 40, 43 ] ], 32 [ [], [ 49 ], [ 44, 51 ], [ 42, 49, 53 ], [ 40, 46, 51, 54 ] ], 33 [ [], [ 63 ], [ 55, 63 ], [ 51, 58, 63 ], [ 48, 55, 60, 63 ] ], 34 [ [], [ 63 ], [ 56, 63 ], [ 52, 59, 63 ], [ 49, 55, 60, 63 ] ] 35] 36 37TQ = [ 20, 10, 10, 10 ] 38 39TC = [ 15, 23, 20, 20 ] 40L = [ [ 4, 4, 3, 1 ], [ 4, 4, 3, 1 ], 41 [ 4, 4, 3, 2 ], [ 4, 4, 3, 1 ] ] 42 43### ------------------------------------------------------------------------ ### 44 45class BandwidthDetector: 46 47 def __init__(self, dt, sr): 48 49 self.dt = dt 50 self.sr = sr 51 52 def run(self, e): 53 54 dt = self.dt 55 sr = self.sr 56 57 ### Stage 1, determine bw0 candidate 58 59 bw0 = 0 60 61 for bw in range(sr): 62 i0 = BW_START[dt][sr][bw] 63 i1 = BW_STOP[dt][sr][bw] 64 if np.mean(e[i0:i1+1]) >= TQ[bw]: 65 bw0 = bw + 1 66 67 ### Stage 2, Cut-off random coefficients at each steps 68 69 bw = bw0 70 71 if bw0 < sr: 72 l = L[dt][bw0] 73 i0 = BW_START[dt][sr][bw0] - l 74 i1 = BW_START[dt][sr][bw0] 75 76 c = 10 * np.log10(1e-31 + e[i0-l+1:i1-l+2] / e[i0+1:i1+2]) 77 if np.amax(c) <= TC[bw0]: 78 bw = sr 79 80 self.bw = bw 81 return self.bw 82 83 def get_nbits(self): 84 85 return 0 if self.sr == 0 else \ 86 1 + np.log2(self.sr).astype(int) 87 88 def store(self, b): 89 90 b.write_uint(self.bw, self.get_nbits()) 91 92 def get(self, b): 93 94 return b.read_uint(self.get_nbits()) 95 96### ------------------------------------------------------------------------ ### 97 98def check_unit(rng, dt, sr): 99 100 ok = True 101 102 bwdet = BandwidthDetector(dt, sr) 103 104 for bw0 in range(sr+1): 105 for drop in range(10): 106 107 ### Generate random 'high' energy and 108 ### scale relevant bands to select 'bw0' 109 110 e = 20 + 100 * rng.random(64) 111 112 for i in range(sr): 113 if i+1 != bw0: 114 i0 = BW_START[dt][sr][i] 115 i1 = BW_STOP[dt][sr][i] 116 e[i0:i1+1] /= (np.mean(e[i0:i1+1]) / TQ[i] + 1e-3) 117 118 ### Stage 2 Condition, 119 ### cut-off random coefficients at each steps 120 121 if bw0 < sr: 122 l = L[dt][bw0] 123 i0 = BW_START[dt][sr][bw0] - l 124 i1 = BW_START[dt][sr][bw0] 125 126 e[i0-l+1:i1+2] /= np.power(10, np.arange(2*l+1) / (1 + drop)) 127 128 ### Check with implementation 129 130 bw_c = lc3.bwdet_run(dt, sr, e) 131 132 ok = ok and bw_c == bwdet.run(e) 133 134 return ok 135 136def check_appendix_c(dt): 137 138 i0 = dt - T.DT_7M5 139 sr = T.SRATE_16K 140 141 ok = True 142 143 E_B = C.E_B[i0] 144 P_BW = C.P_BW[i0] 145 146 bw = lc3.bwdet_run(dt, sr, E_B[0]) 147 ok = ok and bw == P_BW[0] 148 149 bw = lc3.bwdet_run(dt, sr, E_B[1]) 150 ok = ok and bw == P_BW[1] 151 152 return ok 153 154def check(): 155 156 rng = np.random.default_rng(1234) 157 158 ok = True 159 for dt in range(T.NUM_DT): 160 for sr in range(T.SRATE_8K, T.SRATE_48K + 1): 161 ok = ok and check_unit(rng, dt, sr) 162 163 for dt in ( T.DT_7M5, T.DT_10M ): 164 ok = ok and check_appendix_c(dt) 165 166 return ok 167 168### ------------------------------------------------------------------------ ### 169