1*49fe348cSAndroid Build Coastguard Worker# 2*49fe348cSAndroid Build Coastguard Worker# Copyright 2022 Google LLC 3*49fe348cSAndroid Build Coastguard Worker# 4*49fe348cSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*49fe348cSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*49fe348cSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*49fe348cSAndroid Build Coastguard Worker# 8*49fe348cSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*49fe348cSAndroid Build Coastguard Worker# 10*49fe348cSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*49fe348cSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*49fe348cSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*49fe348cSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*49fe348cSAndroid Build Coastguard Worker# limitations under the License. 15*49fe348cSAndroid Build Coastguard Worker# 16*49fe348cSAndroid Build Coastguard Worker 17*49fe348cSAndroid Build Coastguard Workerimport numpy as np 18*49fe348cSAndroid Build Coastguard Workerimport scipy.fftpack as fftpack 19*49fe348cSAndroid Build Coastguard Worker 20*49fe348cSAndroid Build Coastguard Workerimport lc3 21*49fe348cSAndroid Build Coastguard Workerimport tables as T, appendix_c as C 22*49fe348cSAndroid Build Coastguard Worker 23*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ### 24*49fe348cSAndroid Build Coastguard Worker 25*49fe348cSAndroid Build Coastguard Workerclass Sns: 26*49fe348cSAndroid Build Coastguard Worker 27*49fe348cSAndroid Build Coastguard Worker def __init__(self, dt, sr): 28*49fe348cSAndroid Build Coastguard Worker 29*49fe348cSAndroid Build Coastguard Worker self.dt = dt 30*49fe348cSAndroid Build Coastguard Worker self.sr = sr 31*49fe348cSAndroid Build Coastguard Worker self.I = T.I[dt][sr] 32*49fe348cSAndroid Build Coastguard Worker 33*49fe348cSAndroid Build Coastguard Worker (self.ind_lf, self.ind_hf, self.shape, self.gain) = \ 34*49fe348cSAndroid Build Coastguard Worker (None, None, None, None) 35*49fe348cSAndroid Build Coastguard Worker 36*49fe348cSAndroid Build Coastguard Worker (self.idx_a, self.ls_a, self.idx_b, self.ls_b) = \ 37*49fe348cSAndroid Build Coastguard Worker (None, None, None, None) 38*49fe348cSAndroid Build Coastguard Worker 39*49fe348cSAndroid Build Coastguard Worker def get_data(self): 40*49fe348cSAndroid Build Coastguard Worker 41*49fe348cSAndroid Build Coastguard Worker data = { 'lfcb' : self.ind_lf, 'hfcb' : self.ind_hf, 42*49fe348cSAndroid Build Coastguard Worker 'shape' : self.shape, 'gain' : self.gain, 43*49fe348cSAndroid Build Coastguard Worker 'idx_a' : self.idx_a, 'ls_a' : self.ls_a } 44*49fe348cSAndroid Build Coastguard Worker 45*49fe348cSAndroid Build Coastguard Worker if self.idx_b is not None: 46*49fe348cSAndroid Build Coastguard Worker data.update({ 'idx_b' : self.idx_b, 'ls_b' : self.ls_b }) 47*49fe348cSAndroid Build Coastguard Worker 48*49fe348cSAndroid Build Coastguard Worker return data 49*49fe348cSAndroid Build Coastguard Worker 50*49fe348cSAndroid Build Coastguard Worker def get_nbits(self): 51*49fe348cSAndroid Build Coastguard Worker 52*49fe348cSAndroid Build Coastguard Worker return 38 53*49fe348cSAndroid Build Coastguard Worker 54*49fe348cSAndroid Build Coastguard Worker def spectral_shaping(self, scf, inv, x): 55*49fe348cSAndroid Build Coastguard Worker 56*49fe348cSAndroid Build Coastguard Worker ## Scale factors interpolation 57*49fe348cSAndroid Build Coastguard Worker 58*49fe348cSAndroid Build Coastguard Worker scf_i = np.empty(4*len(scf)) 59*49fe348cSAndroid Build Coastguard Worker scf_i[0 ] = scf[0] 60*49fe348cSAndroid Build Coastguard Worker scf_i[1 ] = scf[0] 61*49fe348cSAndroid Build Coastguard Worker scf_i[2:62:4] = scf[:15] + 1/8 * (scf[1:] - scf[:15]) 62*49fe348cSAndroid Build Coastguard Worker scf_i[3:63:4] = scf[:15] + 3/8 * (scf[1:] - scf[:15]) 63*49fe348cSAndroid Build Coastguard Worker scf_i[4:64:4] = scf[:15] + 5/8 * (scf[1:] - scf[:15]) 64*49fe348cSAndroid Build Coastguard Worker scf_i[5:64:4] = scf[:15] + 7/8 * (scf[1:] - scf[:15]) 65*49fe348cSAndroid Build Coastguard Worker scf_i[62 ] = scf[15 ] + 1/8 * (scf[15] - scf[14 ]) 66*49fe348cSAndroid Build Coastguard Worker scf_i[63 ] = scf[15 ] + 3/8 * (scf[15] - scf[14 ]) 67*49fe348cSAndroid Build Coastguard Worker 68*49fe348cSAndroid Build Coastguard Worker nb = len(self.I) - 1 69*49fe348cSAndroid Build Coastguard Worker 70*49fe348cSAndroid Build Coastguard Worker if nb < 32: 71*49fe348cSAndroid Build Coastguard Worker n4 = round(abs(1-32/nb)*nb) 72*49fe348cSAndroid Build Coastguard Worker n2 = nb - n4 73*49fe348cSAndroid Build Coastguard Worker 74*49fe348cSAndroid Build Coastguard Worker for i in range(n4): 75*49fe348cSAndroid Build Coastguard Worker scf_i[i] = np.mean(scf_i[4*i:4*i+4]) 76*49fe348cSAndroid Build Coastguard Worker 77*49fe348cSAndroid Build Coastguard Worker for i in range(n4, n4+n2): 78*49fe348cSAndroid Build Coastguard Worker scf_i[i] = np.mean(scf_i[2*n4+2*i:2*n4+2*i+2]) 79*49fe348cSAndroid Build Coastguard Worker 80*49fe348cSAndroid Build Coastguard Worker scf_i = scf_i[:n4+n2] 81*49fe348cSAndroid Build Coastguard Worker 82*49fe348cSAndroid Build Coastguard Worker elif nb < 64: 83*49fe348cSAndroid Build Coastguard Worker n2 = 64 - nb 84*49fe348cSAndroid Build Coastguard Worker 85*49fe348cSAndroid Build Coastguard Worker for i in range(n2): 86*49fe348cSAndroid Build Coastguard Worker scf_i[i] = np.mean(scf_i[2*i:2*i+2]) 87*49fe348cSAndroid Build Coastguard Worker scf_i = np.append(scf_i[:n2], scf_i[2*n2:]) 88*49fe348cSAndroid Build Coastguard Worker 89*49fe348cSAndroid Build Coastguard Worker g_sns = np.power(2, [ -scf_i, scf_i ][inv]) 90*49fe348cSAndroid Build Coastguard Worker 91*49fe348cSAndroid Build Coastguard Worker ## Spectral shaping 92*49fe348cSAndroid Build Coastguard Worker 93*49fe348cSAndroid Build Coastguard Worker y = np.empty(len(x)) 94*49fe348cSAndroid Build Coastguard Worker I = self.I 95*49fe348cSAndroid Build Coastguard Worker 96*49fe348cSAndroid Build Coastguard Worker for b in range(nb): 97*49fe348cSAndroid Build Coastguard Worker y[I[b]:I[b+1]] = x[I[b]:I[b+1]] * g_sns[b] 98*49fe348cSAndroid Build Coastguard Worker 99*49fe348cSAndroid Build Coastguard Worker return y 100*49fe348cSAndroid Build Coastguard Worker 101*49fe348cSAndroid Build Coastguard Worker 102*49fe348cSAndroid Build Coastguard Workerclass SnsAnalysis(Sns): 103*49fe348cSAndroid Build Coastguard Worker 104*49fe348cSAndroid Build Coastguard Worker def __init__(self, dt, sr): 105*49fe348cSAndroid Build Coastguard Worker 106*49fe348cSAndroid Build Coastguard Worker super().__init__(dt, sr) 107*49fe348cSAndroid Build Coastguard Worker 108*49fe348cSAndroid Build Coastguard Worker def compute_scale_factors(self, e, att, nbytes): 109*49fe348cSAndroid Build Coastguard Worker 110*49fe348cSAndroid Build Coastguard Worker dt = self.dt 111*49fe348cSAndroid Build Coastguard Worker sr = self.sr 112*49fe348cSAndroid Build Coastguard Worker hr = self.sr >= T.SRATE_48K_HR 113*49fe348cSAndroid Build Coastguard Worker 114*49fe348cSAndroid Build Coastguard Worker ## Padding 115*49fe348cSAndroid Build Coastguard Worker 116*49fe348cSAndroid Build Coastguard Worker if len(e) < 32: 117*49fe348cSAndroid Build Coastguard Worker n4 = round(abs(1-32/len(e))*len(e)) 118*49fe348cSAndroid Build Coastguard Worker n2 = len(e) - n4 119*49fe348cSAndroid Build Coastguard Worker 120*49fe348cSAndroid Build Coastguard Worker e = np.append(np.zeros(3*n4+n2), e) 121*49fe348cSAndroid Build Coastguard Worker for i in range(n4): 122*49fe348cSAndroid Build Coastguard Worker e[4*i+0] = e[4*i+1] = \ 123*49fe348cSAndroid Build Coastguard Worker e[4*i+2] = e[4*i+3] = e[3*n4+n2+i] 124*49fe348cSAndroid Build Coastguard Worker 125*49fe348cSAndroid Build Coastguard Worker for i in range(2*n4, 2*n4+n2): 126*49fe348cSAndroid Build Coastguard Worker e[2*i+0] = e[2*i+1] = e[2*n4+n2+i] 127*49fe348cSAndroid Build Coastguard Worker 128*49fe348cSAndroid Build Coastguard Worker elif len(e) < 64: 129*49fe348cSAndroid Build Coastguard Worker n2 = 64 - len(e) 130*49fe348cSAndroid Build Coastguard Worker 131*49fe348cSAndroid Build Coastguard Worker e = np.append(np.empty(n2), e) 132*49fe348cSAndroid Build Coastguard Worker for i in range(n2): 133*49fe348cSAndroid Build Coastguard Worker e[2*i+0] = e[2*i+1] = e[n2+i] 134*49fe348cSAndroid Build Coastguard Worker 135*49fe348cSAndroid Build Coastguard Worker ## Smoothing 136*49fe348cSAndroid Build Coastguard Worker 137*49fe348cSAndroid Build Coastguard Worker e_s = np.zeros(len(e)) 138*49fe348cSAndroid Build Coastguard Worker e_s[0 ] = 0.75 * e[0 ] + 0.25 * e[1 ] 139*49fe348cSAndroid Build Coastguard Worker e_s[1:63] = 0.25 * e[0:62] + 0.5 * e[1:63] + 0.25 * e[2:64] 140*49fe348cSAndroid Build Coastguard Worker e_s[ 63] = 0.25 * e[ 62] + 0.75 * e[ 63] 141*49fe348cSAndroid Build Coastguard Worker 142*49fe348cSAndroid Build Coastguard Worker ## Pre-emphasis 143*49fe348cSAndroid Build Coastguard Worker 144*49fe348cSAndroid Build Coastguard Worker g_tilt = [ 14, 18, 22, 26, 30, 30, 34 ][self.sr] 145*49fe348cSAndroid Build Coastguard Worker e_p = e_s * (10 ** ((np.arange(64) * g_tilt) / 630)) 146*49fe348cSAndroid Build Coastguard Worker 147*49fe348cSAndroid Build Coastguard Worker ## Noise floor 148*49fe348cSAndroid Build Coastguard Worker 149*49fe348cSAndroid Build Coastguard Worker noise_floor = max(np.average(e_p) * (10 ** (-40/10)), 2 ** -32) 150*49fe348cSAndroid Build Coastguard Worker e_p = np.fmax(e_p, noise_floor * np.ones(len(e))) 151*49fe348cSAndroid Build Coastguard Worker 152*49fe348cSAndroid Build Coastguard Worker ## Logarithm 153*49fe348cSAndroid Build Coastguard Worker 154*49fe348cSAndroid Build Coastguard Worker e_l = np.log2(10 ** -31 + e_p) / 2 155*49fe348cSAndroid Build Coastguard Worker 156*49fe348cSAndroid Build Coastguard Worker ## Band energy grouping 157*49fe348cSAndroid Build Coastguard Worker 158*49fe348cSAndroid Build Coastguard Worker w = [ 1/12, 2/12, 3/12, 3/12, 2/12, 1/12 ] 159*49fe348cSAndroid Build Coastguard Worker 160*49fe348cSAndroid Build Coastguard Worker e_4 = np.zeros(len(e_l) // 4) 161*49fe348cSAndroid Build Coastguard Worker e_4[0 ] = w[0] * e_l[0] + np.sum(w[1:] * e_l[:5]) 162*49fe348cSAndroid Build Coastguard Worker e_4[1:15] = [ np.sum(w * e_l[4*i-1:4*i+5]) for i in range(1, 15) ] 163*49fe348cSAndroid Build Coastguard Worker e_4[ 15] = np.sum(w[:5] * e_l[59:64]) + w[5] * e_l[63] 164*49fe348cSAndroid Build Coastguard Worker 165*49fe348cSAndroid Build Coastguard Worker ## Mean removal and scaling, attack handling 166*49fe348cSAndroid Build Coastguard Worker 167*49fe348cSAndroid Build Coastguard Worker cf = [ 0.85, 0.6 ][hr] 168*49fe348cSAndroid Build Coastguard Worker if hr and nbytes * 8 > [ 1150, 2300, 0, 4400 ][self.dt]: 169*49fe348cSAndroid Build Coastguard Worker cf *= [ 0.25, 0.35 ][ self.dt == T.DT_10M ] 170*49fe348cSAndroid Build Coastguard Worker 171*49fe348cSAndroid Build Coastguard Worker scf = cf * (e_4 - np.average(e_4)) 172*49fe348cSAndroid Build Coastguard Worker 173*49fe348cSAndroid Build Coastguard Worker scf_a = np.zeros(len(scf)) 174*49fe348cSAndroid Build Coastguard Worker scf_a[0 ] = np.mean(scf[:3]) 175*49fe348cSAndroid Build Coastguard Worker scf_a[1 ] = np.mean(scf[:4]) 176*49fe348cSAndroid Build Coastguard Worker scf_a[2:14] = [ np.mean(scf[i:i+5]) for i in range(12) ] 177*49fe348cSAndroid Build Coastguard Worker scf_a[ 14] = np.mean(scf[12:]) 178*49fe348cSAndroid Build Coastguard Worker scf_a[ 15] = np.mean(scf[13:]) 179*49fe348cSAndroid Build Coastguard Worker 180*49fe348cSAndroid Build Coastguard Worker scf_a = (0.5 if self.dt != T.DT_7M5 else 0.3) * \ 181*49fe348cSAndroid Build Coastguard Worker (scf_a - np.average(scf_a)) 182*49fe348cSAndroid Build Coastguard Worker 183*49fe348cSAndroid Build Coastguard Worker return scf_a if att else scf 184*49fe348cSAndroid Build Coastguard Worker 185*49fe348cSAndroid Build Coastguard Worker def enum_mpvq(self, v): 186*49fe348cSAndroid Build Coastguard Worker 187*49fe348cSAndroid Build Coastguard Worker sign = None 188*49fe348cSAndroid Build Coastguard Worker index = 0 189*49fe348cSAndroid Build Coastguard Worker x = 0 190*49fe348cSAndroid Build Coastguard Worker 191*49fe348cSAndroid Build Coastguard Worker for (n, vn) in enumerate(v[::-1]): 192*49fe348cSAndroid Build Coastguard Worker 193*49fe348cSAndroid Build Coastguard Worker if sign is not None and vn != 0: 194*49fe348cSAndroid Build Coastguard Worker index = 2*index + sign 195*49fe348cSAndroid Build Coastguard Worker if vn != 0: 196*49fe348cSAndroid Build Coastguard Worker sign = 1 if vn < 0 else 0 197*49fe348cSAndroid Build Coastguard Worker 198*49fe348cSAndroid Build Coastguard Worker index += T.SNS_MPVQ_OFFSETS[n][x] 199*49fe348cSAndroid Build Coastguard Worker x += abs(vn) 200*49fe348cSAndroid Build Coastguard Worker 201*49fe348cSAndroid Build Coastguard Worker return (index, bool(sign)) 202*49fe348cSAndroid Build Coastguard Worker 203*49fe348cSAndroid Build Coastguard Worker def quantize(self, scf): 204*49fe348cSAndroid Build Coastguard Worker 205*49fe348cSAndroid Build Coastguard Worker ## Stage 1 206*49fe348cSAndroid Build Coastguard Worker 207*49fe348cSAndroid Build Coastguard Worker dmse_lf = [ np.sum((scf[:8] - T.SNS_LFCB[i]) ** 2) for i in range(32) ] 208*49fe348cSAndroid Build Coastguard Worker dmse_hf = [ np.sum((scf[8:] - T.SNS_HFCB[i]) ** 2) for i in range(32) ] 209*49fe348cSAndroid Build Coastguard Worker 210*49fe348cSAndroid Build Coastguard Worker self.ind_lf = np.argmin(dmse_lf) 211*49fe348cSAndroid Build Coastguard Worker self.ind_hf = np.argmin(dmse_hf) 212*49fe348cSAndroid Build Coastguard Worker 213*49fe348cSAndroid Build Coastguard Worker st1 = np.append(T.SNS_LFCB[self.ind_lf], T.SNS_HFCB[self.ind_hf]) 214*49fe348cSAndroid Build Coastguard Worker r1 = scf - st1 215*49fe348cSAndroid Build Coastguard Worker 216*49fe348cSAndroid Build Coastguard Worker ## Stage 2 217*49fe348cSAndroid Build Coastguard Worker 218*49fe348cSAndroid Build Coastguard Worker t2_rot = fftpack.dct(r1, norm = 'ortho') 219*49fe348cSAndroid Build Coastguard Worker x = np.abs(t2_rot) 220*49fe348cSAndroid Build Coastguard Worker 221*49fe348cSAndroid Build Coastguard Worker ## Stage 2 Shape search, step 1 222*49fe348cSAndroid Build Coastguard Worker 223*49fe348cSAndroid Build Coastguard Worker K = 6 224*49fe348cSAndroid Build Coastguard Worker 225*49fe348cSAndroid Build Coastguard Worker proj_fac = (K - 1) / sum(np.abs(t2_rot)) 226*49fe348cSAndroid Build Coastguard Worker y3 = np.floor(x * proj_fac).astype(int) 227*49fe348cSAndroid Build Coastguard Worker 228*49fe348cSAndroid Build Coastguard Worker ## Stage 2 Shape search, step 2 229*49fe348cSAndroid Build Coastguard Worker 230*49fe348cSAndroid Build Coastguard Worker corr_xy = np.sum(y3 * x) 231*49fe348cSAndroid Build Coastguard Worker energy_y = np.sum(y3 * y3) 232*49fe348cSAndroid Build Coastguard Worker 233*49fe348cSAndroid Build Coastguard Worker k0 = sum(y3) 234*49fe348cSAndroid Build Coastguard Worker for k in range(k0, K): 235*49fe348cSAndroid Build Coastguard Worker q_pvq = ((corr_xy + x) ** 2) / (energy_y + 2*y3 + 1) 236*49fe348cSAndroid Build Coastguard Worker n_best = np.argmax(q_pvq) 237*49fe348cSAndroid Build Coastguard Worker 238*49fe348cSAndroid Build Coastguard Worker corr_xy += x[n_best] 239*49fe348cSAndroid Build Coastguard Worker energy_y += 2*y3[n_best] + 1 240*49fe348cSAndroid Build Coastguard Worker y3[n_best] += 1 241*49fe348cSAndroid Build Coastguard Worker 242*49fe348cSAndroid Build Coastguard Worker ## Stage 2 Shape search, step 3 243*49fe348cSAndroid Build Coastguard Worker 244*49fe348cSAndroid Build Coastguard Worker K = 8 245*49fe348cSAndroid Build Coastguard Worker 246*49fe348cSAndroid Build Coastguard Worker y2 = y3.copy() 247*49fe348cSAndroid Build Coastguard Worker 248*49fe348cSAndroid Build Coastguard Worker for k in range(sum(y2), K): 249*49fe348cSAndroid Build Coastguard Worker q_pvq = ((corr_xy + x) ** 2) / (energy_y + 2*y2 + 1) 250*49fe348cSAndroid Build Coastguard Worker n_best = np.argmax(q_pvq) 251*49fe348cSAndroid Build Coastguard Worker 252*49fe348cSAndroid Build Coastguard Worker corr_xy += x[n_best] 253*49fe348cSAndroid Build Coastguard Worker energy_y += 2*y2[n_best] + 1 254*49fe348cSAndroid Build Coastguard Worker y2[n_best] += 1 255*49fe348cSAndroid Build Coastguard Worker 256*49fe348cSAndroid Build Coastguard Worker 257*49fe348cSAndroid Build Coastguard Worker ## Stage 2 Shape search, step 4 258*49fe348cSAndroid Build Coastguard Worker 259*49fe348cSAndroid Build Coastguard Worker y1 = np.append(y2[:10], [0] * 6) 260*49fe348cSAndroid Build Coastguard Worker 261*49fe348cSAndroid Build Coastguard Worker ## Stage 2 Shape search, step 5 262*49fe348cSAndroid Build Coastguard Worker 263*49fe348cSAndroid Build Coastguard Worker corr_xy -= sum(y2[10:] * x[10:]) 264*49fe348cSAndroid Build Coastguard Worker energy_y -= sum(y2[10:] * y2[10:]) 265*49fe348cSAndroid Build Coastguard Worker 266*49fe348cSAndroid Build Coastguard Worker ## Stage 2 Shape search, step 6 267*49fe348cSAndroid Build Coastguard Worker 268*49fe348cSAndroid Build Coastguard Worker K = 10 269*49fe348cSAndroid Build Coastguard Worker 270*49fe348cSAndroid Build Coastguard Worker for k in range(sum(y1), K): 271*49fe348cSAndroid Build Coastguard Worker q_pvq = ((corr_xy + x[:10]) ** 2) / (energy_y + 2*y1[:10] + 1) 272*49fe348cSAndroid Build Coastguard Worker n_best = np.argmax(q_pvq) 273*49fe348cSAndroid Build Coastguard Worker 274*49fe348cSAndroid Build Coastguard Worker corr_xy += x[n_best] 275*49fe348cSAndroid Build Coastguard Worker energy_y += 2*y1[n_best] + 1 276*49fe348cSAndroid Build Coastguard Worker y1[n_best] += 1 277*49fe348cSAndroid Build Coastguard Worker 278*49fe348cSAndroid Build Coastguard Worker ## Stage 2 Shape search, step 7 279*49fe348cSAndroid Build Coastguard Worker 280*49fe348cSAndroid Build Coastguard Worker y0 = np.append(y1[:10], [ 0 ] * 6) 281*49fe348cSAndroid Build Coastguard Worker 282*49fe348cSAndroid Build Coastguard Worker q_pvq = ((corr_xy + x[10:]) ** 2) / (energy_y + 2*y0[10:] + 1) 283*49fe348cSAndroid Build Coastguard Worker n_best = 10 + np.argmax(q_pvq) 284*49fe348cSAndroid Build Coastguard Worker 285*49fe348cSAndroid Build Coastguard Worker y0[n_best] += 1 286*49fe348cSAndroid Build Coastguard Worker 287*49fe348cSAndroid Build Coastguard Worker ## Stage 2 Shape search, step 8 288*49fe348cSAndroid Build Coastguard Worker 289*49fe348cSAndroid Build Coastguard Worker y0 *= np.sign(t2_rot).astype(int) 290*49fe348cSAndroid Build Coastguard Worker y1 *= np.sign(t2_rot).astype(int) 291*49fe348cSAndroid Build Coastguard Worker y2 *= np.sign(t2_rot).astype(int) 292*49fe348cSAndroid Build Coastguard Worker y3 *= np.sign(t2_rot).astype(int) 293*49fe348cSAndroid Build Coastguard Worker 294*49fe348cSAndroid Build Coastguard Worker ## Stage 2 Shape search, step 9 295*49fe348cSAndroid Build Coastguard Worker 296*49fe348cSAndroid Build Coastguard Worker xq = [ y / np.sqrt(sum(y ** 2)) for y in (y0, y1, y2, y3) ] 297*49fe348cSAndroid Build Coastguard Worker 298*49fe348cSAndroid Build Coastguard Worker ## Shape and gain combination determination 299*49fe348cSAndroid Build Coastguard Worker 300*49fe348cSAndroid Build Coastguard Worker G = [ T.SNS_VQ_REG_ADJ_GAINS, T.SNS_VQ_REG_LF_ADJ_GAINS, 301*49fe348cSAndroid Build Coastguard Worker T.SNS_VQ_NEAR_ADJ_GAINS, T.SNS_VQ_FAR_ADJ_GAINS ] 302*49fe348cSAndroid Build Coastguard Worker 303*49fe348cSAndroid Build Coastguard Worker dMSE = [ [ sum((t2_rot - G[j][i] * xq[j]) ** 2) 304*49fe348cSAndroid Build Coastguard Worker for i in range(len(G[j])) ] for j in range(4) ] 305*49fe348cSAndroid Build Coastguard Worker 306*49fe348cSAndroid Build Coastguard Worker self.shape = np.argmin([ np.min(dMSE[j]) for j in range(4) ]) 307*49fe348cSAndroid Build Coastguard Worker self.gain = np.argmin(dMSE[self.shape]) 308*49fe348cSAndroid Build Coastguard Worker 309*49fe348cSAndroid Build Coastguard Worker gain = G[self.shape][self.gain] 310*49fe348cSAndroid Build Coastguard Worker 311*49fe348cSAndroid Build Coastguard Worker ## Enumeration of the selected PVQ pulse configurations 312*49fe348cSAndroid Build Coastguard Worker 313*49fe348cSAndroid Build Coastguard Worker if self.shape == 0: 314*49fe348cSAndroid Build Coastguard Worker (self.idx_a, self.ls_a) = self.enum_mpvq(y0[:10]) 315*49fe348cSAndroid Build Coastguard Worker (self.idx_b, self.ls_b) = self.enum_mpvq(y0[10:]) 316*49fe348cSAndroid Build Coastguard Worker elif self.shape == 1: 317*49fe348cSAndroid Build Coastguard Worker (self.idx_a, self.ls_a) = self.enum_mpvq(y1[:10]) 318*49fe348cSAndroid Build Coastguard Worker (self.idx_b, self.ls_b) = (None, None) 319*49fe348cSAndroid Build Coastguard Worker elif self.shape == 2: 320*49fe348cSAndroid Build Coastguard Worker (self.idx_a, self.ls_a) = self.enum_mpvq(y2) 321*49fe348cSAndroid Build Coastguard Worker (self.idx_b, self.ls_b) = (None, None) 322*49fe348cSAndroid Build Coastguard Worker elif self.shape == 3: 323*49fe348cSAndroid Build Coastguard Worker (self.idx_a, self.ls_a) = self.enum_mpvq(y3) 324*49fe348cSAndroid Build Coastguard Worker (self.idx_b, self.ls_b) = (None, None) 325*49fe348cSAndroid Build Coastguard Worker 326*49fe348cSAndroid Build Coastguard Worker ## Synthesis of the Quantized scale factor 327*49fe348cSAndroid Build Coastguard Worker 328*49fe348cSAndroid Build Coastguard Worker scf_q = st1 + gain * fftpack.idct(xq[self.shape], norm = 'ortho') 329*49fe348cSAndroid Build Coastguard Worker 330*49fe348cSAndroid Build Coastguard Worker return scf_q 331*49fe348cSAndroid Build Coastguard Worker 332*49fe348cSAndroid Build Coastguard Worker def run(self, eb, att, nbytes, x): 333*49fe348cSAndroid Build Coastguard Worker 334*49fe348cSAndroid Build Coastguard Worker scf = self.compute_scale_factors(eb, att, nbytes) 335*49fe348cSAndroid Build Coastguard Worker scf_q = self.quantize(scf) 336*49fe348cSAndroid Build Coastguard Worker y = self.spectral_shaping(scf_q, False, x) 337*49fe348cSAndroid Build Coastguard Worker 338*49fe348cSAndroid Build Coastguard Worker return y 339*49fe348cSAndroid Build Coastguard Worker 340*49fe348cSAndroid Build Coastguard Worker def store(self, b): 341*49fe348cSAndroid Build Coastguard Worker 342*49fe348cSAndroid Build Coastguard Worker shape = self.shape 343*49fe348cSAndroid Build Coastguard Worker gain_msb_bits = np.array([ 1, 1, 2, 2 ])[shape] 344*49fe348cSAndroid Build Coastguard Worker gain_lsb_bits = np.array([ 0, 1, 0, 1 ])[shape] 345*49fe348cSAndroid Build Coastguard Worker 346*49fe348cSAndroid Build Coastguard Worker b.write_uint(self.ind_lf, 5) 347*49fe348cSAndroid Build Coastguard Worker b.write_uint(self.ind_hf, 5) 348*49fe348cSAndroid Build Coastguard Worker 349*49fe348cSAndroid Build Coastguard Worker b.write_bit(shape >> 1) 350*49fe348cSAndroid Build Coastguard Worker 351*49fe348cSAndroid Build Coastguard Worker b.write_uint(self.gain >> gain_lsb_bits, gain_msb_bits) 352*49fe348cSAndroid Build Coastguard Worker 353*49fe348cSAndroid Build Coastguard Worker b.write_bit(self.ls_a) 354*49fe348cSAndroid Build Coastguard Worker 355*49fe348cSAndroid Build Coastguard Worker if self.shape == 0: 356*49fe348cSAndroid Build Coastguard Worker sz_shape_a = 2390004 357*49fe348cSAndroid Build Coastguard Worker index_joint = self.idx_a + \ 358*49fe348cSAndroid Build Coastguard Worker (2 * self.idx_b + self.ls_b + 2) * sz_shape_a 359*49fe348cSAndroid Build Coastguard Worker 360*49fe348cSAndroid Build Coastguard Worker elif self.shape == 1: 361*49fe348cSAndroid Build Coastguard Worker sz_shape_a = 2390004 362*49fe348cSAndroid Build Coastguard Worker index_joint = self.idx_a + (self.gain & 1) * sz_shape_a 363*49fe348cSAndroid Build Coastguard Worker 364*49fe348cSAndroid Build Coastguard Worker elif self.shape == 2: 365*49fe348cSAndroid Build Coastguard Worker index_joint = self.idx_a 366*49fe348cSAndroid Build Coastguard Worker 367*49fe348cSAndroid Build Coastguard Worker elif self.shape == 3: 368*49fe348cSAndroid Build Coastguard Worker sz_shape_a = 15158272 369*49fe348cSAndroid Build Coastguard Worker index_joint = sz_shape_a + (self.gain & 1) + 2 * self.idx_a 370*49fe348cSAndroid Build Coastguard Worker 371*49fe348cSAndroid Build Coastguard Worker b.write_uint(index_joint, 14 - gain_msb_bits) 372*49fe348cSAndroid Build Coastguard Worker b.write_uint(index_joint >> (14 - gain_msb_bits), 12) 373*49fe348cSAndroid Build Coastguard Worker 374*49fe348cSAndroid Build Coastguard Worker 375*49fe348cSAndroid Build Coastguard Workerclass SnsSynthesis(Sns): 376*49fe348cSAndroid Build Coastguard Worker 377*49fe348cSAndroid Build Coastguard Worker def __init__(self, dt, sr): 378*49fe348cSAndroid Build Coastguard Worker 379*49fe348cSAndroid Build Coastguard Worker super().__init__(dt, sr) 380*49fe348cSAndroid Build Coastguard Worker 381*49fe348cSAndroid Build Coastguard Worker def deenum_mpvq(self, index, ls, npulses, n): 382*49fe348cSAndroid Build Coastguard Worker 383*49fe348cSAndroid Build Coastguard Worker y = np.zeros(n, dtype=np.intc) 384*49fe348cSAndroid Build Coastguard Worker pos = 0 385*49fe348cSAndroid Build Coastguard Worker 386*49fe348cSAndroid Build Coastguard Worker for i in range(len(y)-1, -1, -1): 387*49fe348cSAndroid Build Coastguard Worker 388*49fe348cSAndroid Build Coastguard Worker if index > 0: 389*49fe348cSAndroid Build Coastguard Worker yi = 0 390*49fe348cSAndroid Build Coastguard Worker while index < T.SNS_MPVQ_OFFSETS[i][npulses - yi]: yi += 1 391*49fe348cSAndroid Build Coastguard Worker index -= T.SNS_MPVQ_OFFSETS[i][npulses - yi] 392*49fe348cSAndroid Build Coastguard Worker else: 393*49fe348cSAndroid Build Coastguard Worker yi = npulses 394*49fe348cSAndroid Build Coastguard Worker 395*49fe348cSAndroid Build Coastguard Worker y[pos] = [ yi, -yi ][int(ls)] 396*49fe348cSAndroid Build Coastguard Worker pos += 1 397*49fe348cSAndroid Build Coastguard Worker 398*49fe348cSAndroid Build Coastguard Worker npulses -= yi 399*49fe348cSAndroid Build Coastguard Worker if npulses <= 0: 400*49fe348cSAndroid Build Coastguard Worker break 401*49fe348cSAndroid Build Coastguard Worker 402*49fe348cSAndroid Build Coastguard Worker if yi > 0: 403*49fe348cSAndroid Build Coastguard Worker ls = index & 1 404*49fe348cSAndroid Build Coastguard Worker index >>= 1 405*49fe348cSAndroid Build Coastguard Worker 406*49fe348cSAndroid Build Coastguard Worker return y 407*49fe348cSAndroid Build Coastguard Worker 408*49fe348cSAndroid Build Coastguard Worker def unquantize(self): 409*49fe348cSAndroid Build Coastguard Worker 410*49fe348cSAndroid Build Coastguard Worker ## SNS VQ Decoding 411*49fe348cSAndroid Build Coastguard Worker 412*49fe348cSAndroid Build Coastguard Worker y = np.empty(16, dtype=np.intc) 413*49fe348cSAndroid Build Coastguard Worker 414*49fe348cSAndroid Build Coastguard Worker if self.shape == 0: 415*49fe348cSAndroid Build Coastguard Worker y[:10] = self.deenum_mpvq(self.idx_a, self.ls_a, 10, 10) 416*49fe348cSAndroid Build Coastguard Worker y[10:] = self.deenum_mpvq(self.idx_b, self.ls_b, 1, 6) 417*49fe348cSAndroid Build Coastguard Worker elif self.shape == 1: 418*49fe348cSAndroid Build Coastguard Worker y[:10] = self.deenum_mpvq(self.idx_a, self.ls_a, 10, 10) 419*49fe348cSAndroid Build Coastguard Worker y[10:] = np.zeros(6, dtype=np.intc) 420*49fe348cSAndroid Build Coastguard Worker elif self.shape == 2: 421*49fe348cSAndroid Build Coastguard Worker y = self.deenum_mpvq(self.idx_a, self.ls_a, 8, 16) 422*49fe348cSAndroid Build Coastguard Worker elif self.shape == 3: 423*49fe348cSAndroid Build Coastguard Worker y = self.deenum_mpvq(self.idx_a, self.ls_a, 6, 16) 424*49fe348cSAndroid Build Coastguard Worker 425*49fe348cSAndroid Build Coastguard Worker ## Unit energy normalization 426*49fe348cSAndroid Build Coastguard Worker 427*49fe348cSAndroid Build Coastguard Worker y = y / np.sqrt(sum(y ** 2)) 428*49fe348cSAndroid Build Coastguard Worker 429*49fe348cSAndroid Build Coastguard Worker ## Reconstruction of the quantized scale factors 430*49fe348cSAndroid Build Coastguard Worker 431*49fe348cSAndroid Build Coastguard Worker G = [ T.SNS_VQ_REG_ADJ_GAINS, T.SNS_VQ_REG_LF_ADJ_GAINS, 432*49fe348cSAndroid Build Coastguard Worker T.SNS_VQ_NEAR_ADJ_GAINS, T.SNS_VQ_FAR_ADJ_GAINS ] 433*49fe348cSAndroid Build Coastguard Worker 434*49fe348cSAndroid Build Coastguard Worker gain = G[self.shape][self.gain] 435*49fe348cSAndroid Build Coastguard Worker 436*49fe348cSAndroid Build Coastguard Worker scf = np.append(T.SNS_LFCB[self.ind_lf], T.SNS_HFCB[self.ind_hf]) \ 437*49fe348cSAndroid Build Coastguard Worker + gain * fftpack.idct(y, norm = 'ortho') 438*49fe348cSAndroid Build Coastguard Worker 439*49fe348cSAndroid Build Coastguard Worker return scf 440*49fe348cSAndroid Build Coastguard Worker 441*49fe348cSAndroid Build Coastguard Worker def load(self, b): 442*49fe348cSAndroid Build Coastguard Worker 443*49fe348cSAndroid Build Coastguard Worker self.ind_lf = b.read_uint(5) 444*49fe348cSAndroid Build Coastguard Worker self.ind_hf = b.read_uint(5) 445*49fe348cSAndroid Build Coastguard Worker 446*49fe348cSAndroid Build Coastguard Worker shape_msb = b.read_bit() 447*49fe348cSAndroid Build Coastguard Worker 448*49fe348cSAndroid Build Coastguard Worker gain_msb_bits = 1 + shape_msb 449*49fe348cSAndroid Build Coastguard Worker self.gain = b.read_uint(gain_msb_bits) 450*49fe348cSAndroid Build Coastguard Worker 451*49fe348cSAndroid Build Coastguard Worker self.ls_a = b.read_bit() 452*49fe348cSAndroid Build Coastguard Worker 453*49fe348cSAndroid Build Coastguard Worker index_joint = b.read_uint(14 - gain_msb_bits) 454*49fe348cSAndroid Build Coastguard Worker index_joint |= b.read_uint(12) << (14 - gain_msb_bits) 455*49fe348cSAndroid Build Coastguard Worker 456*49fe348cSAndroid Build Coastguard Worker if shape_msb == 0: 457*49fe348cSAndroid Build Coastguard Worker sz_shape_a = 2390004 458*49fe348cSAndroid Build Coastguard Worker 459*49fe348cSAndroid Build Coastguard Worker if index_joint >= sz_shape_a * 14: 460*49fe348cSAndroid Build Coastguard Worker raise ValueError('Invalide SNS joint index') 461*49fe348cSAndroid Build Coastguard Worker 462*49fe348cSAndroid Build Coastguard Worker self.idx_a = index_joint % sz_shape_a 463*49fe348cSAndroid Build Coastguard Worker index_joint = index_joint // sz_shape_a 464*49fe348cSAndroid Build Coastguard Worker if index_joint >= 2: 465*49fe348cSAndroid Build Coastguard Worker self.shape = 0 466*49fe348cSAndroid Build Coastguard Worker self.idx_b = (index_joint - 2) // 2 467*49fe348cSAndroid Build Coastguard Worker self.ls_b = (index_joint - 2) % 2 468*49fe348cSAndroid Build Coastguard Worker else: 469*49fe348cSAndroid Build Coastguard Worker self.shape = 1 470*49fe348cSAndroid Build Coastguard Worker self.gain = (self.gain << 1) + (index_joint & 1) 471*49fe348cSAndroid Build Coastguard Worker 472*49fe348cSAndroid Build Coastguard Worker else: 473*49fe348cSAndroid Build Coastguard Worker sz_shape_a = 15158272 474*49fe348cSAndroid Build Coastguard Worker if index_joint >= sz_shape_a + 1549824: 475*49fe348cSAndroid Build Coastguard Worker raise ValueError('Invalide SNS joint index') 476*49fe348cSAndroid Build Coastguard Worker 477*49fe348cSAndroid Build Coastguard Worker if index_joint < sz_shape_a: 478*49fe348cSAndroid Build Coastguard Worker self.shape = 2 479*49fe348cSAndroid Build Coastguard Worker self.idx_a = index_joint 480*49fe348cSAndroid Build Coastguard Worker else: 481*49fe348cSAndroid Build Coastguard Worker self.shape = 3 482*49fe348cSAndroid Build Coastguard Worker index_joint -= sz_shape_a 483*49fe348cSAndroid Build Coastguard Worker self.gain = (self.gain << 1) + (index_joint % 2) 484*49fe348cSAndroid Build Coastguard Worker self.idx_a = index_joint // 2 485*49fe348cSAndroid Build Coastguard Worker 486*49fe348cSAndroid Build Coastguard Worker def run(self, x): 487*49fe348cSAndroid Build Coastguard Worker 488*49fe348cSAndroid Build Coastguard Worker scf = self.unquantize() 489*49fe348cSAndroid Build Coastguard Worker y = self.spectral_shaping(scf, True, x) 490*49fe348cSAndroid Build Coastguard Worker 491*49fe348cSAndroid Build Coastguard Worker return y 492*49fe348cSAndroid Build Coastguard Worker 493*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ### 494*49fe348cSAndroid Build Coastguard Worker 495*49fe348cSAndroid Build Coastguard Workerdef check_analysis(rng, dt, sr): 496*49fe348cSAndroid Build Coastguard Worker 497*49fe348cSAndroid Build Coastguard Worker ok = True 498*49fe348cSAndroid Build Coastguard Worker 499*49fe348cSAndroid Build Coastguard Worker analysis = SnsAnalysis(dt, sr) 500*49fe348cSAndroid Build Coastguard Worker 501*49fe348cSAndroid Build Coastguard Worker for i in range(10): 502*49fe348cSAndroid Build Coastguard Worker ne = T.I[dt][sr][-1] 503*49fe348cSAndroid Build Coastguard Worker x = rng.random(ne) * 1e4 504*49fe348cSAndroid Build Coastguard Worker e = rng.random(len(T.I[dt][sr]) - 1) * 1e10 505*49fe348cSAndroid Build Coastguard Worker 506*49fe348cSAndroid Build Coastguard Worker if sr >= T.SRATE_48K_HR: 507*49fe348cSAndroid Build Coastguard Worker for nbits in (1144, 1152, 2296, 2304, 4400, 4408): 508*49fe348cSAndroid Build Coastguard Worker y = analysis.run(e, False, nbits // 8, x) 509*49fe348cSAndroid Build Coastguard Worker data = analysis.get_data() 510*49fe348cSAndroid Build Coastguard Worker 511*49fe348cSAndroid Build Coastguard Worker (y_c, data_c) = lc3.sns_analyze( 512*49fe348cSAndroid Build Coastguard Worker dt, sr, nbits // 8, e, False, x) 513*49fe348cSAndroid Build Coastguard Worker 514*49fe348cSAndroid Build Coastguard Worker for k in data.keys(): 515*49fe348cSAndroid Build Coastguard Worker ok = ok and data_c[k] == data[k] 516*49fe348cSAndroid Build Coastguard Worker 517*49fe348cSAndroid Build Coastguard Worker ok = ok and lc3.sns_get_nbits() == analysis.get_nbits() 518*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(y - y_c)) < 1e-1 519*49fe348cSAndroid Build Coastguard Worker 520*49fe348cSAndroid Build Coastguard Worker else: 521*49fe348cSAndroid Build Coastguard Worker for att in (0, 1): 522*49fe348cSAndroid Build Coastguard Worker y = analysis.run(e, att, 0, x) 523*49fe348cSAndroid Build Coastguard Worker data = analysis.get_data() 524*49fe348cSAndroid Build Coastguard Worker 525*49fe348cSAndroid Build Coastguard Worker (y_c, data_c) = lc3.sns_analyze(dt, sr, 0, e, att, x) 526*49fe348cSAndroid Build Coastguard Worker 527*49fe348cSAndroid Build Coastguard Worker for k in data.keys(): 528*49fe348cSAndroid Build Coastguard Worker ok = ok and data_c[k] == data[k] 529*49fe348cSAndroid Build Coastguard Worker 530*49fe348cSAndroid Build Coastguard Worker ok = ok and lc3.sns_get_nbits() == analysis.get_nbits() 531*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(y - y_c)) < 1e-1 532*49fe348cSAndroid Build Coastguard Worker 533*49fe348cSAndroid Build Coastguard Worker return ok 534*49fe348cSAndroid Build Coastguard Worker 535*49fe348cSAndroid Build Coastguard Workerdef check_synthesis(rng, dt, sr): 536*49fe348cSAndroid Build Coastguard Worker 537*49fe348cSAndroid Build Coastguard Worker ok = True 538*49fe348cSAndroid Build Coastguard Worker 539*49fe348cSAndroid Build Coastguard Worker synthesis = SnsSynthesis(dt, sr) 540*49fe348cSAndroid Build Coastguard Worker 541*49fe348cSAndroid Build Coastguard Worker for i in range(100): 542*49fe348cSAndroid Build Coastguard Worker 543*49fe348cSAndroid Build Coastguard Worker synthesis.ind_lf = rng.integers(0, 32) 544*49fe348cSAndroid Build Coastguard Worker synthesis.ind_hf = rng.integers(0, 32) 545*49fe348cSAndroid Build Coastguard Worker 546*49fe348cSAndroid Build Coastguard Worker shape = rng.integers(0, 4) 547*49fe348cSAndroid Build Coastguard Worker sz_shape_a = [ 2390004, 2390004, 15158272, 774912 ][shape] 548*49fe348cSAndroid Build Coastguard Worker sz_shape_b = [ 6, 1, 0, 0 ][shape] 549*49fe348cSAndroid Build Coastguard Worker synthesis.shape = shape 550*49fe348cSAndroid Build Coastguard Worker synthesis.gain = rng.integers(0, [ 2, 4, 4, 8 ][shape]) 551*49fe348cSAndroid Build Coastguard Worker synthesis.idx_a = rng.integers(0, sz_shape_a, endpoint=True) 552*49fe348cSAndroid Build Coastguard Worker synthesis.ls_a = bool(rng.integers(0, 1, endpoint=True)) 553*49fe348cSAndroid Build Coastguard Worker synthesis.idx_b = rng.integers(0, sz_shape_b, endpoint=True) 554*49fe348cSAndroid Build Coastguard Worker synthesis.ls_b = bool(rng.integers(0, 1, endpoint=True)) 555*49fe348cSAndroid Build Coastguard Worker 556*49fe348cSAndroid Build Coastguard Worker ne = T.I[dt][sr][-1] 557*49fe348cSAndroid Build Coastguard Worker x = rng.random(ne) * 1e4 558*49fe348cSAndroid Build Coastguard Worker 559*49fe348cSAndroid Build Coastguard Worker y = synthesis.run(x) 560*49fe348cSAndroid Build Coastguard Worker y_c = lc3.sns_synthesize(dt, sr, synthesis.get_data(), x) 561*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(1 - y/y_c)) < 1e-5 562*49fe348cSAndroid Build Coastguard Worker 563*49fe348cSAndroid Build Coastguard Worker return ok 564*49fe348cSAndroid Build Coastguard Worker 565*49fe348cSAndroid Build Coastguard Workerdef check_analysis_appendix_c(dt): 566*49fe348cSAndroid Build Coastguard Worker 567*49fe348cSAndroid Build Coastguard Worker i0 = dt - T.DT_7M5 568*49fe348cSAndroid Build Coastguard Worker sr = T.SRATE_16K 569*49fe348cSAndroid Build Coastguard Worker 570*49fe348cSAndroid Build Coastguard Worker ok = True 571*49fe348cSAndroid Build Coastguard Worker 572*49fe348cSAndroid Build Coastguard Worker for i in range(len(C.E_B[i0])): 573*49fe348cSAndroid Build Coastguard Worker 574*49fe348cSAndroid Build Coastguard Worker scf = lc3.sns_compute_scale_factors(dt, sr, 0, C.E_B[i0][i], False) 575*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(scf - C.SCF[i0][i])) < 1e-4 576*49fe348cSAndroid Build Coastguard Worker 577*49fe348cSAndroid Build Coastguard Worker (lf, hf) = lc3.sns_resolve_codebooks(scf) 578*49fe348cSAndroid Build Coastguard Worker ok = ok and lf == C.IND_LF[i0][i] and hf == C.IND_HF[i0][i] 579*49fe348cSAndroid Build Coastguard Worker 580*49fe348cSAndroid Build Coastguard Worker (y, yn, shape, gain) = lc3.sns_quantize(scf, lf, hf) 581*49fe348cSAndroid Build Coastguard Worker ok = ok and np.any(y[0][:16] - C.SNS_Y0[i0][i] == 0) 582*49fe348cSAndroid Build Coastguard Worker ok = ok and np.any(y[1][:10] - C.SNS_Y1[i0][i] == 0) 583*49fe348cSAndroid Build Coastguard Worker ok = ok and np.any(y[2][:16] - C.SNS_Y2[i0][i] == 0) 584*49fe348cSAndroid Build Coastguard Worker ok = ok and np.any(y[3][:16] - C.SNS_Y3[i0][i] == 0) 585*49fe348cSAndroid Build Coastguard Worker ok = ok and shape == 2*C.SUBMODE_MSB[i0][i] + C.SUBMODE_LSB[i0][i] 586*49fe348cSAndroid Build Coastguard Worker ok = ok and gain == C.G_IND[i0][i] 587*49fe348cSAndroid Build Coastguard Worker 588*49fe348cSAndroid Build Coastguard Worker scf_q = lc3.sns_unquantize(lf, hf, yn[shape], shape, gain) 589*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(scf_q - C.SCF_Q[i0][i])) < 1e-5 590*49fe348cSAndroid Build Coastguard Worker 591*49fe348cSAndroid Build Coastguard Worker x = lc3.sns_spectral_shaping(dt, sr, C.SCF_Q[i0][i], False, C.X[i0][i]) 592*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(1 - x/C.X_S[i0][i])) < 1e-5 593*49fe348cSAndroid Build Coastguard Worker 594*49fe348cSAndroid Build Coastguard Worker (x, data) = lc3.sns_analyze(dt, sr, 0, C.E_B[i0][i], False, C.X[i0][i]) 595*49fe348cSAndroid Build Coastguard Worker ok = ok and data['lfcb'] == C.IND_LF[i0][i] 596*49fe348cSAndroid Build Coastguard Worker ok = ok and data['hfcb'] == C.IND_HF[i0][i] 597*49fe348cSAndroid Build Coastguard Worker ok = ok and data['shape'] == 2*C.SUBMODE_MSB[i0][i] + \ 598*49fe348cSAndroid Build Coastguard Worker C.SUBMODE_LSB[i0][i] 599*49fe348cSAndroid Build Coastguard Worker ok = ok and data['gain'] == C.G_IND[i0][i] 600*49fe348cSAndroid Build Coastguard Worker ok = ok and data['idx_a'] == C.IDX_A[i0][i] 601*49fe348cSAndroid Build Coastguard Worker ok = ok and data['ls_a'] == C.LS_IND_A[i0][i] 602*49fe348cSAndroid Build Coastguard Worker ok = ok and (C.IDX_B[i0][i] is None or 603*49fe348cSAndroid Build Coastguard Worker data['idx_b'] == C.IDX_B[i0][i]) 604*49fe348cSAndroid Build Coastguard Worker ok = ok and (C.LS_IND_B[i0][i] is None or 605*49fe348cSAndroid Build Coastguard Worker data['ls_b'] == C.LS_IND_B[i0][i]) 606*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(1 - x/C.X_S[i0][i])) < 1e-5 607*49fe348cSAndroid Build Coastguard Worker 608*49fe348cSAndroid Build Coastguard Worker return ok 609*49fe348cSAndroid Build Coastguard Worker 610*49fe348cSAndroid Build Coastguard Workerdef check_synthesis_appendix_c(dt): 611*49fe348cSAndroid Build Coastguard Worker 612*49fe348cSAndroid Build Coastguard Worker i0 = dt - T.DT_7M5 613*49fe348cSAndroid Build Coastguard Worker sr = T.SRATE_16K 614*49fe348cSAndroid Build Coastguard Worker 615*49fe348cSAndroid Build Coastguard Worker ok = True 616*49fe348cSAndroid Build Coastguard Worker 617*49fe348cSAndroid Build Coastguard Worker for i in range(len(C.X_HAT_TNS[i0])): 618*49fe348cSAndroid Build Coastguard Worker 619*49fe348cSAndroid Build Coastguard Worker data = { 620*49fe348cSAndroid Build Coastguard Worker 'lfcb' : C.IND_LF[i0][i], 'hfcb' : C.IND_HF[i0][i], 621*49fe348cSAndroid Build Coastguard Worker 'shape' : 2*C.SUBMODE_MSB[i0][i] + C.SUBMODE_LSB[i0][i], 622*49fe348cSAndroid Build Coastguard Worker 'gain' : C.G_IND[i0][i], 623*49fe348cSAndroid Build Coastguard Worker 'idx_a' : C.IDX_A[i0][i], 624*49fe348cSAndroid Build Coastguard Worker 'ls_a' : C.LS_IND_A[i0][i], 625*49fe348cSAndroid Build Coastguard Worker 'idx_b' : C.IDX_B[i0][i] if C.IDX_B[i0][i] is not None else 0, 626*49fe348cSAndroid Build Coastguard Worker 'ls_b' : C.LS_IND_B[i0][i] if C.LS_IND_B[i0][i] is not None else 0, 627*49fe348cSAndroid Build Coastguard Worker } 628*49fe348cSAndroid Build Coastguard Worker 629*49fe348cSAndroid Build Coastguard Worker x = lc3.sns_synthesize(dt, sr, data, C.X_HAT_TNS[i0][i]) 630*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(x - C.X_HAT_SNS[i0][i])) < 1e0 631*49fe348cSAndroid Build Coastguard Worker 632*49fe348cSAndroid Build Coastguard Worker return ok 633*49fe348cSAndroid Build Coastguard Worker 634*49fe348cSAndroid Build Coastguard Workerdef check(): 635*49fe348cSAndroid Build Coastguard Worker 636*49fe348cSAndroid Build Coastguard Worker rng = np.random.default_rng(1234) 637*49fe348cSAndroid Build Coastguard Worker ok = True 638*49fe348cSAndroid Build Coastguard Worker 639*49fe348cSAndroid Build Coastguard Worker for dt in range(T.NUM_DT): 640*49fe348cSAndroid Build Coastguard Worker for sr in range(T.SRATE_8K, T.SRATE_48K + 1): 641*49fe348cSAndroid Build Coastguard Worker ok = ok and check_analysis(rng, dt, sr) 642*49fe348cSAndroid Build Coastguard Worker ok = ok and check_synthesis(rng, dt, sr) 643*49fe348cSAndroid Build Coastguard Worker 644*49fe348cSAndroid Build Coastguard Worker for dt in ( T.DT_2M5, T.DT_5M, T.DT_10M ): 645*49fe348cSAndroid Build Coastguard Worker for sr in ( T.SRATE_48K_HR, T.SRATE_96K_HR ): 646*49fe348cSAndroid Build Coastguard Worker ok = ok and check_analysis(rng, dt, sr) 647*49fe348cSAndroid Build Coastguard Worker ok = ok and check_synthesis(rng, dt, sr) 648*49fe348cSAndroid Build Coastguard Worker 649*49fe348cSAndroid Build Coastguard Worker for dt in ( T.DT_7M5, T.DT_10M ): 650*49fe348cSAndroid Build Coastguard Worker check_analysis_appendix_c(dt) 651*49fe348cSAndroid Build Coastguard Worker check_synthesis_appendix_c(dt) 652*49fe348cSAndroid Build Coastguard Worker 653*49fe348cSAndroid Build Coastguard Worker return ok 654*49fe348cSAndroid Build Coastguard Worker 655*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ### 656