14930cef6SMatthias Ringwald# 24930cef6SMatthias Ringwald# Copyright 2022 Google LLC 34930cef6SMatthias Ringwald# 44930cef6SMatthias Ringwald# Licensed under the Apache License, Version 2.0 (the "License"); 54930cef6SMatthias Ringwald# you may not use this file except in compliance with the License. 64930cef6SMatthias Ringwald# You may obtain a copy of the License at 74930cef6SMatthias Ringwald# 84930cef6SMatthias Ringwald# http://www.apache.org/licenses/LICENSE-2.0 94930cef6SMatthias Ringwald# 104930cef6SMatthias Ringwald# Unless required by applicable law or agreed to in writing, software 114930cef6SMatthias Ringwald# distributed under the License is distributed on an "AS IS" BASIS, 124930cef6SMatthias Ringwald# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134930cef6SMatthias Ringwald# See the License for the specific language governing permissions and 144930cef6SMatthias Ringwald# limitations under the License. 154930cef6SMatthias Ringwald# 164930cef6SMatthias Ringwald 174930cef6SMatthias Ringwaldimport numpy as np 184930cef6SMatthias Ringwaldimport scipy.fftpack as fftpack 194930cef6SMatthias Ringwald 204c4eb519SMatthias Ringwaldimport lc3 214930cef6SMatthias Ringwaldimport tables as T, appendix_c as C 224930cef6SMatthias Ringwald 234930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 244930cef6SMatthias Ringwald 254930cef6SMatthias Ringwaldclass Sns: 264930cef6SMatthias Ringwald 274930cef6SMatthias Ringwald def __init__(self, dt, sr): 284930cef6SMatthias Ringwald 294930cef6SMatthias Ringwald self.dt = dt 304930cef6SMatthias Ringwald self.sr = sr 31*6897da5cSDirk Helbig self.I = T.I[dt][sr] 324930cef6SMatthias Ringwald 334930cef6SMatthias Ringwald (self.ind_lf, self.ind_hf, self.shape, self.gain) = \ 344930cef6SMatthias Ringwald (None, None, None, None) 354930cef6SMatthias Ringwald 364930cef6SMatthias Ringwald (self.idx_a, self.ls_a, self.idx_b, self.ls_b) = \ 374930cef6SMatthias Ringwald (None, None, None, None) 384930cef6SMatthias Ringwald 394930cef6SMatthias Ringwald def get_data(self): 404930cef6SMatthias Ringwald 414930cef6SMatthias Ringwald data = { 'lfcb' : self.ind_lf, 'hfcb' : self.ind_hf, 424930cef6SMatthias Ringwald 'shape' : self.shape, 'gain' : self.gain, 434930cef6SMatthias Ringwald 'idx_a' : self.idx_a, 'ls_a' : self.ls_a } 444930cef6SMatthias Ringwald 454930cef6SMatthias Ringwald if self.idx_b is not None: 464930cef6SMatthias Ringwald data.update({ 'idx_b' : self.idx_b, 'ls_b' : self.ls_b }) 474930cef6SMatthias Ringwald 484930cef6SMatthias Ringwald return data 494930cef6SMatthias Ringwald 504930cef6SMatthias Ringwald def get_nbits(self): 514930cef6SMatthias Ringwald 524930cef6SMatthias Ringwald return 38 534930cef6SMatthias Ringwald 544930cef6SMatthias Ringwald def spectral_shaping(self, scf, inv, x): 554930cef6SMatthias Ringwald 56*6897da5cSDirk Helbig ## Scale factors interpolation 574930cef6SMatthias Ringwald 584930cef6SMatthias Ringwald scf_i = np.empty(4*len(scf)) 594930cef6SMatthias Ringwald scf_i[0 ] = scf[0] 604930cef6SMatthias Ringwald scf_i[1 ] = scf[0] 614930cef6SMatthias Ringwald scf_i[2:62:4] = scf[:15] + 1/8 * (scf[1:] - scf[:15]) 624930cef6SMatthias Ringwald scf_i[3:63:4] = scf[:15] + 3/8 * (scf[1:] - scf[:15]) 634930cef6SMatthias Ringwald scf_i[4:64:4] = scf[:15] + 5/8 * (scf[1:] - scf[:15]) 644930cef6SMatthias Ringwald scf_i[5:64:4] = scf[:15] + 7/8 * (scf[1:] - scf[:15]) 654930cef6SMatthias Ringwald scf_i[62 ] = scf[15 ] + 1/8 * (scf[15] - scf[14 ]) 664930cef6SMatthias Ringwald scf_i[63 ] = scf[15 ] + 3/8 * (scf[15] - scf[14 ]) 674930cef6SMatthias Ringwald 68*6897da5cSDirk Helbig nb = len(self.I) - 1 69*6897da5cSDirk Helbig 70*6897da5cSDirk Helbig if nb < 32: 71*6897da5cSDirk Helbig n4 = round(abs(1-32/nb)*nb) 72*6897da5cSDirk Helbig n2 = nb - n4 73*6897da5cSDirk Helbig 74*6897da5cSDirk Helbig for i in range(n4): 75*6897da5cSDirk Helbig scf_i[i] = np.mean(scf_i[4*i:4*i+4]) 76*6897da5cSDirk Helbig 77*6897da5cSDirk Helbig for i in range(n4, n4+n2): 78*6897da5cSDirk Helbig scf_i[i] = np.mean(scf_i[2*n4+2*i:2*n4+2*i+2]) 79*6897da5cSDirk Helbig 80*6897da5cSDirk Helbig scf_i = scf_i[:n4+n2] 81*6897da5cSDirk Helbig 82*6897da5cSDirk Helbig elif nb < 64: 83*6897da5cSDirk Helbig n2 = 64 - nb 844930cef6SMatthias Ringwald 854930cef6SMatthias Ringwald for i in range(n2): 86*6897da5cSDirk Helbig scf_i[i] = np.mean(scf_i[2*i:2*i+2]) 874930cef6SMatthias Ringwald scf_i = np.append(scf_i[:n2], scf_i[2*n2:]) 884930cef6SMatthias Ringwald 894930cef6SMatthias Ringwald g_sns = np.power(2, [ -scf_i, scf_i ][inv]) 904930cef6SMatthias Ringwald 91*6897da5cSDirk Helbig ## Spectral shaping 924930cef6SMatthias Ringwald 934930cef6SMatthias Ringwald y = np.empty(len(x)) 94*6897da5cSDirk Helbig I = self.I 954930cef6SMatthias Ringwald 96*6897da5cSDirk Helbig for b in range(nb): 974930cef6SMatthias Ringwald y[I[b]:I[b+1]] = x[I[b]:I[b+1]] * g_sns[b] 984930cef6SMatthias Ringwald 994930cef6SMatthias Ringwald return y 1004930cef6SMatthias Ringwald 1014930cef6SMatthias Ringwald 1024930cef6SMatthias Ringwaldclass SnsAnalysis(Sns): 1034930cef6SMatthias Ringwald 1044930cef6SMatthias Ringwald def __init__(self, dt, sr): 1054930cef6SMatthias Ringwald 1064930cef6SMatthias Ringwald super().__init__(dt, sr) 1074930cef6SMatthias Ringwald 108*6897da5cSDirk Helbig def compute_scale_factors(self, e, att, nbytes): 1094930cef6SMatthias Ringwald 1104930cef6SMatthias Ringwald dt = self.dt 111*6897da5cSDirk Helbig sr = self.sr 112*6897da5cSDirk Helbig hr = self.sr >= T.SRATE_48K_HR 1134930cef6SMatthias Ringwald 114*6897da5cSDirk Helbig ## Padding 1154930cef6SMatthias Ringwald 116*6897da5cSDirk Helbig if len(e) < 32: 117*6897da5cSDirk Helbig n4 = round(abs(1-32/len(e))*len(e)) 118*6897da5cSDirk Helbig n2 = len(e) - n4 119*6897da5cSDirk Helbig 120*6897da5cSDirk Helbig e = np.append(np.zeros(3*n4+n2), e) 121*6897da5cSDirk Helbig for i in range(n4): 122*6897da5cSDirk Helbig e[4*i+0] = e[4*i+1] = \ 123*6897da5cSDirk Helbig e[4*i+2] = e[4*i+3] = e[3*n4+n2+i] 124*6897da5cSDirk Helbig 125*6897da5cSDirk Helbig for i in range(2*n4, 2*n4+n2): 126*6897da5cSDirk Helbig e[2*i+0] = e[2*i+1] = e[2*n4+n2+i] 127*6897da5cSDirk Helbig 128*6897da5cSDirk Helbig elif len(e) < 64: 1294930cef6SMatthias Ringwald n2 = 64 - len(e) 1304930cef6SMatthias Ringwald 1314930cef6SMatthias Ringwald e = np.append(np.empty(n2), e) 1324930cef6SMatthias Ringwald for i in range(n2): 1334930cef6SMatthias Ringwald e[2*i+0] = e[2*i+1] = e[n2+i] 1344930cef6SMatthias Ringwald 135*6897da5cSDirk Helbig ## Smoothing 1364930cef6SMatthias Ringwald 1374930cef6SMatthias Ringwald e_s = np.zeros(len(e)) 1384930cef6SMatthias Ringwald e_s[0 ] = 0.75 * e[0 ] + 0.25 * e[1 ] 1394930cef6SMatthias Ringwald e_s[1:63] = 0.25 * e[0:62] + 0.5 * e[1:63] + 0.25 * e[2:64] 1404930cef6SMatthias Ringwald e_s[ 63] = 0.25 * e[ 62] + 0.75 * e[ 63] 1414930cef6SMatthias Ringwald 142*6897da5cSDirk Helbig ## Pre-emphasis 1434930cef6SMatthias Ringwald 144*6897da5cSDirk Helbig g_tilt = [ 14, 18, 22, 26, 30, 30, 34 ][self.sr] 1454930cef6SMatthias Ringwald e_p = e_s * (10 ** ((np.arange(64) * g_tilt) / 630)) 1464930cef6SMatthias Ringwald 147*6897da5cSDirk Helbig ## Noise floor 1484930cef6SMatthias Ringwald 1494930cef6SMatthias Ringwald noise_floor = max(np.average(e_p) * (10 ** (-40/10)), 2 ** -32) 1504930cef6SMatthias Ringwald e_p = np.fmax(e_p, noise_floor * np.ones(len(e))) 1514930cef6SMatthias Ringwald 152*6897da5cSDirk Helbig ## Logarithm 1534930cef6SMatthias Ringwald 1544930cef6SMatthias Ringwald e_l = np.log2(10 ** -31 + e_p) / 2 1554930cef6SMatthias Ringwald 156*6897da5cSDirk Helbig ## Band energy grouping 1574930cef6SMatthias Ringwald 1584930cef6SMatthias Ringwald w = [ 1/12, 2/12, 3/12, 3/12, 2/12, 1/12 ] 1594930cef6SMatthias Ringwald 1604930cef6SMatthias Ringwald e_4 = np.zeros(len(e_l) // 4) 1614930cef6SMatthias Ringwald e_4[0 ] = w[0] * e_l[0] + np.sum(w[1:] * e_l[:5]) 1624930cef6SMatthias Ringwald e_4[1:15] = [ np.sum(w * e_l[4*i-1:4*i+5]) for i in range(1, 15) ] 1634930cef6SMatthias Ringwald e_4[ 15] = np.sum(w[:5] * e_l[59:64]) + w[5] * e_l[63] 1644930cef6SMatthias Ringwald 165*6897da5cSDirk Helbig ## Mean removal and scaling, attack handling 1664930cef6SMatthias Ringwald 167*6897da5cSDirk Helbig cf = [ 0.85, 0.6 ][hr] 168*6897da5cSDirk Helbig if hr and nbytes * 8 > [ 1150, 2300, 0, 4400 ][self.dt]: 169*6897da5cSDirk Helbig cf *= [ 0.25, 0.35 ][ self.dt == T.DT_10M ] 170*6897da5cSDirk Helbig 171*6897da5cSDirk Helbig scf = cf * (e_4 - np.average(e_4)) 1724930cef6SMatthias Ringwald 1734930cef6SMatthias Ringwald scf_a = np.zeros(len(scf)) 174*6897da5cSDirk Helbig scf_a[0 ] = np.mean(scf[:3]) 175*6897da5cSDirk Helbig scf_a[1 ] = np.mean(scf[:4]) 176*6897da5cSDirk Helbig scf_a[2:14] = [ np.mean(scf[i:i+5]) for i in range(12) ] 177*6897da5cSDirk Helbig scf_a[ 14] = np.mean(scf[12:]) 178*6897da5cSDirk Helbig scf_a[ 15] = np.mean(scf[13:]) 1794930cef6SMatthias Ringwald 180*6897da5cSDirk Helbig scf_a = (0.5 if self.dt != T.DT_7M5 else 0.3) * \ 1814930cef6SMatthias Ringwald (scf_a - np.average(scf_a)) 1824930cef6SMatthias Ringwald 1834930cef6SMatthias Ringwald return scf_a if att else scf 1844930cef6SMatthias Ringwald 1854930cef6SMatthias Ringwald def enum_mpvq(self, v): 1864930cef6SMatthias Ringwald 1874930cef6SMatthias Ringwald sign = None 1884930cef6SMatthias Ringwald index = 0 1894930cef6SMatthias Ringwald x = 0 1904930cef6SMatthias Ringwald 1914930cef6SMatthias Ringwald for (n, vn) in enumerate(v[::-1]): 1924930cef6SMatthias Ringwald 1934930cef6SMatthias Ringwald if sign is not None and vn != 0: 1944930cef6SMatthias Ringwald index = 2*index + sign 1954930cef6SMatthias Ringwald if vn != 0: 1964930cef6SMatthias Ringwald sign = 1 if vn < 0 else 0 1974930cef6SMatthias Ringwald 1984930cef6SMatthias Ringwald index += T.SNS_MPVQ_OFFSETS[n][x] 1994930cef6SMatthias Ringwald x += abs(vn) 2004930cef6SMatthias Ringwald 2014930cef6SMatthias Ringwald return (index, bool(sign)) 2024930cef6SMatthias Ringwald 2034930cef6SMatthias Ringwald def quantize(self, scf): 2044930cef6SMatthias Ringwald 205*6897da5cSDirk Helbig ## Stage 1 2064930cef6SMatthias Ringwald 2074930cef6SMatthias Ringwald dmse_lf = [ np.sum((scf[:8] - T.SNS_LFCB[i]) ** 2) for i in range(32) ] 2084930cef6SMatthias Ringwald dmse_hf = [ np.sum((scf[8:] - T.SNS_HFCB[i]) ** 2) for i in range(32) ] 2094930cef6SMatthias Ringwald 2104930cef6SMatthias Ringwald self.ind_lf = np.argmin(dmse_lf) 2114930cef6SMatthias Ringwald self.ind_hf = np.argmin(dmse_hf) 2124930cef6SMatthias Ringwald 2134930cef6SMatthias Ringwald st1 = np.append(T.SNS_LFCB[self.ind_lf], T.SNS_HFCB[self.ind_hf]) 2144930cef6SMatthias Ringwald r1 = scf - st1 2154930cef6SMatthias Ringwald 216*6897da5cSDirk Helbig ## Stage 2 2174930cef6SMatthias Ringwald 2184930cef6SMatthias Ringwald t2_rot = fftpack.dct(r1, norm = 'ortho') 2194930cef6SMatthias Ringwald x = np.abs(t2_rot) 2204930cef6SMatthias Ringwald 221*6897da5cSDirk Helbig ## Stage 2 Shape search, step 1 2224930cef6SMatthias Ringwald 2234930cef6SMatthias Ringwald K = 6 2244930cef6SMatthias Ringwald 2254930cef6SMatthias Ringwald proj_fac = (K - 1) / sum(np.abs(t2_rot)) 2264930cef6SMatthias Ringwald y3 = np.floor(x * proj_fac).astype(int) 2274930cef6SMatthias Ringwald 228*6897da5cSDirk Helbig ## Stage 2 Shape search, step 2 2294930cef6SMatthias Ringwald 2304930cef6SMatthias Ringwald corr_xy = np.sum(y3 * x) 2314930cef6SMatthias Ringwald energy_y = np.sum(y3 * y3) 2324930cef6SMatthias Ringwald 2334930cef6SMatthias Ringwald k0 = sum(y3) 2344930cef6SMatthias Ringwald for k in range(k0, K): 2354930cef6SMatthias Ringwald q_pvq = ((corr_xy + x) ** 2) / (energy_y + 2*y3 + 1) 2364930cef6SMatthias Ringwald n_best = np.argmax(q_pvq) 2374930cef6SMatthias Ringwald 2384930cef6SMatthias Ringwald corr_xy += x[n_best] 2394930cef6SMatthias Ringwald energy_y += 2*y3[n_best] + 1 2404930cef6SMatthias Ringwald y3[n_best] += 1 2414930cef6SMatthias Ringwald 242*6897da5cSDirk Helbig ## Stage 2 Shape search, step 3 2434930cef6SMatthias Ringwald 2444930cef6SMatthias Ringwald K = 8 2454930cef6SMatthias Ringwald 2464930cef6SMatthias Ringwald y2 = y3.copy() 2474930cef6SMatthias Ringwald 2484930cef6SMatthias Ringwald for k in range(sum(y2), K): 2494930cef6SMatthias Ringwald q_pvq = ((corr_xy + x) ** 2) / (energy_y + 2*y2 + 1) 2504930cef6SMatthias Ringwald n_best = np.argmax(q_pvq) 2514930cef6SMatthias Ringwald 2524930cef6SMatthias Ringwald corr_xy += x[n_best] 2534930cef6SMatthias Ringwald energy_y += 2*y2[n_best] + 1 2544930cef6SMatthias Ringwald y2[n_best] += 1 2554930cef6SMatthias Ringwald 2564930cef6SMatthias Ringwald 257*6897da5cSDirk Helbig ## Stage 2 Shape search, step 4 2584930cef6SMatthias Ringwald 2594930cef6SMatthias Ringwald y1 = np.append(y2[:10], [0] * 6) 2604930cef6SMatthias Ringwald 261*6897da5cSDirk Helbig ## Stage 2 Shape search, step 5 2624930cef6SMatthias Ringwald 2634930cef6SMatthias Ringwald corr_xy -= sum(y2[10:] * x[10:]) 2644930cef6SMatthias Ringwald energy_y -= sum(y2[10:] * y2[10:]) 2654930cef6SMatthias Ringwald 266*6897da5cSDirk Helbig ## Stage 2 Shape search, step 6 2674930cef6SMatthias Ringwald 2684930cef6SMatthias Ringwald K = 10 2694930cef6SMatthias Ringwald 2704930cef6SMatthias Ringwald for k in range(sum(y1), K): 2714930cef6SMatthias Ringwald q_pvq = ((corr_xy + x[:10]) ** 2) / (energy_y + 2*y1[:10] + 1) 2724930cef6SMatthias Ringwald n_best = np.argmax(q_pvq) 2734930cef6SMatthias Ringwald 2744930cef6SMatthias Ringwald corr_xy += x[n_best] 2754930cef6SMatthias Ringwald energy_y += 2*y1[n_best] + 1 2764930cef6SMatthias Ringwald y1[n_best] += 1 2774930cef6SMatthias Ringwald 278*6897da5cSDirk Helbig ## Stage 2 Shape search, step 7 2794930cef6SMatthias Ringwald 2804930cef6SMatthias Ringwald y0 = np.append(y1[:10], [ 0 ] * 6) 2814930cef6SMatthias Ringwald 2824930cef6SMatthias Ringwald q_pvq = ((corr_xy + x[10:]) ** 2) / (energy_y + 2*y0[10:] + 1) 2834930cef6SMatthias Ringwald n_best = 10 + np.argmax(q_pvq) 2844930cef6SMatthias Ringwald 2854930cef6SMatthias Ringwald y0[n_best] += 1 2864930cef6SMatthias Ringwald 287*6897da5cSDirk Helbig ## Stage 2 Shape search, step 8 2884930cef6SMatthias Ringwald 2894930cef6SMatthias Ringwald y0 *= np.sign(t2_rot).astype(int) 2904930cef6SMatthias Ringwald y1 *= np.sign(t2_rot).astype(int) 2914930cef6SMatthias Ringwald y2 *= np.sign(t2_rot).astype(int) 2924930cef6SMatthias Ringwald y3 *= np.sign(t2_rot).astype(int) 2934930cef6SMatthias Ringwald 294*6897da5cSDirk Helbig ## Stage 2 Shape search, step 9 2954930cef6SMatthias Ringwald 2964930cef6SMatthias Ringwald xq = [ y / np.sqrt(sum(y ** 2)) for y in (y0, y1, y2, y3) ] 2974930cef6SMatthias Ringwald 298*6897da5cSDirk Helbig ## Shape and gain combination determination 2994930cef6SMatthias Ringwald 3004930cef6SMatthias Ringwald G = [ T.SNS_VQ_REG_ADJ_GAINS, T.SNS_VQ_REG_LF_ADJ_GAINS, 3014930cef6SMatthias Ringwald T.SNS_VQ_NEAR_ADJ_GAINS, T.SNS_VQ_FAR_ADJ_GAINS ] 3024930cef6SMatthias Ringwald 3034930cef6SMatthias Ringwald dMSE = [ [ sum((t2_rot - G[j][i] * xq[j]) ** 2) 3044930cef6SMatthias Ringwald for i in range(len(G[j])) ] for j in range(4) ] 3054930cef6SMatthias Ringwald 3064930cef6SMatthias Ringwald self.shape = np.argmin([ np.min(dMSE[j]) for j in range(4) ]) 3074930cef6SMatthias Ringwald self.gain = np.argmin(dMSE[self.shape]) 3084930cef6SMatthias Ringwald 3094930cef6SMatthias Ringwald gain = G[self.shape][self.gain] 3104930cef6SMatthias Ringwald 311*6897da5cSDirk Helbig ## Enumeration of the selected PVQ pulse configurations 3124930cef6SMatthias Ringwald 3134930cef6SMatthias Ringwald if self.shape == 0: 3144930cef6SMatthias Ringwald (self.idx_a, self.ls_a) = self.enum_mpvq(y0[:10]) 3154930cef6SMatthias Ringwald (self.idx_b, self.ls_b) = self.enum_mpvq(y0[10:]) 3164930cef6SMatthias Ringwald elif self.shape == 1: 3174930cef6SMatthias Ringwald (self.idx_a, self.ls_a) = self.enum_mpvq(y1[:10]) 3184930cef6SMatthias Ringwald (self.idx_b, self.ls_b) = (None, None) 3194930cef6SMatthias Ringwald elif self.shape == 2: 3204930cef6SMatthias Ringwald (self.idx_a, self.ls_a) = self.enum_mpvq(y2) 3214930cef6SMatthias Ringwald (self.idx_b, self.ls_b) = (None, None) 3224930cef6SMatthias Ringwald elif self.shape == 3: 3234930cef6SMatthias Ringwald (self.idx_a, self.ls_a) = self.enum_mpvq(y3) 3244930cef6SMatthias Ringwald (self.idx_b, self.ls_b) = (None, None) 3254930cef6SMatthias Ringwald 326*6897da5cSDirk Helbig ## Synthesis of the Quantized scale factor 3274930cef6SMatthias Ringwald 3284930cef6SMatthias Ringwald scf_q = st1 + gain * fftpack.idct(xq[self.shape], norm = 'ortho') 3294930cef6SMatthias Ringwald 3304930cef6SMatthias Ringwald return scf_q 3314930cef6SMatthias Ringwald 332*6897da5cSDirk Helbig def run(self, eb, att, nbytes, x): 3334930cef6SMatthias Ringwald 334*6897da5cSDirk Helbig scf = self.compute_scale_factors(eb, att, nbytes) 3354930cef6SMatthias Ringwald scf_q = self.quantize(scf) 3364930cef6SMatthias Ringwald y = self.spectral_shaping(scf_q, False, x) 3374930cef6SMatthias Ringwald 3384930cef6SMatthias Ringwald return y 3394930cef6SMatthias Ringwald 3404930cef6SMatthias Ringwald def store(self, b): 3414930cef6SMatthias Ringwald 3424930cef6SMatthias Ringwald shape = self.shape 3434930cef6SMatthias Ringwald gain_msb_bits = np.array([ 1, 1, 2, 2 ])[shape] 3444930cef6SMatthias Ringwald gain_lsb_bits = np.array([ 0, 1, 0, 1 ])[shape] 3454930cef6SMatthias Ringwald 3464930cef6SMatthias Ringwald b.write_uint(self.ind_lf, 5) 3474930cef6SMatthias Ringwald b.write_uint(self.ind_hf, 5) 3484930cef6SMatthias Ringwald 3494930cef6SMatthias Ringwald b.write_bit(shape >> 1) 3504930cef6SMatthias Ringwald 3514930cef6SMatthias Ringwald b.write_uint(self.gain >> gain_lsb_bits, gain_msb_bits) 3524930cef6SMatthias Ringwald 3534930cef6SMatthias Ringwald b.write_bit(self.ls_a) 3544930cef6SMatthias Ringwald 3554930cef6SMatthias Ringwald if self.shape == 0: 3564930cef6SMatthias Ringwald sz_shape_a = 2390004 3574930cef6SMatthias Ringwald index_joint = self.idx_a + \ 3584930cef6SMatthias Ringwald (2 * self.idx_b + self.ls_b + 2) * sz_shape_a 3594930cef6SMatthias Ringwald 3604930cef6SMatthias Ringwald elif self.shape == 1: 3614930cef6SMatthias Ringwald sz_shape_a = 2390004 3624930cef6SMatthias Ringwald index_joint = self.idx_a + (self.gain & 1) * sz_shape_a 3634930cef6SMatthias Ringwald 3644930cef6SMatthias Ringwald elif self.shape == 2: 3654930cef6SMatthias Ringwald index_joint = self.idx_a 3664930cef6SMatthias Ringwald 3674930cef6SMatthias Ringwald elif self.shape == 3: 3684930cef6SMatthias Ringwald sz_shape_a = 15158272 3694930cef6SMatthias Ringwald index_joint = sz_shape_a + (self.gain & 1) + 2 * self.idx_a 3704930cef6SMatthias Ringwald 3714930cef6SMatthias Ringwald b.write_uint(index_joint, 14 - gain_msb_bits) 3724930cef6SMatthias Ringwald b.write_uint(index_joint >> (14 - gain_msb_bits), 12) 3734930cef6SMatthias Ringwald 3744930cef6SMatthias Ringwald 3754930cef6SMatthias Ringwaldclass SnsSynthesis(Sns): 3764930cef6SMatthias Ringwald 3774930cef6SMatthias Ringwald def __init__(self, dt, sr): 3784930cef6SMatthias Ringwald 3794930cef6SMatthias Ringwald super().__init__(dt, sr) 3804930cef6SMatthias Ringwald 3814930cef6SMatthias Ringwald def deenum_mpvq(self, index, ls, npulses, n): 3824930cef6SMatthias Ringwald 383*6897da5cSDirk Helbig y = np.zeros(n, dtype=np.intc) 3844930cef6SMatthias Ringwald pos = 0 3854930cef6SMatthias Ringwald 3864930cef6SMatthias Ringwald for i in range(len(y)-1, -1, -1): 3874930cef6SMatthias Ringwald 3884930cef6SMatthias Ringwald if index > 0: 3894930cef6SMatthias Ringwald yi = 0 3904930cef6SMatthias Ringwald while index < T.SNS_MPVQ_OFFSETS[i][npulses - yi]: yi += 1 3914930cef6SMatthias Ringwald index -= T.SNS_MPVQ_OFFSETS[i][npulses - yi] 3924930cef6SMatthias Ringwald else: 3934930cef6SMatthias Ringwald yi = npulses 3944930cef6SMatthias Ringwald 3954930cef6SMatthias Ringwald y[pos] = [ yi, -yi ][int(ls)] 3964930cef6SMatthias Ringwald pos += 1 3974930cef6SMatthias Ringwald 3984930cef6SMatthias Ringwald npulses -= yi 3994930cef6SMatthias Ringwald if npulses <= 0: 4004930cef6SMatthias Ringwald break 4014930cef6SMatthias Ringwald 4024930cef6SMatthias Ringwald if yi > 0: 4034930cef6SMatthias Ringwald ls = index & 1 4044930cef6SMatthias Ringwald index >>= 1 4054930cef6SMatthias Ringwald 4064930cef6SMatthias Ringwald return y 4074930cef6SMatthias Ringwald 4084930cef6SMatthias Ringwald def unquantize(self): 4094930cef6SMatthias Ringwald 410*6897da5cSDirk Helbig ## SNS VQ Decoding 4114930cef6SMatthias Ringwald 412*6897da5cSDirk Helbig y = np.empty(16, dtype=np.intc) 4134930cef6SMatthias Ringwald 4144930cef6SMatthias Ringwald if self.shape == 0: 4154930cef6SMatthias Ringwald y[:10] = self.deenum_mpvq(self.idx_a, self.ls_a, 10, 10) 4164930cef6SMatthias Ringwald y[10:] = self.deenum_mpvq(self.idx_b, self.ls_b, 1, 6) 4174930cef6SMatthias Ringwald elif self.shape == 1: 4184930cef6SMatthias Ringwald y[:10] = self.deenum_mpvq(self.idx_a, self.ls_a, 10, 10) 419*6897da5cSDirk Helbig y[10:] = np.zeros(6, dtype=np.intc) 4204930cef6SMatthias Ringwald elif self.shape == 2: 4214930cef6SMatthias Ringwald y = self.deenum_mpvq(self.idx_a, self.ls_a, 8, 16) 4224930cef6SMatthias Ringwald elif self.shape == 3: 4234930cef6SMatthias Ringwald y = self.deenum_mpvq(self.idx_a, self.ls_a, 6, 16) 4244930cef6SMatthias Ringwald 425*6897da5cSDirk Helbig ## Unit energy normalization 4264930cef6SMatthias Ringwald 4274930cef6SMatthias Ringwald y = y / np.sqrt(sum(y ** 2)) 4284930cef6SMatthias Ringwald 429*6897da5cSDirk Helbig ## Reconstruction of the quantized scale factors 4304930cef6SMatthias Ringwald 4314930cef6SMatthias Ringwald G = [ T.SNS_VQ_REG_ADJ_GAINS, T.SNS_VQ_REG_LF_ADJ_GAINS, 4324930cef6SMatthias Ringwald T.SNS_VQ_NEAR_ADJ_GAINS, T.SNS_VQ_FAR_ADJ_GAINS ] 4334930cef6SMatthias Ringwald 4344930cef6SMatthias Ringwald gain = G[self.shape][self.gain] 4354930cef6SMatthias Ringwald 4364930cef6SMatthias Ringwald scf = np.append(T.SNS_LFCB[self.ind_lf], T.SNS_HFCB[self.ind_hf]) \ 4374930cef6SMatthias Ringwald + gain * fftpack.idct(y, norm = 'ortho') 4384930cef6SMatthias Ringwald 4394930cef6SMatthias Ringwald return scf 4404930cef6SMatthias Ringwald 4414930cef6SMatthias Ringwald def load(self, b): 4424930cef6SMatthias Ringwald 4434930cef6SMatthias Ringwald self.ind_lf = b.read_uint(5) 4444930cef6SMatthias Ringwald self.ind_hf = b.read_uint(5) 4454930cef6SMatthias Ringwald 4464930cef6SMatthias Ringwald shape_msb = b.read_bit() 4474930cef6SMatthias Ringwald 4484930cef6SMatthias Ringwald gain_msb_bits = 1 + shape_msb 4494930cef6SMatthias Ringwald self.gain = b.read_uint(gain_msb_bits) 4504930cef6SMatthias Ringwald 4514930cef6SMatthias Ringwald self.ls_a = b.read_bit() 4524930cef6SMatthias Ringwald 4534930cef6SMatthias Ringwald index_joint = b.read_uint(14 - gain_msb_bits) 4544930cef6SMatthias Ringwald index_joint |= b.read_uint(12) << (14 - gain_msb_bits) 4554930cef6SMatthias Ringwald 4564930cef6SMatthias Ringwald if shape_msb == 0: 4574930cef6SMatthias Ringwald sz_shape_a = 2390004 4584930cef6SMatthias Ringwald 4594930cef6SMatthias Ringwald if index_joint >= sz_shape_a * 14: 4604930cef6SMatthias Ringwald raise ValueError('Invalide SNS joint index') 4614930cef6SMatthias Ringwald 4624930cef6SMatthias Ringwald self.idx_a = index_joint % sz_shape_a 4634930cef6SMatthias Ringwald index_joint = index_joint // sz_shape_a 4644930cef6SMatthias Ringwald if index_joint >= 2: 4654930cef6SMatthias Ringwald self.shape = 0 4664930cef6SMatthias Ringwald self.idx_b = (index_joint - 2) // 2 4674930cef6SMatthias Ringwald self.ls_b = (index_joint - 2) % 2 4684930cef6SMatthias Ringwald else: 4694930cef6SMatthias Ringwald self.shape = 1 4704930cef6SMatthias Ringwald self.gain = (self.gain << 1) + (index_joint & 1) 4714930cef6SMatthias Ringwald 4724930cef6SMatthias Ringwald else: 4734930cef6SMatthias Ringwald sz_shape_a = 15158272 4744930cef6SMatthias Ringwald if index_joint >= sz_shape_a + 1549824: 4754930cef6SMatthias Ringwald raise ValueError('Invalide SNS joint index') 4764930cef6SMatthias Ringwald 4774930cef6SMatthias Ringwald if index_joint < sz_shape_a: 4784930cef6SMatthias Ringwald self.shape = 2 4794930cef6SMatthias Ringwald self.idx_a = index_joint 4804930cef6SMatthias Ringwald else: 4814930cef6SMatthias Ringwald self.shape = 3 4824930cef6SMatthias Ringwald index_joint -= sz_shape_a 4834930cef6SMatthias Ringwald self.gain = (self.gain << 1) + (index_joint % 2) 4844930cef6SMatthias Ringwald self.idx_a = index_joint // 2 4854930cef6SMatthias Ringwald 4864930cef6SMatthias Ringwald def run(self, x): 4874930cef6SMatthias Ringwald 4884930cef6SMatthias Ringwald scf = self.unquantize() 4894930cef6SMatthias Ringwald y = self.spectral_shaping(scf, True, x) 4904930cef6SMatthias Ringwald 4914930cef6SMatthias Ringwald return y 4924930cef6SMatthias Ringwald 4934930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 4944930cef6SMatthias Ringwald 4954930cef6SMatthias Ringwalddef check_analysis(rng, dt, sr): 4964930cef6SMatthias Ringwald 4974930cef6SMatthias Ringwald ok = True 4984930cef6SMatthias Ringwald 4994930cef6SMatthias Ringwald analysis = SnsAnalysis(dt, sr) 5004930cef6SMatthias Ringwald 5014930cef6SMatthias Ringwald for i in range(10): 502*6897da5cSDirk Helbig ne = T.I[dt][sr][-1] 503*6897da5cSDirk Helbig x = rng.random(ne) * 1e4 504*6897da5cSDirk Helbig e = rng.random(len(T.I[dt][sr]) - 1) * 1e10 5054930cef6SMatthias Ringwald 506*6897da5cSDirk Helbig if sr >= T.SRATE_48K_HR: 507*6897da5cSDirk Helbig for nbits in (1144, 1152, 2296, 2304, 4400, 4408): 508*6897da5cSDirk Helbig y = analysis.run(e, False, nbits // 8, x) 5094930cef6SMatthias Ringwald data = analysis.get_data() 5104930cef6SMatthias Ringwald 511*6897da5cSDirk Helbig (y_c, data_c) = lc3.sns_analyze( 512*6897da5cSDirk Helbig dt, sr, nbits // 8, e, False, x) 513*6897da5cSDirk Helbig 514*6897da5cSDirk Helbig for k in data.keys(): 515*6897da5cSDirk Helbig ok = ok and data_c[k] == data[k] 516*6897da5cSDirk Helbig 517*6897da5cSDirk Helbig ok = ok and lc3.sns_get_nbits() == analysis.get_nbits() 518*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(y - y_c)) < 1e-1 519*6897da5cSDirk Helbig 520*6897da5cSDirk Helbig else: 521*6897da5cSDirk Helbig for att in (0, 1): 522*6897da5cSDirk Helbig y = analysis.run(e, att, 0, x) 523*6897da5cSDirk Helbig data = analysis.get_data() 524*6897da5cSDirk Helbig 525*6897da5cSDirk Helbig (y_c, data_c) = lc3.sns_analyze(dt, sr, 0, e, att, x) 5264930cef6SMatthias Ringwald 5274930cef6SMatthias Ringwald for k in data.keys(): 5284930cef6SMatthias Ringwald ok = ok and data_c[k] == data[k] 5294930cef6SMatthias Ringwald 5304930cef6SMatthias Ringwald ok = ok and lc3.sns_get_nbits() == analysis.get_nbits() 5314930cef6SMatthias Ringwald ok = ok and np.amax(np.abs(y - y_c)) < 1e-1 5324930cef6SMatthias Ringwald 5334930cef6SMatthias Ringwald return ok 5344930cef6SMatthias Ringwald 5354930cef6SMatthias Ringwalddef check_synthesis(rng, dt, sr): 5364930cef6SMatthias Ringwald 5374930cef6SMatthias Ringwald ok = True 5384930cef6SMatthias Ringwald 5394930cef6SMatthias Ringwald synthesis = SnsSynthesis(dt, sr) 5404930cef6SMatthias Ringwald 5414930cef6SMatthias Ringwald for i in range(100): 5424930cef6SMatthias Ringwald 5434930cef6SMatthias Ringwald synthesis.ind_lf = rng.integers(0, 32) 5444930cef6SMatthias Ringwald synthesis.ind_hf = rng.integers(0, 32) 5454930cef6SMatthias Ringwald 5464930cef6SMatthias Ringwald shape = rng.integers(0, 4) 5474930cef6SMatthias Ringwald sz_shape_a = [ 2390004, 2390004, 15158272, 774912 ][shape] 5484930cef6SMatthias Ringwald sz_shape_b = [ 6, 1, 0, 0 ][shape] 5494930cef6SMatthias Ringwald synthesis.shape = shape 5504930cef6SMatthias Ringwald synthesis.gain = rng.integers(0, [ 2, 4, 4, 8 ][shape]) 5514930cef6SMatthias Ringwald synthesis.idx_a = rng.integers(0, sz_shape_a, endpoint=True) 5524930cef6SMatthias Ringwald synthesis.ls_a = bool(rng.integers(0, 1, endpoint=True)) 5534930cef6SMatthias Ringwald synthesis.idx_b = rng.integers(0, sz_shape_b, endpoint=True) 5544930cef6SMatthias Ringwald synthesis.ls_b = bool(rng.integers(0, 1, endpoint=True)) 5554930cef6SMatthias Ringwald 556*6897da5cSDirk Helbig ne = T.I[dt][sr][-1] 557*6897da5cSDirk Helbig x = rng.random(ne) * 1e4 5584930cef6SMatthias Ringwald 5594930cef6SMatthias Ringwald y = synthesis.run(x) 5604930cef6SMatthias Ringwald y_c = lc3.sns_synthesize(dt, sr, synthesis.get_data(), x) 561*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(1 - y/y_c)) < 1e-5 5624930cef6SMatthias Ringwald 5634930cef6SMatthias Ringwald return ok 5644930cef6SMatthias Ringwald 5654930cef6SMatthias Ringwalddef check_analysis_appendix_c(dt): 5664930cef6SMatthias Ringwald 567*6897da5cSDirk Helbig i0 = dt - T.DT_7M5 5684930cef6SMatthias Ringwald sr = T.SRATE_16K 569*6897da5cSDirk Helbig 5704930cef6SMatthias Ringwald ok = True 5714930cef6SMatthias Ringwald 572*6897da5cSDirk Helbig for i in range(len(C.E_B[i0])): 5734930cef6SMatthias Ringwald 574*6897da5cSDirk Helbig scf = lc3.sns_compute_scale_factors(dt, sr, 0, C.E_B[i0][i], False) 575*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(scf - C.SCF[i0][i])) < 1e-4 5764930cef6SMatthias Ringwald 5774930cef6SMatthias Ringwald (lf, hf) = lc3.sns_resolve_codebooks(scf) 578*6897da5cSDirk Helbig ok = ok and lf == C.IND_LF[i0][i] and hf == C.IND_HF[i0][i] 5794930cef6SMatthias Ringwald 5804930cef6SMatthias Ringwald (y, yn, shape, gain) = lc3.sns_quantize(scf, lf, hf) 581*6897da5cSDirk Helbig ok = ok and np.any(y[0][:16] - C.SNS_Y0[i0][i] == 0) 582*6897da5cSDirk Helbig ok = ok and np.any(y[1][:10] - C.SNS_Y1[i0][i] == 0) 583*6897da5cSDirk Helbig ok = ok and np.any(y[2][:16] - C.SNS_Y2[i0][i] == 0) 584*6897da5cSDirk Helbig ok = ok and np.any(y[3][:16] - C.SNS_Y3[i0][i] == 0) 585*6897da5cSDirk Helbig ok = ok and shape == 2*C.SUBMODE_MSB[i0][i] + C.SUBMODE_LSB[i0][i] 586*6897da5cSDirk Helbig ok = ok and gain == C.G_IND[i0][i] 5874930cef6SMatthias Ringwald 5884930cef6SMatthias Ringwald scf_q = lc3.sns_unquantize(lf, hf, yn[shape], shape, gain) 589*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(scf_q - C.SCF_Q[i0][i])) < 1e-5 5904930cef6SMatthias Ringwald 591*6897da5cSDirk Helbig x = lc3.sns_spectral_shaping(dt, sr, C.SCF_Q[i0][i], False, C.X[i0][i]) 592*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(1 - x/C.X_S[i0][i])) < 1e-5 5934930cef6SMatthias Ringwald 594*6897da5cSDirk Helbig (x, data) = lc3.sns_analyze(dt, sr, 0, C.E_B[i0][i], False, C.X[i0][i]) 595*6897da5cSDirk Helbig ok = ok and data['lfcb'] == C.IND_LF[i0][i] 596*6897da5cSDirk Helbig ok = ok and data['hfcb'] == C.IND_HF[i0][i] 597*6897da5cSDirk Helbig ok = ok and data['shape'] == 2*C.SUBMODE_MSB[i0][i] + \ 598*6897da5cSDirk Helbig C.SUBMODE_LSB[i0][i] 599*6897da5cSDirk Helbig ok = ok and data['gain'] == C.G_IND[i0][i] 600*6897da5cSDirk Helbig ok = ok and data['idx_a'] == C.IDX_A[i0][i] 601*6897da5cSDirk Helbig ok = ok and data['ls_a'] == C.LS_IND_A[i0][i] 602*6897da5cSDirk Helbig ok = ok and (C.IDX_B[i0][i] is None or 603*6897da5cSDirk Helbig data['idx_b'] == C.IDX_B[i0][i]) 604*6897da5cSDirk Helbig ok = ok and (C.LS_IND_B[i0][i] is None or 605*6897da5cSDirk Helbig data['ls_b'] == C.LS_IND_B[i0][i]) 606*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(1 - x/C.X_S[i0][i])) < 1e-5 6074930cef6SMatthias Ringwald 6084930cef6SMatthias Ringwald return ok 6094930cef6SMatthias Ringwald 6104930cef6SMatthias Ringwalddef check_synthesis_appendix_c(dt): 6114930cef6SMatthias Ringwald 612*6897da5cSDirk Helbig i0 = dt - T.DT_7M5 6134930cef6SMatthias Ringwald sr = T.SRATE_16K 614*6897da5cSDirk Helbig 6154930cef6SMatthias Ringwald ok = True 6164930cef6SMatthias Ringwald 617*6897da5cSDirk Helbig for i in range(len(C.X_HAT_TNS[i0])): 6184930cef6SMatthias Ringwald 6194930cef6SMatthias Ringwald data = { 620*6897da5cSDirk Helbig 'lfcb' : C.IND_LF[i0][i], 'hfcb' : C.IND_HF[i0][i], 621*6897da5cSDirk Helbig 'shape' : 2*C.SUBMODE_MSB[i0][i] + C.SUBMODE_LSB[i0][i], 622*6897da5cSDirk Helbig 'gain' : C.G_IND[i0][i], 623*6897da5cSDirk Helbig 'idx_a' : C.IDX_A[i0][i], 624*6897da5cSDirk Helbig 'ls_a' : C.LS_IND_A[i0][i], 625*6897da5cSDirk Helbig 'idx_b' : C.IDX_B[i0][i] if C.IDX_B[i0][i] is not None else 0, 626*6897da5cSDirk Helbig 'ls_b' : C.LS_IND_B[i0][i] if C.LS_IND_B[i0][i] is not None else 0, 6274930cef6SMatthias Ringwald } 6284930cef6SMatthias Ringwald 629*6897da5cSDirk Helbig x = lc3.sns_synthesize(dt, sr, data, C.X_HAT_TNS[i0][i]) 630*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(x - C.X_HAT_SNS[i0][i])) < 1e0 6314930cef6SMatthias Ringwald 6324930cef6SMatthias Ringwald return ok 6334930cef6SMatthias Ringwald 6344930cef6SMatthias Ringwalddef check(): 6354930cef6SMatthias Ringwald 6364930cef6SMatthias Ringwald rng = np.random.default_rng(1234) 6374930cef6SMatthias Ringwald ok = True 6384930cef6SMatthias Ringwald 6394930cef6SMatthias Ringwald for dt in range(T.NUM_DT): 640*6897da5cSDirk Helbig for sr in range(T.SRATE_8K, T.SRATE_48K + 1): 6414930cef6SMatthias Ringwald ok = ok and check_analysis(rng, dt, sr) 6424930cef6SMatthias Ringwald ok = ok and check_synthesis(rng, dt, sr) 6434930cef6SMatthias Ringwald 644*6897da5cSDirk Helbig for dt in ( T.DT_2M5, T.DT_5M, T.DT_10M ): 645*6897da5cSDirk Helbig for sr in ( T.SRATE_48K_HR, T.SRATE_96K_HR ): 646*6897da5cSDirk Helbig ok = ok and check_analysis(rng, dt, sr) 647*6897da5cSDirk Helbig ok = ok and check_synthesis(rng, dt, sr) 648*6897da5cSDirk Helbig 649*6897da5cSDirk Helbig for dt in ( T.DT_7M5, T.DT_10M ): 650*6897da5cSDirk Helbig check_analysis_appendix_c(dt) 651*6897da5cSDirk Helbig check_synthesis_appendix_c(dt) 6524930cef6SMatthias Ringwald 6534930cef6SMatthias Ringwald return ok 6544930cef6SMatthias Ringwald 6554930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 656