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.signal as signal 194930cef6SMatthias Ringwald 204c4eb519SMatthias Ringwaldimport lc3 214930cef6SMatthias Ringwaldimport tables as T, appendix_c as C 224930cef6SMatthias Ringwald 234930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 244930cef6SMatthias Ringwald 254930cef6SMatthias Ringwaldclass Resampler_12k8: 264930cef6SMatthias Ringwald 274930cef6SMatthias Ringwald def __init__(self, dt, sr, history = 0): 284930cef6SMatthias Ringwald 294930cef6SMatthias Ringwald self.sr = sr 304930cef6SMatthias Ringwald self.p = 192 // T.SRATE_KHZ[sr] 314930cef6SMatthias Ringwald self.w = 240 // self.p 324930cef6SMatthias Ringwald 334930cef6SMatthias Ringwald self.n = ((T.DT_MS[dt] * 128) / 10).astype(int) 34*6897da5cSDirk Helbig self.d = [ 24, 44 ][dt == T.DT_7M5] 354930cef6SMatthias Ringwald 364930cef6SMatthias Ringwald self.x = np.zeros(self.w + T.NS[dt][sr]) 374930cef6SMatthias Ringwald self.u = np.zeros(self.n + 2) 384930cef6SMatthias Ringwald self.y = np.zeros(self.n + self.d + history) 394930cef6SMatthias Ringwald 404930cef6SMatthias Ringwald def resample(self, x): 414930cef6SMatthias Ringwald 424930cef6SMatthias Ringwald p = self.p 434930cef6SMatthias Ringwald w = self.w 444930cef6SMatthias Ringwald d = self.d 454930cef6SMatthias Ringwald n = self.n 464930cef6SMatthias Ringwald 474930cef6SMatthias Ringwald ### Sliding window 484930cef6SMatthias Ringwald 494930cef6SMatthias Ringwald self.x[:w] = self.x[-w:] 504930cef6SMatthias Ringwald self.x[w:] = x 514930cef6SMatthias Ringwald self.u[:2] = self.u[-2:] 524930cef6SMatthias Ringwald 534930cef6SMatthias Ringwald if len(self.y) > 2*n + d: 544930cef6SMatthias Ringwald self.y[n+d:-n] = self.y[d+2*n:] 554930cef6SMatthias Ringwald if len(self.y) > n + d: 564930cef6SMatthias Ringwald self.y[-n:] = self.y[:n] 574930cef6SMatthias Ringwald self.y[:d] = self.y[n:d+n] 584930cef6SMatthias Ringwald 594930cef6SMatthias Ringwald x = self.x 604930cef6SMatthias Ringwald u = self.u 614930cef6SMatthias Ringwald 62*6897da5cSDirk Helbig ### Resampling 634930cef6SMatthias Ringwald 644930cef6SMatthias Ringwald h = np.zeros(240 + p) 654930cef6SMatthias Ringwald h[-119:] = T.LTPF_H12K8[:119] 664930cef6SMatthias Ringwald h[ :120] = T.LTPF_H12K8[119:] 674930cef6SMatthias Ringwald 684930cef6SMatthias Ringwald for i in range(n): 694930cef6SMatthias Ringwald e = (15 * i) // p 704930cef6SMatthias Ringwald f = (15 * i) % p 714930cef6SMatthias Ringwald k = np.arange(-120, 120 + p, p) - f 724930cef6SMatthias Ringwald u[2+i] = p * np.dot( x[e:e+w+1], np.take(h, k) ) 734930cef6SMatthias Ringwald 744930cef6SMatthias Ringwald if self.sr == T.SRATE_8K: 754930cef6SMatthias Ringwald u = 0.5 * u 764930cef6SMatthias Ringwald 77*6897da5cSDirk Helbig ### High-pass filtering 784930cef6SMatthias Ringwald 794930cef6SMatthias Ringwald b = [ 0.9827947082978771, -1.9655894165957540, 0.9827947082978771 ] 804930cef6SMatthias Ringwald a = [ 1 , -1.9652933726226904, 0.9658854605688177 ] 814930cef6SMatthias Ringwald 824930cef6SMatthias Ringwald self.y[d:d+n] = b[0] * u[2:] + b[1] * u[1:-1] + b[2] * u[:-2] 834930cef6SMatthias Ringwald for i in range(n): 844930cef6SMatthias Ringwald self.y[d+i] -= a[1] * self.y[d+i-1] + a[2] * self.y[d+i-2] 854930cef6SMatthias Ringwald 864930cef6SMatthias Ringwald return self.y 874930cef6SMatthias Ringwald 884930cef6SMatthias Ringwald 894930cef6SMatthias Ringwaldclass Resampler_6k4: 904930cef6SMatthias Ringwald 914930cef6SMatthias Ringwald def __init__(self, n, history = 0): 924930cef6SMatthias Ringwald 934930cef6SMatthias Ringwald self.x = np.zeros(n + 5) 944930cef6SMatthias Ringwald self.n = n // 2 954930cef6SMatthias Ringwald 964930cef6SMatthias Ringwald self.y = np.zeros(self.n + history) 974930cef6SMatthias Ringwald 984930cef6SMatthias Ringwald def resample(self, x): 994930cef6SMatthias Ringwald 1004930cef6SMatthias Ringwald n = self.n 1014930cef6SMatthias Ringwald 1024930cef6SMatthias Ringwald ### Sliding window 1034930cef6SMatthias Ringwald 1044930cef6SMatthias Ringwald self.x[:3] = self.x[-5:-2] 1054930cef6SMatthias Ringwald self.x[3:] = x[:2*n+2] 1064930cef6SMatthias Ringwald x = self.x 1074930cef6SMatthias Ringwald 1084930cef6SMatthias Ringwald if len(self.y) > 2*n: 1094930cef6SMatthias Ringwald self.y[n:-n] = self.y[2*n:] 1104930cef6SMatthias Ringwald if len(self.y) > n: 1114930cef6SMatthias Ringwald self.y[-n:] = self.y[:n] 1124930cef6SMatthias Ringwald 113*6897da5cSDirk Helbig ### Downsampling to 6.4 KHz 1144930cef6SMatthias Ringwald 1154930cef6SMatthias Ringwald h = [ 0.1236796411180537, 0.2353512128364889, 0.2819382920909148, 1164930cef6SMatthias Ringwald 0.2353512128364889, 0.1236796411180537 ] 1174930cef6SMatthias Ringwald 1184930cef6SMatthias Ringwald self.y[:n] = [ np.dot(x[2*i:2*i+5], h) for i in range(self.n) ] 1194930cef6SMatthias Ringwald return self.y 1204930cef6SMatthias Ringwald 1214930cef6SMatthias Ringwald 1224930cef6SMatthias Ringwalddef initial_hp50_state(): 1234930cef6SMatthias Ringwald return { 's1': 0, 's2': 0 } 1244930cef6SMatthias Ringwald 1254930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 1264930cef6SMatthias Ringwald 1274930cef6SMatthias Ringwaldclass Ltpf: 1284930cef6SMatthias Ringwald 1294930cef6SMatthias Ringwald def __init__(self, dt, sr): 1304930cef6SMatthias Ringwald 1314930cef6SMatthias Ringwald self.dt = dt 1324930cef6SMatthias Ringwald self.sr = sr 1334930cef6SMatthias Ringwald 1344930cef6SMatthias Ringwald (self.pitch_present, self.pitch_index) = (None, None) 1354930cef6SMatthias Ringwald 1364930cef6SMatthias Ringwald 1374930cef6SMatthias Ringwaldclass LtpfAnalysis(Ltpf): 1384930cef6SMatthias Ringwald 1394930cef6SMatthias Ringwald def __init__(self, dt, sr): 1404930cef6SMatthias Ringwald 1414930cef6SMatthias Ringwald super().__init__(dt, sr) 1424930cef6SMatthias Ringwald 143*6897da5cSDirk Helbig self.resampler_12k8 = Resampler_12k8(dt, sr, 144*6897da5cSDirk Helbig history = 232 + (32 if dt == T.DT_2M5 else 0)) 1454930cef6SMatthias Ringwald 146*6897da5cSDirk Helbig self.resampler_6k4 = Resampler_6k4(self.resampler_12k8.n, 147*6897da5cSDirk Helbig history = 114 + (16 if dt == T.DT_2M5 else 0)) 1484930cef6SMatthias Ringwald 1494930cef6SMatthias Ringwald self.active = False 1504930cef6SMatthias Ringwald self.tc = 0 1514930cef6SMatthias Ringwald self.pitch = 0 1524930cef6SMatthias Ringwald self.nc = np.zeros(2) 1534930cef6SMatthias Ringwald 1544c4eb519SMatthias Ringwald def get_data(self): 1554c4eb519SMatthias Ringwald 1564c4eb519SMatthias Ringwald return { 'active' : self.active, 1574c4eb519SMatthias Ringwald 'pitch_index' : self.pitch_index } 1584c4eb519SMatthias Ringwald 1594c4eb519SMatthias Ringwald def get_nbits(self): 1604c4eb519SMatthias Ringwald 1614c4eb519SMatthias Ringwald return 1 + 10 * int(self.pitch_present) 1624c4eb519SMatthias Ringwald 163*6897da5cSDirk Helbig def correlate(self, x, i0, n, k0, k1): 1644930cef6SMatthias Ringwald 165*6897da5cSDirk Helbig return np.array([ np.dot( 166*6897da5cSDirk Helbig np.take(x, np.arange(i0, n)), 167*6897da5cSDirk Helbig np.take(x, np.arange(i0, n) - k)) for k in range(k0, 1+k1) ]) 1684930cef6SMatthias Ringwald 169*6897da5cSDirk Helbig def norm_corr(self, x, i0, n, k): 1704930cef6SMatthias Ringwald 171*6897da5cSDirk Helbig u = np.take(x, np.arange(i0, n)) 172*6897da5cSDirk Helbig v = np.take(x, np.arange(i0, n) - k) 1734930cef6SMatthias Ringwald uv = np.dot(u, v) 1744930cef6SMatthias Ringwald return uv / np.sqrt(np.dot(u, u) * np.dot(v, v)) if uv > 0 else 0 1754930cef6SMatthias Ringwald 1764930cef6SMatthias Ringwald def run(self, x): 1774930cef6SMatthias Ringwald 178*6897da5cSDirk Helbig ### Resampling 1794930cef6SMatthias Ringwald 1804930cef6SMatthias Ringwald x_12k8 = self.resampler_12k8.resample(x) 1814930cef6SMatthias Ringwald 182*6897da5cSDirk Helbig ### Pitch detection algorithm 1834930cef6SMatthias Ringwald 1844930cef6SMatthias Ringwald x = self.resampler_6k4.resample(x_12k8) 185*6897da5cSDirk Helbig i0 = [-16, 0][self.dt > T.DT_2M5] 1864930cef6SMatthias Ringwald n = self.resampler_6k4.n 1874930cef6SMatthias Ringwald 188*6897da5cSDirk Helbig r = self.correlate(x, i0, n, 17, 114) 1894930cef6SMatthias Ringwald rw = r * (1 - 0.5 * np.arange(len(r)) / (len(r) - 1)) 1904930cef6SMatthias Ringwald 1914930cef6SMatthias Ringwald tc = self.tc 1924930cef6SMatthias Ringwald k0 = max(0, tc-4) 1934930cef6SMatthias Ringwald k1 = min(len(r)-1, tc+4) 1944930cef6SMatthias Ringwald t = [ 17 + np.argmax(rw), 17 + k0 + np.argmax(r[k0:1+k1]) ] 1954930cef6SMatthias Ringwald 196*6897da5cSDirk Helbig nc = [ self.norm_corr(x, i0, n, t[i]) for i in range(2) ] 1974930cef6SMatthias Ringwald ti = int(nc[1] > 0.85 * nc[0]) 1984930cef6SMatthias Ringwald self.tc = t[ti] - 17 1994930cef6SMatthias Ringwald 2004930cef6SMatthias Ringwald self.pitch_present = bool(nc[ti] > 0.6) 2014930cef6SMatthias Ringwald 202*6897da5cSDirk Helbig ### Pitch-lag parameter 2034930cef6SMatthias Ringwald 2044930cef6SMatthias Ringwald if self.pitch_present: 2054930cef6SMatthias Ringwald tc = self.tc + 17 2064930cef6SMatthias Ringwald 2074930cef6SMatthias Ringwald x = x_12k8 208*6897da5cSDirk Helbig i0 = [-32, 0][self.dt > T.DT_2M5] 2094930cef6SMatthias Ringwald n = self.resampler_12k8.n 2104930cef6SMatthias Ringwald 2114930cef6SMatthias Ringwald k0 = max( 32, 2*tc-4) 2124930cef6SMatthias Ringwald k1 = min(228, 2*tc+4) 213*6897da5cSDirk Helbig r = self.correlate(x, i0, n, k0-4, k1+4) 2144930cef6SMatthias Ringwald e = k0 + np.argmax(r[4:-4]) 2154930cef6SMatthias Ringwald 2164930cef6SMatthias Ringwald h = np.zeros(42) 2174930cef6SMatthias Ringwald h[-15:] = T.LTPF_H4[:15] 2184930cef6SMatthias Ringwald h[ :16] = T.LTPF_H4[15:] 2194930cef6SMatthias Ringwald 2204930cef6SMatthias Ringwald m = np.arange(-4, 5) 2214930cef6SMatthias Ringwald s = [ np.dot( np.take(r, e-k0+4 + m), np.take(h, 4*m-d) ) \ 2224930cef6SMatthias Ringwald for d in range(-3, 4) ] 2234930cef6SMatthias Ringwald 2244930cef6SMatthias Ringwald f = np.argmax(s[3:]) if e <= 32 else \ 2254930cef6SMatthias Ringwald -3 + np.argmax(s) if e < 127 else \ 2264930cef6SMatthias Ringwald -2 + 2*np.argmax(s[1:-1:2]) if e < 157 else 0 2274930cef6SMatthias Ringwald 2284930cef6SMatthias Ringwald e -= (f < 0) 2294930cef6SMatthias Ringwald f += 4*(f < 0) 2304930cef6SMatthias Ringwald 2314930cef6SMatthias Ringwald self.pitch_index = 4*e + f - 128 if e < 127 else \ 2324930cef6SMatthias Ringwald 2*e + f//2 + 126 if e < 157 else e + 283 2334930cef6SMatthias Ringwald 2344930cef6SMatthias Ringwald else: 2354930cef6SMatthias Ringwald e = f = 0 2364930cef6SMatthias Ringwald self.pitch_index = 0 2374930cef6SMatthias Ringwald 238*6897da5cSDirk Helbig ### Activation bit 2394930cef6SMatthias Ringwald 2404930cef6SMatthias Ringwald h = np.zeros(24) 2414930cef6SMatthias Ringwald h[-7:] = T.LTPF_HI[:7] 2424930cef6SMatthias Ringwald h[ :8] = T.LTPF_HI[7:] 2434930cef6SMatthias Ringwald 244*6897da5cSDirk Helbig x = x_12k8 245*6897da5cSDirk Helbig i0 = [-32, 0][self.dt > T.DT_2M5] 246*6897da5cSDirk Helbig n = self.resampler_12k8.n 247*6897da5cSDirk Helbig 2484930cef6SMatthias Ringwald k = np.arange(-2, 3) 2494930cef6SMatthias Ringwald u = [ np.dot( np.take(x, i-k), np.take(h, 4*k) ) \ 250*6897da5cSDirk Helbig for i in range(i0, n) ] 2514930cef6SMatthias Ringwald v = [ np.dot( np.take(x, i-k), np.take(h, 4*k-f) ) \ 252*6897da5cSDirk Helbig for i in range(i0-e, n-e) ] 2534930cef6SMatthias Ringwald 2544930cef6SMatthias Ringwald nc = max(0, np.dot(u, v)) / np.sqrt(np.dot(u, u) * np.dot(v, v)) \ 2554930cef6SMatthias Ringwald if self.pitch_present else 0 2564930cef6SMatthias Ringwald 2574930cef6SMatthias Ringwald pitch = e + f/4 2584930cef6SMatthias Ringwald 2594930cef6SMatthias Ringwald if not self.active: 2604930cef6SMatthias Ringwald active = (self.dt == T.DT_10M or self.nc[1] > 0.94) \ 2614930cef6SMatthias Ringwald and self.nc[0] > 0.94 and nc > 0.94 2624930cef6SMatthias Ringwald 2634930cef6SMatthias Ringwald else: 2644930cef6SMatthias Ringwald dp = abs(pitch - self.pitch) 2654930cef6SMatthias Ringwald dc = nc - self.nc[0] 2664930cef6SMatthias Ringwald active = nc > 0.9 or (dp < 2 and dc > -0.1 and nc > 0.84) 2674930cef6SMatthias Ringwald 2684930cef6SMatthias Ringwald if not self.pitch_present: 2694930cef6SMatthias Ringwald active = False 2704930cef6SMatthias Ringwald pitch = 0 2714930cef6SMatthias Ringwald nc = 0 2724930cef6SMatthias Ringwald 2734930cef6SMatthias Ringwald self.active = active 2744930cef6SMatthias Ringwald self.pitch = pitch 2754930cef6SMatthias Ringwald self.nc[1] = self.nc[0] 2764930cef6SMatthias Ringwald self.nc[0] = nc 2774930cef6SMatthias Ringwald 2784930cef6SMatthias Ringwald return self.pitch_present 2794930cef6SMatthias Ringwald 2804930cef6SMatthias Ringwald def disable(self): 2814930cef6SMatthias Ringwald 2824930cef6SMatthias Ringwald self.active = False 2834930cef6SMatthias Ringwald 2844930cef6SMatthias Ringwald def store(self, b): 2854930cef6SMatthias Ringwald 2864930cef6SMatthias Ringwald b.write_uint(self.active, 1) 2874930cef6SMatthias Ringwald b.write_uint(self.pitch_index, 9) 2884930cef6SMatthias Ringwald 2894930cef6SMatthias Ringwald 2904930cef6SMatthias Ringwaldclass LtpfSynthesis(Ltpf): 2914930cef6SMatthias Ringwald 2924930cef6SMatthias Ringwald C_N = [ T.LTPF_N_8K , T.LTPF_N_16K, 2934930cef6SMatthias Ringwald T.LTPF_N_24K, T.LTPF_N_32K, T.LTPF_N_48K ] 2944930cef6SMatthias Ringwald 2954930cef6SMatthias Ringwald C_D = [ T.LTPF_D_8K , T.LTPF_D_16K, 2964930cef6SMatthias Ringwald T.LTPF_D_24K, T.LTPF_D_32K, T.LTPF_D_48K ] 2974930cef6SMatthias Ringwald 2984930cef6SMatthias Ringwald def __init__(self, dt, sr): 2994930cef6SMatthias Ringwald 3004930cef6SMatthias Ringwald super().__init__(dt, sr) 3014930cef6SMatthias Ringwald 3024930cef6SMatthias Ringwald self.C_N = LtpfSynthesis.C_N[sr] 3034930cef6SMatthias Ringwald self.C_D = LtpfSynthesis.C_D[sr] 3044930cef6SMatthias Ringwald 3054930cef6SMatthias Ringwald ns = T.NS[dt][sr] 3064930cef6SMatthias Ringwald 3074930cef6SMatthias Ringwald self.active = [ False, False ] 3084930cef6SMatthias Ringwald self.pitch_index = 0 3094930cef6SMatthias Ringwald 3104930cef6SMatthias Ringwald max_pitch_12k8 = 228 3114930cef6SMatthias Ringwald max_pitch = max_pitch_12k8 * T.SRATE_KHZ[self.sr] / 12.8 3124930cef6SMatthias Ringwald max_pitch = np.ceil(max_pitch).astype(int) 3134930cef6SMatthias Ringwald 3144930cef6SMatthias Ringwald self.x = np.zeros(ns) 3154930cef6SMatthias Ringwald self.y = np.zeros(max_pitch + len(self.C_D[0])) 3164930cef6SMatthias Ringwald 3174930cef6SMatthias Ringwald self.p_e = [ 0, 0 ] 3184930cef6SMatthias Ringwald self.p_f = [ 0, 0 ] 3194930cef6SMatthias Ringwald self.c_n = [ None, None ] 3204930cef6SMatthias Ringwald self.c_d = [ None, None ] 3214930cef6SMatthias Ringwald 3224930cef6SMatthias Ringwald def load(self, b): 3234930cef6SMatthias Ringwald 3244930cef6SMatthias Ringwald self.active[0] = bool(b.read_uint(1)) 3254930cef6SMatthias Ringwald self.pitch_index = b.read_uint(9) 3264930cef6SMatthias Ringwald 3274930cef6SMatthias Ringwald def disable(self): 3284930cef6SMatthias Ringwald 3294930cef6SMatthias Ringwald self.active[0] = False 3304930cef6SMatthias Ringwald self.pitch_index = 0 3314930cef6SMatthias Ringwald 3324930cef6SMatthias Ringwald def run(self, x, nbytes): 3334930cef6SMatthias Ringwald 3344930cef6SMatthias Ringwald sr = self.sr 3354930cef6SMatthias Ringwald dt = self.dt 3364930cef6SMatthias Ringwald 337*6897da5cSDirk Helbig ### Filter parameters 3384930cef6SMatthias Ringwald 3394930cef6SMatthias Ringwald pitch_index = self.pitch_index 3404930cef6SMatthias Ringwald 3414930cef6SMatthias Ringwald if pitch_index >= 440: 3424930cef6SMatthias Ringwald p_e = pitch_index - 283 3434930cef6SMatthias Ringwald p_f = 0 3444930cef6SMatthias Ringwald elif pitch_index >= 380: 3454930cef6SMatthias Ringwald p_e = pitch_index // 2 - 63 3464930cef6SMatthias Ringwald p_f = 2*(pitch_index - 2*(p_e + 63)) 3474930cef6SMatthias Ringwald else: 3484930cef6SMatthias Ringwald p_e = pitch_index // 4 + 32 3494930cef6SMatthias Ringwald p_f = pitch_index - 4*(p_e - 32) 3504930cef6SMatthias Ringwald 3514930cef6SMatthias Ringwald p = (p_e + p_f / 4) * T.SRATE_KHZ[self.sr] / 12.8 3524930cef6SMatthias Ringwald 3534930cef6SMatthias Ringwald self.p_e[0] = int(p * 4 + 0.5) // 4 3544930cef6SMatthias Ringwald self.p_f[0] = int(p * 4 + 0.5) - 4*self.p_e[0] 3554930cef6SMatthias Ringwald 356*6897da5cSDirk Helbig nbits = round(nbytes*8 * 10 / T.DT_MS[dt]) 357*6897da5cSDirk Helbig if dt == T.DT_2M5: 358*6897da5cSDirk Helbig nbits = int(nbits * (1 - 0.4)) 359*6897da5cSDirk Helbig elif dt == T.DT_5M: 360*6897da5cSDirk Helbig nbits = nbits - 160 361*6897da5cSDirk Helbig 3624930cef6SMatthias Ringwald g_idx = max(nbits // 80, 3+sr) - (3+sr) 3634930cef6SMatthias Ringwald 3644930cef6SMatthias Ringwald g = [ 0.4, 0.35, 0.3, 0.25 ][g_idx] if g_idx < 4 else 0 3654930cef6SMatthias Ringwald g_idx = min(g_idx, 3) 3664930cef6SMatthias Ringwald 3674930cef6SMatthias Ringwald self.c_n[0] = 0.85 * g * LtpfSynthesis.C_N[sr][g_idx] 3684930cef6SMatthias Ringwald self.c_d[0] = g * LtpfSynthesis.C_D[sr][self.p_f[0]] 3694930cef6SMatthias Ringwald 370*6897da5cSDirk Helbig ### Transition handling 3714930cef6SMatthias Ringwald 3724930cef6SMatthias Ringwald n0 = (T.SRATE_KHZ[sr] * 1000) // 400 3734930cef6SMatthias Ringwald ns = T.NS[dt][sr] 3744930cef6SMatthias Ringwald 3754930cef6SMatthias Ringwald x = np.append(x, self.x) 3764930cef6SMatthias Ringwald y = np.append(np.zeros(ns), self.y) 3774930cef6SMatthias Ringwald yc = y.copy() 3784930cef6SMatthias Ringwald 3794930cef6SMatthias Ringwald c_n = self.c_n 3804930cef6SMatthias Ringwald c_d = self.c_d 3814930cef6SMatthias Ringwald 3824930cef6SMatthias Ringwald l_n = len(c_n[0]) 3834930cef6SMatthias Ringwald l_d = len(c_d[0]) 3844930cef6SMatthias Ringwald 3854930cef6SMatthias Ringwald d = [ self.p_e[0] - (l_d - 1) // 2, 3864930cef6SMatthias Ringwald self.p_e[1] - (l_d - 1) // 2 ] 3874930cef6SMatthias Ringwald 3884930cef6SMatthias Ringwald for k in range(n0): 3894930cef6SMatthias Ringwald 3904930cef6SMatthias Ringwald if not self.active[0] and not self.active[1]: 3914930cef6SMatthias Ringwald y[k] = x[k] 3924930cef6SMatthias Ringwald 3934930cef6SMatthias Ringwald elif self.active[0] and not self.active[1]: 3944930cef6SMatthias Ringwald u = np.dot(c_n[0], np.take(x, k - np.arange(l_n))) - \ 3954930cef6SMatthias Ringwald np.dot(c_d[0], np.take(y, k - d[0] - np.arange(l_d))) 3964930cef6SMatthias Ringwald y[k] = x[k] - (k/n0) * u 3974930cef6SMatthias Ringwald 3984930cef6SMatthias Ringwald elif not self.active[0] and self.active[1]: 3994930cef6SMatthias Ringwald u = np.dot(c_n[1], np.take(x, k - np.arange(l_n))) - \ 4004930cef6SMatthias Ringwald np.dot(c_d[1], np.take(y, k - d[1] - np.arange(l_d))) 4014930cef6SMatthias Ringwald y[k] = x[k] - (1 - k/n0) * u 4024930cef6SMatthias Ringwald 4034930cef6SMatthias Ringwald elif self.p_e[0] == self.p_e[1] and self.p_f[0] == self.p_f[1]: 4044930cef6SMatthias Ringwald u = np.dot(c_n[0], np.take(x, k - np.arange(l_n))) - \ 4054930cef6SMatthias Ringwald np.dot(c_d[0], np.take(y, k - d[0] - np.arange(l_d))) 4064930cef6SMatthias Ringwald y[k] = x[k] - u 4074930cef6SMatthias Ringwald 4084930cef6SMatthias Ringwald else: 4094930cef6SMatthias Ringwald u = np.dot(c_n[1], np.take(x, k - np.arange(l_n))) - \ 4104930cef6SMatthias Ringwald np.dot(c_d[1], np.take(y, k - d[1] - np.arange(l_d))) 4114930cef6SMatthias Ringwald yc[k] = x[k] - (1 - k/n0) * u 4124930cef6SMatthias Ringwald 4134930cef6SMatthias Ringwald u = np.dot(c_n[0], np.take(yc, k - np.arange(l_n))) - \ 4144930cef6SMatthias Ringwald np.dot(c_d[0], np.take(y , k - d[0] - np.arange(l_d))) 4154930cef6SMatthias Ringwald y[k] = yc[k] - (k/n0) * u 4164930cef6SMatthias Ringwald 417*6897da5cSDirk Helbig ### Remainder of the frame 4184930cef6SMatthias Ringwald 4194930cef6SMatthias Ringwald for k in range(n0, ns): 4204930cef6SMatthias Ringwald 4214930cef6SMatthias Ringwald if not self.active[0]: 4224930cef6SMatthias Ringwald y[k] = x[k] 4234930cef6SMatthias Ringwald 4244930cef6SMatthias Ringwald else: 4254930cef6SMatthias Ringwald u = np.dot(c_n[0], np.take(x, k - np.arange(l_n))) - \ 4264930cef6SMatthias Ringwald np.dot(c_d[0], np.take(y, k - d[0] - np.arange(l_d))) 4274930cef6SMatthias Ringwald y[k] = x[k] - u 4284930cef6SMatthias Ringwald 4294930cef6SMatthias Ringwald ### Sliding window 4304930cef6SMatthias Ringwald 4314930cef6SMatthias Ringwald self.active[1] = self.active[0] 4324930cef6SMatthias Ringwald self.p_e[1] = self.p_e[0] 4334930cef6SMatthias Ringwald self.p_f[1] = self.p_f[0] 4344930cef6SMatthias Ringwald self.c_n[1] = self.c_n[0] 4354930cef6SMatthias Ringwald self.c_d[1] = self.c_d[0] 4364930cef6SMatthias Ringwald 4374930cef6SMatthias Ringwald self.x = x[:ns] 4384930cef6SMatthias Ringwald self.y = np.append(self.y[ns:], y[:ns]) 4394930cef6SMatthias Ringwald 4404930cef6SMatthias Ringwald return y[:ns] 4414930cef6SMatthias Ringwald 4424930cef6SMatthias Ringwalddef initial_state(): 4434930cef6SMatthias Ringwald return { 'active' : False, 'pitch': 0, 'nc': np.zeros(2), 4444930cef6SMatthias Ringwald 'hp50' : initial_hp50_state(), 4454930cef6SMatthias Ringwald 'x_12k8' : np.zeros(384), 'x_6k4' : np.zeros(178), 'tc' : 0 } 4464930cef6SMatthias Ringwald 4474930cef6SMatthias Ringwalddef initial_sstate(): 4484930cef6SMatthias Ringwald return { 'active': False, 'pitch': 0, 4494930cef6SMatthias Ringwald 'c': np.zeros(2*12), 'x': np.zeros(12) } 4504930cef6SMatthias Ringwald 4514930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 4524930cef6SMatthias Ringwald 4534930cef6SMatthias Ringwalddef check_resampler(rng, dt, sr): 4544930cef6SMatthias Ringwald 4554930cef6SMatthias Ringwald ns = T.NS[dt][sr] 4564930cef6SMatthias Ringwald nt = (5 * T.SRATE_KHZ[sr]) // 4 4574930cef6SMatthias Ringwald ok = True 4584930cef6SMatthias Ringwald 4594930cef6SMatthias Ringwald r = Resampler_12k8(dt, sr) 4604930cef6SMatthias Ringwald 4614930cef6SMatthias Ringwald hp50_c = initial_hp50_state() 4624930cef6SMatthias Ringwald x_c = np.zeros(nt) 4634930cef6SMatthias Ringwald y_c = np.zeros(384) 4644930cef6SMatthias Ringwald 4654930cef6SMatthias Ringwald for run in range(10): 4664930cef6SMatthias Ringwald 4674930cef6SMatthias Ringwald x = ((2 * rng.random(ns)) - 1) * (2 ** 15 - 1) 4684930cef6SMatthias Ringwald y = r.resample(x) 4694930cef6SMatthias Ringwald 4704930cef6SMatthias Ringwald x_c = np.append(x_c[-nt:], x.astype(np.int16)) 4714930cef6SMatthias Ringwald y_c[:-r.n] = y_c[r.n:] 4724930cef6SMatthias Ringwald y_c = lc3.ltpf_resample(dt, sr, hp50_c, x_c, y_c) 4734930cef6SMatthias Ringwald 4744930cef6SMatthias Ringwald ok = ok and np.amax(np.abs(y_c[-r.d-r.n:] - y[:r.d+r.n]/2)) < 4 4754930cef6SMatthias Ringwald 4764930cef6SMatthias Ringwald return ok 4774930cef6SMatthias Ringwald 4784930cef6SMatthias Ringwalddef check_resampler_appendix_c(dt): 4794930cef6SMatthias Ringwald 480*6897da5cSDirk Helbig i0 = dt - T.DT_7M5 4814930cef6SMatthias Ringwald sr = T.SRATE_16K 482*6897da5cSDirk Helbig 4834930cef6SMatthias Ringwald ok = True 4844930cef6SMatthias Ringwald 4854930cef6SMatthias Ringwald nt = (5 * T.SRATE_KHZ[sr]) // 4 486*6897da5cSDirk Helbig n = [ 96, 128 ][i0] 487*6897da5cSDirk Helbig k = [ 44, 24 ][i0] + n 4884930cef6SMatthias Ringwald 4894930cef6SMatthias Ringwald state = initial_hp50_state() 4904930cef6SMatthias Ringwald 491*6897da5cSDirk Helbig x = np.append(np.zeros(nt), C.X_PCM[i0][0]) 4924930cef6SMatthias Ringwald y = np.zeros(384) 4934930cef6SMatthias Ringwald y = lc3.ltpf_resample(dt, sr, state, x, y) 494*6897da5cSDirk Helbig u = y[-k:len(C.X_TILDE_12K8D[i0][0])-k] 4954930cef6SMatthias Ringwald 496*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[i0][0]/2)) < 2 4974930cef6SMatthias Ringwald 498*6897da5cSDirk Helbig x = np.append(x[-nt:], C.X_PCM[i0][1]) 4994930cef6SMatthias Ringwald y[:-n] = y[n:] 5004930cef6SMatthias Ringwald y = lc3.ltpf_resample(dt, sr, state, x, y) 501*6897da5cSDirk Helbig u = y[-k:len(C.X_TILDE_12K8D[i0][1])-k] 5024930cef6SMatthias Ringwald 503*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[i0][1]/2)) < 2 5044930cef6SMatthias Ringwald 5054930cef6SMatthias Ringwald return ok 5064930cef6SMatthias Ringwald 5074930cef6SMatthias Ringwalddef check_analysis(rng, dt, sr): 5084930cef6SMatthias Ringwald 5094930cef6SMatthias Ringwald ns = T.NS[dt][sr] 5104930cef6SMatthias Ringwald nt = (5 * T.SRATE_KHZ[sr]) // 4 5114930cef6SMatthias Ringwald ok = True 5124930cef6SMatthias Ringwald 5134930cef6SMatthias Ringwald state_c = initial_state() 5144930cef6SMatthias Ringwald x_c = np.zeros(ns+nt) 5154930cef6SMatthias Ringwald 5164930cef6SMatthias Ringwald ltpf = LtpfAnalysis(dt, sr) 5174930cef6SMatthias Ringwald 5184930cef6SMatthias Ringwald t = np.arange(100 * ns) / (T.SRATE_KHZ[sr] * 1000) 519*6897da5cSDirk Helbig s = signal.chirp(t, f0=10, f1=2500, t1=t[-1], method='logarithmic') 5204930cef6SMatthias Ringwald 5214930cef6SMatthias Ringwald for i in range(20): 5224930cef6SMatthias Ringwald 5234930cef6SMatthias Ringwald x = s[i*ns:(i+1)*ns] * (2 ** 15 - 1) 5244930cef6SMatthias Ringwald 5254930cef6SMatthias Ringwald pitch_present = ltpf.run(x) 5264930cef6SMatthias Ringwald data = ltpf.get_data() 5274930cef6SMatthias Ringwald 5284930cef6SMatthias Ringwald x_c = np.append(x_c[-nt:], x.astype(np.int16)) 5294930cef6SMatthias Ringwald (pitch_present_c, data_c) = lc3.ltpf_analyse(dt, sr, state_c, x_c) 5304930cef6SMatthias Ringwald 5314930cef6SMatthias Ringwald ok = ok and (not pitch_present or state_c['tc'] == ltpf.tc) 532*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(state_c['nc'][0] - ltpf.nc[0])) < 1e-1 5334930cef6SMatthias Ringwald ok = ok and pitch_present_c == pitch_present 5344930cef6SMatthias Ringwald ok = ok and data_c['active'] == data['active'] 5354930cef6SMatthias Ringwald ok = ok and data_c['pitch_index'] == data['pitch_index'] 5364930cef6SMatthias Ringwald ok = ok and lc3.ltpf_get_nbits(pitch_present) == ltpf.get_nbits() 5374930cef6SMatthias Ringwald 5384930cef6SMatthias Ringwald return ok 5394930cef6SMatthias Ringwald 5404930cef6SMatthias Ringwalddef check_synthesis(rng, dt, sr): 5414930cef6SMatthias Ringwald 5424930cef6SMatthias Ringwald ok = True 5434930cef6SMatthias Ringwald 5444930cef6SMatthias Ringwald ns = T.NS[dt][sr] 5454930cef6SMatthias Ringwald nd = 18 * T.SRATE_KHZ[sr] 5464930cef6SMatthias Ringwald 5474930cef6SMatthias Ringwald synthesis = LtpfSynthesis(dt, sr) 5484930cef6SMatthias Ringwald 5494930cef6SMatthias Ringwald state_c = initial_sstate() 5504930cef6SMatthias Ringwald x_c = np.zeros(nd+ns) 5514930cef6SMatthias Ringwald 5524930cef6SMatthias Ringwald for i in range(50): 553*6897da5cSDirk Helbig 5544930cef6SMatthias Ringwald pitch_present = bool(rng.integers(0, 10) >= 1) 5554930cef6SMatthias Ringwald if not pitch_present: 5564930cef6SMatthias Ringwald synthesis.disable() 5574930cef6SMatthias Ringwald else: 5584930cef6SMatthias Ringwald synthesis.active[0] = bool(rng.integers(0, 5) >= 1) 5594930cef6SMatthias Ringwald synthesis.pitch_index = rng.integers(0, 512) 5604930cef6SMatthias Ringwald 5614930cef6SMatthias Ringwald data_c = None if not pitch_present else \ 5624930cef6SMatthias Ringwald { 'active' : synthesis.active[0], 5634930cef6SMatthias Ringwald 'pitch_index' : synthesis.pitch_index } 5644930cef6SMatthias Ringwald 5654930cef6SMatthias Ringwald x = rng.random(ns) * 1e4 5664930cef6SMatthias Ringwald nbytes = rng.integers(10*(2+sr), 10*(6+sr)) 5674930cef6SMatthias Ringwald 5684930cef6SMatthias Ringwald x_c[:nd] = x_c[ns:] 5694930cef6SMatthias Ringwald x_c[nd:] = x 5704930cef6SMatthias Ringwald 5714930cef6SMatthias Ringwald y = synthesis.run(x, nbytes) 5724930cef6SMatthias Ringwald x_c = lc3.ltpf_synthesize(dt, sr, nbytes, state_c, data_c, x_c) 5734930cef6SMatthias Ringwald 5744930cef6SMatthias Ringwald ok = ok and np.amax(np.abs(x_c[nd:] - y)) < 1e-2 5754930cef6SMatthias Ringwald 5764930cef6SMatthias Ringwald return ok 5774930cef6SMatthias Ringwald 5784930cef6SMatthias Ringwalddef check_analysis_appendix_c(dt): 5794930cef6SMatthias Ringwald 580*6897da5cSDirk Helbig i0 = dt - T.DT_7M5 5814930cef6SMatthias Ringwald sr = T.SRATE_16K 582*6897da5cSDirk Helbig 5834930cef6SMatthias Ringwald ok = True 5844930cef6SMatthias Ringwald 585*6897da5cSDirk Helbig nt = (5 * T.SRATE_KHZ[sr]) // 4 586*6897da5cSDirk Helbig 5874930cef6SMatthias Ringwald state = initial_state() 5884930cef6SMatthias Ringwald 589*6897da5cSDirk Helbig x = np.append(np.zeros(nt), C.X_PCM[i0][0]) 5904930cef6SMatthias Ringwald (pitch_present, data) = lc3.ltpf_analyse(dt, sr, state, x) 5914930cef6SMatthias Ringwald 592*6897da5cSDirk Helbig ok = ok and C.T_CURR[i0][0] - state['tc'] == 17 593*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[i0][0])) < 1e-5 594*6897da5cSDirk Helbig ok = ok and pitch_present == C.PITCH_PRESENT[i0][0] 595*6897da5cSDirk Helbig ok = ok and data['pitch_index'] == C.PITCH_INDEX[i0][0] 596*6897da5cSDirk Helbig ok = ok and data['active'] == C.LTPF_ACTIVE[i0][0] 5974930cef6SMatthias Ringwald 598*6897da5cSDirk Helbig x = np.append(x[-nt:], C.X_PCM[i0][1]) 5994930cef6SMatthias Ringwald (pitch_present, data) = lc3.ltpf_analyse(dt, sr, state, x) 6004930cef6SMatthias Ringwald 601*6897da5cSDirk Helbig ok = ok and C.T_CURR[i0][1] - state['tc'] == 17 602*6897da5cSDirk Helbig ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[i0][1])) < 1e-5 603*6897da5cSDirk Helbig ok = ok and pitch_present == C.PITCH_PRESENT[i0][1] 604*6897da5cSDirk Helbig ok = ok and data['pitch_index'] == C.PITCH_INDEX[i0][1] 605*6897da5cSDirk Helbig ok = ok and data['active'] == C.LTPF_ACTIVE[i0][1] 6064930cef6SMatthias Ringwald 6074930cef6SMatthias Ringwald return ok 6084930cef6SMatthias Ringwald 6094930cef6SMatthias Ringwalddef check_synthesis_appendix_c(dt): 6104930cef6SMatthias Ringwald 6114930cef6SMatthias Ringwald sr = T.SRATE_16K 6124930cef6SMatthias Ringwald 613*6897da5cSDirk Helbig ok = True 6144930cef6SMatthias Ringwald if dt != T.DT_10M: 6154930cef6SMatthias Ringwald return ok 6164930cef6SMatthias Ringwald 6174930cef6SMatthias Ringwald ns = T.NS[dt][sr] 6184930cef6SMatthias Ringwald nd = 18 * T.SRATE_KHZ[sr] 6194930cef6SMatthias Ringwald 6204930cef6SMatthias Ringwald NBYTES = [ C.LTPF_C2_NBITS // 8, C.LTPF_C3_NBITS // 8, 6214930cef6SMatthias Ringwald C.LTPF_C4_NBITS // 8, C.LTPF_C5_NBITS // 8 ] 6224930cef6SMatthias Ringwald 6234930cef6SMatthias Ringwald ACTIVE = [ C.LTPF_C2_ACTIVE, C.LTPF_C3_ACTIVE, 6244930cef6SMatthias Ringwald C.LTPF_C4_ACTIVE, C.LTPF_C5_ACTIVE ] 6254930cef6SMatthias Ringwald 6264930cef6SMatthias Ringwald PITCH_INDEX = [ C.LTPF_C2_PITCH_INDEX, C.LTPF_C3_PITCH_INDEX, 6274930cef6SMatthias Ringwald C.LTPF_C4_PITCH_INDEX, C.LTPF_C5_PITCH_INDEX ] 6284930cef6SMatthias Ringwald 6294930cef6SMatthias Ringwald X = [ C.LTPF_C2_X, C.LTPF_C3_X, 6304930cef6SMatthias Ringwald C.LTPF_C4_X, C.LTPF_C5_X ] 6314930cef6SMatthias Ringwald 6324930cef6SMatthias Ringwald PREV = [ C.LTPF_C2_PREV, C.LTPF_C3_PREV, 6334930cef6SMatthias Ringwald C.LTPF_C4_PREV, C.LTPF_C5_PREV ] 6344930cef6SMatthias Ringwald 6354930cef6SMatthias Ringwald TRANS = [ C.LTPF_C2_TRANS, C.LTPF_C3_TRANS, 6364930cef6SMatthias Ringwald C.LTPF_C4_TRANS, C.LTPF_C5_TRANS ] 6374930cef6SMatthias Ringwald 6384930cef6SMatthias Ringwald for i in range(4): 6394930cef6SMatthias Ringwald 6404930cef6SMatthias Ringwald state = initial_sstate() 6414930cef6SMatthias Ringwald nbytes = NBYTES[i] 6424930cef6SMatthias Ringwald 6434930cef6SMatthias Ringwald data = { 'active' : ACTIVE[i][0], 'pitch_index' : PITCH_INDEX[i][0] } 6444930cef6SMatthias Ringwald x = np.append(np.zeros(nd), X[i][0]) 6454930cef6SMatthias Ringwald 6464930cef6SMatthias Ringwald lc3.ltpf_synthesize(dt, sr, nbytes, state, data, x) 6474930cef6SMatthias Ringwald 6484930cef6SMatthias Ringwald data = { 'active' : ACTIVE[i][1], 'pitch_index' : PITCH_INDEX[i][1] } 6494930cef6SMatthias Ringwald x[ :nd-ns] = PREV[i][0][-nd+ns:] 6504930cef6SMatthias Ringwald x[nd-ns:nd] = PREV[i][1] 6514930cef6SMatthias Ringwald x[nd:nd+ns] = X[i][1] 6524930cef6SMatthias Ringwald 6534930cef6SMatthias Ringwald y = lc3.ltpf_synthesize(dt, sr, nbytes, state, data, x)[nd:] 6544930cef6SMatthias Ringwald 6554930cef6SMatthias Ringwald ok = ok and np.amax(np.abs(y - TRANS[i])) < 1e-3 6564930cef6SMatthias Ringwald 6574930cef6SMatthias Ringwald return ok 6584930cef6SMatthias Ringwald 6594930cef6SMatthias Ringwalddef check(): 6604930cef6SMatthias Ringwald 6614930cef6SMatthias Ringwald rng = np.random.default_rng(1234) 6624930cef6SMatthias Ringwald ok = True 6634930cef6SMatthias Ringwald 6644930cef6SMatthias Ringwald for dt in range(T.NUM_DT): 665*6897da5cSDirk Helbig for sr in range(T.SRATE_8K, T.SRATE_48K + 1): 6664930cef6SMatthias Ringwald ok = ok and check_resampler(rng, dt, sr) 6674930cef6SMatthias Ringwald ok = ok and check_analysis(rng, dt, sr) 6684930cef6SMatthias Ringwald ok = ok and check_synthesis(rng, dt, sr) 6694930cef6SMatthias Ringwald 670*6897da5cSDirk Helbig for dt in ( T.DT_7M5, T.DT_10M ): 6714930cef6SMatthias Ringwald ok = ok and check_resampler_appendix_c(dt) 6724930cef6SMatthias Ringwald ok = ok and check_analysis_appendix_c(dt) 6734930cef6SMatthias Ringwald ok = ok and check_synthesis_appendix_c(dt) 6744930cef6SMatthias Ringwald 6754930cef6SMatthias Ringwald return ok 6764930cef6SMatthias Ringwald 6774930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 678