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