1*49fe348cSAndroid Build Coastguard Worker# 2*49fe348cSAndroid Build Coastguard Worker# Copyright 2022 Google LLC 3*49fe348cSAndroid Build Coastguard Worker# 4*49fe348cSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*49fe348cSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*49fe348cSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*49fe348cSAndroid Build Coastguard Worker# 8*49fe348cSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*49fe348cSAndroid Build Coastguard Worker# 10*49fe348cSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*49fe348cSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*49fe348cSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*49fe348cSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*49fe348cSAndroid Build Coastguard Worker# limitations under the License. 15*49fe348cSAndroid Build Coastguard Worker# 16*49fe348cSAndroid Build Coastguard Worker 17*49fe348cSAndroid Build Coastguard Workerimport numpy as np 18*49fe348cSAndroid Build Coastguard Workerimport scipy.fft 19*49fe348cSAndroid Build Coastguard Worker 20*49fe348cSAndroid Build Coastguard Workerimport lc3 21*49fe348cSAndroid Build Coastguard Workerimport tables as T, appendix_c as C 22*49fe348cSAndroid Build Coastguard Worker 23*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ### 24*49fe348cSAndroid Build Coastguard Worker 25*49fe348cSAndroid Build Coastguard Workerclass Mdct: 26*49fe348cSAndroid Build Coastguard Worker 27*49fe348cSAndroid Build Coastguard Worker W = [ [ T.W_2M5_8K , T.W_2M5_16K, T.W_2M5_24K, 28*49fe348cSAndroid Build Coastguard Worker T.W_2M5_32K, T.W_2M5_48K, T.W_2M5_48K_HR, T.W_2M5_96K_HR ], 29*49fe348cSAndroid Build Coastguard Worker 30*49fe348cSAndroid Build Coastguard Worker [ T.W_5M_8K , T.W_5M_16K , T.W_5M_24K , 31*49fe348cSAndroid Build Coastguard Worker T.W_5M_32K , T.W_5M_48K , T.W_5M_48K_HR , T.W_5M_96K_HR ], 32*49fe348cSAndroid Build Coastguard Worker 33*49fe348cSAndroid Build Coastguard Worker [ T.W_7M5_8K , T.W_7M5_16K, T.W_7M5_24K, 34*49fe348cSAndroid Build Coastguard Worker T.W_7M5_32K, T.W_7M5_48K, None, None ], 35*49fe348cSAndroid Build Coastguard Worker 36*49fe348cSAndroid Build Coastguard Worker [ T.W_10M_8K , T.W_10M_16K, T.W_10M_24K, 37*49fe348cSAndroid Build Coastguard Worker T.W_10M_32K, T.W_10M_48K, T.W_10M_48K_HR, T.W_10M_96K_HR ] ] 38*49fe348cSAndroid Build Coastguard Worker 39*49fe348cSAndroid Build Coastguard Worker def __init__(self, dt, sr): 40*49fe348cSAndroid Build Coastguard Worker 41*49fe348cSAndroid Build Coastguard Worker self.ns = T.NS[dt][sr] 42*49fe348cSAndroid Build Coastguard Worker self.nd = T.ND[dt][sr] 43*49fe348cSAndroid Build Coastguard Worker 44*49fe348cSAndroid Build Coastguard Worker self.t = np.zeros(2*self.ns) 45*49fe348cSAndroid Build Coastguard Worker self.w = Mdct.W[dt][sr] 46*49fe348cSAndroid Build Coastguard Worker 47*49fe348cSAndroid Build Coastguard Worker 48*49fe348cSAndroid Build Coastguard Workerclass MdctForward(Mdct): 49*49fe348cSAndroid Build Coastguard Worker 50*49fe348cSAndroid Build Coastguard Worker def __init__(self, dt, sr): 51*49fe348cSAndroid Build Coastguard Worker 52*49fe348cSAndroid Build Coastguard Worker super().__init__(dt, sr) 53*49fe348cSAndroid Build Coastguard Worker 54*49fe348cSAndroid Build Coastguard Worker def run(self, x): 55*49fe348cSAndroid Build Coastguard Worker 56*49fe348cSAndroid Build Coastguard Worker ns = self.ns 57*49fe348cSAndroid Build Coastguard Worker nd = self.nd 58*49fe348cSAndroid Build Coastguard Worker 59*49fe348cSAndroid Build Coastguard Worker self.t[nd:nd+ns] = x 60*49fe348cSAndroid Build Coastguard Worker t = self.t * self.w 61*49fe348cSAndroid Build Coastguard Worker self.t[0:nd] = x[ns-nd:] 62*49fe348cSAndroid Build Coastguard Worker 63*49fe348cSAndroid Build Coastguard Worker n = len(t) 64*49fe348cSAndroid Build Coastguard Worker n2 = n // 2 65*49fe348cSAndroid Build Coastguard Worker 66*49fe348cSAndroid Build Coastguard Worker z = t * np.exp(-2j * np.pi * np.arange(n) / (2*n)) 67*49fe348cSAndroid Build Coastguard Worker z = scipy.fft.fft(z)[:n2] 68*49fe348cSAndroid Build Coastguard Worker z = z * np.exp(-2j * np.pi * 69*49fe348cSAndroid Build Coastguard Worker (n2/2 + 0.5) * (np.arange(n2) + 0.5) / (2 * n2)) 70*49fe348cSAndroid Build Coastguard Worker return np.real(z) * np.sqrt(2/n2) 71*49fe348cSAndroid Build Coastguard Worker 72*49fe348cSAndroid Build Coastguard Worker 73*49fe348cSAndroid Build Coastguard Workerclass MdctInverse(Mdct): 74*49fe348cSAndroid Build Coastguard Worker 75*49fe348cSAndroid Build Coastguard Worker def __init__(self, dt, sr): 76*49fe348cSAndroid Build Coastguard Worker 77*49fe348cSAndroid Build Coastguard Worker super().__init__(dt, sr) 78*49fe348cSAndroid Build Coastguard Worker 79*49fe348cSAndroid Build Coastguard Worker def run(self, x): 80*49fe348cSAndroid Build Coastguard Worker 81*49fe348cSAndroid Build Coastguard Worker ns = self.ns 82*49fe348cSAndroid Build Coastguard Worker nd = self.nd 83*49fe348cSAndroid Build Coastguard Worker 84*49fe348cSAndroid Build Coastguard Worker n = len(x) 85*49fe348cSAndroid Build Coastguard Worker 86*49fe348cSAndroid Build Coastguard Worker x = np.append(x, -x[::-1]) 87*49fe348cSAndroid Build Coastguard Worker z = x * np.exp(2j * np.pi * (n/2 + 0.5) * np.arange(2*n) / (2*n)) 88*49fe348cSAndroid Build Coastguard Worker z = scipy.fft.ifft(z) * n 89*49fe348cSAndroid Build Coastguard Worker z = z * np.exp(2j * np.pi * (np.arange(2*n) + (n/2 + 0.5)) / (4*n)) 90*49fe348cSAndroid Build Coastguard Worker t = np.real(z) * np.sqrt(2/n) 91*49fe348cSAndroid Build Coastguard Worker 92*49fe348cSAndroid Build Coastguard Worker t = t * self.w[::-1] 93*49fe348cSAndroid Build Coastguard Worker 94*49fe348cSAndroid Build Coastguard Worker y = np.empty(ns) 95*49fe348cSAndroid Build Coastguard Worker y[:nd] = t[ns-nd:ns] + self.t[2*ns-nd:] 96*49fe348cSAndroid Build Coastguard Worker y[nd:] = t[ns:2*ns-nd] 97*49fe348cSAndroid Build Coastguard Worker self.t = t 98*49fe348cSAndroid Build Coastguard Worker 99*49fe348cSAndroid Build Coastguard Worker return y 100*49fe348cSAndroid Build Coastguard Worker 101*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ### 102*49fe348cSAndroid Build Coastguard Worker 103*49fe348cSAndroid Build Coastguard Workerdef check_forward_unit(rng, dt, sr): 104*49fe348cSAndroid Build Coastguard Worker 105*49fe348cSAndroid Build Coastguard Worker ns = T.NS[dt][sr] 106*49fe348cSAndroid Build Coastguard Worker nd = T.ND[dt][sr] 107*49fe348cSAndroid Build Coastguard Worker ok = True 108*49fe348cSAndroid Build Coastguard Worker 109*49fe348cSAndroid Build Coastguard Worker x = (2 * rng.random(ns)) - 1 110*49fe348cSAndroid Build Coastguard Worker 111*49fe348cSAndroid Build Coastguard Worker y = [ None ] * 2 112*49fe348cSAndroid Build Coastguard Worker y_c = [ None ] * 2 113*49fe348cSAndroid Build Coastguard Worker 114*49fe348cSAndroid Build Coastguard Worker mdct = MdctForward(dt, sr) 115*49fe348cSAndroid Build Coastguard Worker y[0] = mdct.run(x) 116*49fe348cSAndroid Build Coastguard Worker y[1] = mdct.run(x) 117*49fe348cSAndroid Build Coastguard Worker 118*49fe348cSAndroid Build Coastguard Worker (y_c[0], d_c) = lc3.mdct_forward(dt, sr, x, np.zeros(nd)) 119*49fe348cSAndroid Build Coastguard Worker y_c[1] = lc3.mdct_forward(dt, sr, x, d_c)[0] 120*49fe348cSAndroid Build Coastguard Worker 121*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5 122*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5 123*49fe348cSAndroid Build Coastguard Worker 124*49fe348cSAndroid Build Coastguard Worker return ok 125*49fe348cSAndroid Build Coastguard Worker 126*49fe348cSAndroid Build Coastguard Worker 127*49fe348cSAndroid Build Coastguard Workerdef check_forward_appendix_c(dt): 128*49fe348cSAndroid Build Coastguard Worker 129*49fe348cSAndroid Build Coastguard Worker i0 = dt - T.DT_7M5 130*49fe348cSAndroid Build Coastguard Worker sr = T.SRATE_16K 131*49fe348cSAndroid Build Coastguard Worker 132*49fe348cSAndroid Build Coastguard Worker ok = True 133*49fe348cSAndroid Build Coastguard Worker 134*49fe348cSAndroid Build Coastguard Worker ns = T.NS[dt][sr] 135*49fe348cSAndroid Build Coastguard Worker nd = T.ND[dt][sr] 136*49fe348cSAndroid Build Coastguard Worker 137*49fe348cSAndroid Build Coastguard Worker (y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[i0][0], np.zeros(nd)) 138*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(y - C.X[i0][0])) < 1e-1 139*49fe348cSAndroid Build Coastguard Worker 140*49fe348cSAndroid Build Coastguard Worker (y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[i0][1], d) 141*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(y - C.X[i0][1])) < 1e-1 142*49fe348cSAndroid Build Coastguard Worker 143*49fe348cSAndroid Build Coastguard Worker return ok 144*49fe348cSAndroid Build Coastguard Worker 145*49fe348cSAndroid Build Coastguard Worker 146*49fe348cSAndroid Build Coastguard Workerdef check_inverse_unit(rng, dt, sr): 147*49fe348cSAndroid Build Coastguard Worker 148*49fe348cSAndroid Build Coastguard Worker ns = T.NS[dt][sr] 149*49fe348cSAndroid Build Coastguard Worker nd = T.ND[dt][sr] 150*49fe348cSAndroid Build Coastguard Worker ok = True 151*49fe348cSAndroid Build Coastguard Worker 152*49fe348cSAndroid Build Coastguard Worker x = (2 * rng.random(ns)) - 1 153*49fe348cSAndroid Build Coastguard Worker 154*49fe348cSAndroid Build Coastguard Worker y = [ None ] * 2 155*49fe348cSAndroid Build Coastguard Worker y_c = [ None ] * 2 156*49fe348cSAndroid Build Coastguard Worker 157*49fe348cSAndroid Build Coastguard Worker mdct = MdctInverse(dt, sr) 158*49fe348cSAndroid Build Coastguard Worker y[0] = mdct.run(x) 159*49fe348cSAndroid Build Coastguard Worker y[1] = mdct.run(x) 160*49fe348cSAndroid Build Coastguard Worker 161*49fe348cSAndroid Build Coastguard Worker (y_c[0], d_c) = lc3.mdct_inverse(dt, sr, x, np.zeros(nd)) 162*49fe348cSAndroid Build Coastguard Worker y_c[1] = lc3.mdct_inverse(dt, sr, x, d_c)[0] 163*49fe348cSAndroid Build Coastguard Worker 164*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5 165*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5 166*49fe348cSAndroid Build Coastguard Worker 167*49fe348cSAndroid Build Coastguard Worker return ok 168*49fe348cSAndroid Build Coastguard Worker 169*49fe348cSAndroid Build Coastguard Worker 170*49fe348cSAndroid Build Coastguard Workerdef check_inverse_appendix_c(dt): 171*49fe348cSAndroid Build Coastguard Worker 172*49fe348cSAndroid Build Coastguard Worker i0 = dt - T.DT_7M5 173*49fe348cSAndroid Build Coastguard Worker sr = T.SRATE_16K 174*49fe348cSAndroid Build Coastguard Worker 175*49fe348cSAndroid Build Coastguard Worker ok = True 176*49fe348cSAndroid Build Coastguard Worker 177*49fe348cSAndroid Build Coastguard Worker ns = T.NS[dt][sr] 178*49fe348cSAndroid Build Coastguard Worker nd = T.ND[dt][sr] 179*49fe348cSAndroid Build Coastguard Worker 180*49fe348cSAndroid Build Coastguard Worker (y, d0) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[i0][0], np.zeros(nd)) 181*49fe348cSAndroid Build Coastguard Worker yr = C.T_HAT_MDCT[i0][0][ns-nd:2*ns-nd] 182*49fe348cSAndroid Build Coastguard Worker dr = C.T_HAT_MDCT[i0][0][2*ns-nd:] 183*49fe348cSAndroid Build Coastguard Worker 184*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(yr - y )) < 1e-1 185*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(dr - d0)) < 1e-1 186*49fe348cSAndroid Build Coastguard Worker 187*49fe348cSAndroid Build Coastguard Worker (y, d1) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[i0][1], d0) 188*49fe348cSAndroid Build Coastguard Worker yr[ :nd] = C.T_HAT_MDCT[i0][1][ns-nd:ns] + d0 189*49fe348cSAndroid Build Coastguard Worker yr[nd:ns] = C.T_HAT_MDCT[i0][1][ns:2*ns-nd] 190*49fe348cSAndroid Build Coastguard Worker dr = C.T_HAT_MDCT[i0][1][2*ns-nd:] 191*49fe348cSAndroid Build Coastguard Worker 192*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(yr - y )) < 1e-1 193*49fe348cSAndroid Build Coastguard Worker ok = ok and np.amax(np.abs(dr - d1)) < 1e-1 194*49fe348cSAndroid Build Coastguard Worker 195*49fe348cSAndroid Build Coastguard Worker return ok 196*49fe348cSAndroid Build Coastguard Worker 197*49fe348cSAndroid Build Coastguard Worker 198*49fe348cSAndroid Build Coastguard Workerdef check(): 199*49fe348cSAndroid Build Coastguard Worker 200*49fe348cSAndroid Build Coastguard Worker rng = np.random.default_rng(1234) 201*49fe348cSAndroid Build Coastguard Worker 202*49fe348cSAndroid Build Coastguard Worker ok = True 203*49fe348cSAndroid Build Coastguard Worker 204*49fe348cSAndroid Build Coastguard Worker for dt in range(T.NUM_DT): 205*49fe348cSAndroid Build Coastguard Worker for sr in range(T.SRATE_8K, T.SRATE_48K + 1): 206*49fe348cSAndroid Build Coastguard Worker ok = ok and check_forward_unit(rng, dt, sr) 207*49fe348cSAndroid Build Coastguard Worker ok = ok and check_inverse_unit(rng, dt, sr) 208*49fe348cSAndroid Build Coastguard Worker 209*49fe348cSAndroid Build Coastguard Worker for dt in ( T.DT_2M5, T.DT_5M, T.DT_10M ): 210*49fe348cSAndroid Build Coastguard Worker for sr in ( T.SRATE_48K_HR, T.SRATE_96K_HR ): 211*49fe348cSAndroid Build Coastguard Worker ok = ok and check_forward_unit(rng, dt, sr) 212*49fe348cSAndroid Build Coastguard Worker ok = ok and check_inverse_unit(rng, dt, sr) 213*49fe348cSAndroid Build Coastguard Worker 214*49fe348cSAndroid Build Coastguard Worker for dt in ( T.DT_7M5, T.DT_10M ): 215*49fe348cSAndroid Build Coastguard Worker ok = ok and check_forward_appendix_c(dt) 216*49fe348cSAndroid Build Coastguard Worker ok = ok and check_inverse_appendix_c(dt) 217*49fe348cSAndroid Build Coastguard Worker 218*49fe348cSAndroid Build Coastguard Worker return ok 219