xref: /btstack/3rd-party/lc3-google/test/tns.py (revision 4930cef6e21e6da2d7571b9259c7f0fb8bed3d01)
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 Ringwald
19*4930cef6SMatthias Ringwaldimport build.lc3 as lc3
20*4930cef6SMatthias Ringwaldimport tables as T, appendix_c as C
21*4930cef6SMatthias Ringwald
22*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
23*4930cef6SMatthias Ringwald
24*4930cef6SMatthias Ringwaldclass Tns:
25*4930cef6SMatthias Ringwald
26*4930cef6SMatthias Ringwald    SUB_LIM_10M_NB   = [ [  12,  34,  57,  80 ] ]
27*4930cef6SMatthias Ringwald    SUB_LIM_10M_WB   = [ [  12,  61, 110, 160 ] ]
28*4930cef6SMatthias Ringwald    SUB_LIM_10M_SSWB = [ [  12,  88, 164, 240 ] ]
29*4930cef6SMatthias Ringwald    SUB_LIM_10M_SWB  = [ [  12,  61, 110, 160 ], [ 160, 213, 266, 320 ] ]
30*4930cef6SMatthias Ringwald    SUB_LIM_10M_FB   = [ [  12,  74, 137, 200 ], [ 200, 266, 333, 400 ] ]
31*4930cef6SMatthias Ringwald
32*4930cef6SMatthias Ringwald    SUB_LIM_10M = [ SUB_LIM_10M_NB, SUB_LIM_10M_WB,
33*4930cef6SMatthias Ringwald        SUB_LIM_10M_SSWB, SUB_LIM_10M_SWB, SUB_LIM_10M_FB ]
34*4930cef6SMatthias Ringwald
35*4930cef6SMatthias Ringwald    SUB_LIM_7M5_NB   = [ [   9,  26,  43,  60 ] ]
36*4930cef6SMatthias Ringwald    SUB_LIM_7M5_WB   = [ [   9,  46,  83, 120 ] ]
37*4930cef6SMatthias Ringwald    SUB_LIM_7M5_SSWB = [ [   9,  66, 123, 180 ] ]
38*4930cef6SMatthias Ringwald    SUB_LIM_7M5_SWB  = [ [   9,  46,  82, 120 ], [ 120, 159, 200, 240 ] ]
39*4930cef6SMatthias Ringwald    SUB_LIM_7M5_FB   = [ [   9,  56, 103, 150 ], [ 150, 200, 250, 300 ] ]
40*4930cef6SMatthias Ringwald
41*4930cef6SMatthias Ringwald    SUB_LIM_7M5 = [ SUB_LIM_7M5_NB, SUB_LIM_7M5_WB,
42*4930cef6SMatthias Ringwald        SUB_LIM_7M5_SSWB, SUB_LIM_7M5_SWB, SUB_LIM_7M5_FB ]
43*4930cef6SMatthias Ringwald
44*4930cef6SMatthias Ringwald    SUB_LIM = [ SUB_LIM_7M5, SUB_LIM_10M ]
45*4930cef6SMatthias Ringwald
46*4930cef6SMatthias Ringwald    FREQ_LIM_10M_NB   = [  12,  80 ]
47*4930cef6SMatthias Ringwald    FREQ_LIM_10M_WB   = [  12, 160 ]
48*4930cef6SMatthias Ringwald    FREQ_LIM_10M_SSWB = [  12, 240 ]
49*4930cef6SMatthias Ringwald    FREQ_LIM_10M_SWB  = [  12, 160, 320 ]
50*4930cef6SMatthias Ringwald    FREQ_LIM_10M_FB   = [  12, 200, 400 ]
51*4930cef6SMatthias Ringwald
52*4930cef6SMatthias Ringwald    FREQ_LIM_10M = [ FREQ_LIM_10M_NB, FREQ_LIM_10M_WB,
53*4930cef6SMatthias Ringwald        FREQ_LIM_10M_SSWB, FREQ_LIM_10M_SWB, FREQ_LIM_10M_FB ]
54*4930cef6SMatthias Ringwald
55*4930cef6SMatthias Ringwald    FREQ_LIM_7M5_NB   = [   9,  60 ]
56*4930cef6SMatthias Ringwald    FREQ_LIM_7M5_WB   = [   9, 120 ]
57*4930cef6SMatthias Ringwald    FREQ_LIM_7M5_SSWB = [   9, 180 ]
58*4930cef6SMatthias Ringwald    FREQ_LIM_7M5_SWB  = [   9, 120, 240 ]
59*4930cef6SMatthias Ringwald    FREQ_LIM_7M5_FB   = [   9, 150, 300 ]
60*4930cef6SMatthias Ringwald
61*4930cef6SMatthias Ringwald    FREQ_LIM_7M5 = [ FREQ_LIM_7M5_NB, FREQ_LIM_7M5_WB,
62*4930cef6SMatthias Ringwald        FREQ_LIM_7M5_SSWB, FREQ_LIM_7M5_SWB, FREQ_LIM_7M5_FB ]
63*4930cef6SMatthias Ringwald
64*4930cef6SMatthias Ringwald    FREQ_LIM = [ FREQ_LIM_7M5, FREQ_LIM_10M ]
65*4930cef6SMatthias Ringwald
66*4930cef6SMatthias Ringwald    def __init__(self, dt):
67*4930cef6SMatthias Ringwald
68*4930cef6SMatthias Ringwald        self.dt = dt
69*4930cef6SMatthias Ringwald
70*4930cef6SMatthias Ringwald        (self.nfilters, self.lpc_weighting, self.rc_order, self.rc) = \
71*4930cef6SMatthias Ringwald            (None, None, None, None)
72*4930cef6SMatthias Ringwald
73*4930cef6SMatthias Ringwald    def get_data(self):
74*4930cef6SMatthias Ringwald
75*4930cef6SMatthias Ringwald        return { 'nfilters' : self.nfilters,
76*4930cef6SMatthias Ringwald                 'lpc_weighting' : self.lpc_weighting,
77*4930cef6SMatthias Ringwald                 'rc_order' : self.rc_order, 'rc' : self.rc - 8 }
78*4930cef6SMatthias Ringwald
79*4930cef6SMatthias Ringwald    def get_nbits(self):
80*4930cef6SMatthias Ringwald
81*4930cef6SMatthias Ringwald        lpc_weighting = self.lpc_weighting
82*4930cef6SMatthias Ringwald        nbits = 0
83*4930cef6SMatthias Ringwald
84*4930cef6SMatthias Ringwald        for f in range(self.nfilters):
85*4930cef6SMatthias Ringwald            rc_order = self.rc_order[f]
86*4930cef6SMatthias Ringwald            rc = self.rc[f]
87*4930cef6SMatthias Ringwald
88*4930cef6SMatthias Ringwald            nbits_order = T.TNS_ORDER_BITS[int(lpc_weighting)][rc_order]
89*4930cef6SMatthias Ringwald            nbits_coef = sum([ T.TNS_COEF_BITS[k][rc[k]]
90*4930cef6SMatthias Ringwald                                  for k in range(rc_order) ])
91*4930cef6SMatthias Ringwald
92*4930cef6SMatthias Ringwald            nbits += ((2048 + nbits_order + nbits_coef) + 2047) >> 11
93*4930cef6SMatthias Ringwald
94*4930cef6SMatthias Ringwald        return nbits
95*4930cef6SMatthias Ringwald
96*4930cef6SMatthias Ringwald
97*4930cef6SMatthias Ringwaldclass TnsAnalysis(Tns):
98*4930cef6SMatthias Ringwald
99*4930cef6SMatthias Ringwald    def __init__(self, dt):
100*4930cef6SMatthias Ringwald
101*4930cef6SMatthias Ringwald        super().__init__(dt)
102*4930cef6SMatthias Ringwald
103*4930cef6SMatthias Ringwald    def compute_lpc_coeffs(self, bw, f, x):
104*4930cef6SMatthias Ringwald
105*4930cef6SMatthias Ringwald        ### Normalized autocorrelation function
106*4930cef6SMatthias Ringwald
107*4930cef6SMatthias Ringwald        S = Tns.SUB_LIM[self.dt][bw][f]
108*4930cef6SMatthias Ringwald
109*4930cef6SMatthias Ringwald        r = np.append([ 3 ], np.zeros(8))
110*4930cef6SMatthias Ringwald        e = [ sum(x[S[s]:S[s+1]] ** 2) for s in range(3) ]
111*4930cef6SMatthias Ringwald
112*4930cef6SMatthias Ringwald        for k in range(len(r) if sum(e) > 0 else 0):
113*4930cef6SMatthias Ringwald            c = [ np.dot(x[S[s]:S[s+1]-k], x[S[s]+k:S[s+1]])
114*4930cef6SMatthias Ringwald                      for s in range(3) ]
115*4930cef6SMatthias Ringwald
116*4930cef6SMatthias Ringwald            r[k] = np.sum( np.array(c) / np.array(e) )
117*4930cef6SMatthias Ringwald
118*4930cef6SMatthias Ringwald        r *= np.exp(-0.5 * (0.02 * np.pi * np.arange(9)) ** 2)
119*4930cef6SMatthias Ringwald
120*4930cef6SMatthias Ringwald        ### Levinson-Durbin recursion
121*4930cef6SMatthias Ringwald
122*4930cef6SMatthias Ringwald        err = r[0]
123*4930cef6SMatthias Ringwald        a = np.ones(len(r))
124*4930cef6SMatthias Ringwald
125*4930cef6SMatthias Ringwald        for k in range(1, len(a)):
126*4930cef6SMatthias Ringwald
127*4930cef6SMatthias Ringwald            rc = -sum(a[:k] * r[k:0:-1]) / err
128*4930cef6SMatthias Ringwald
129*4930cef6SMatthias Ringwald            a[1:k] += rc * a[k-1:0:-1]
130*4930cef6SMatthias Ringwald            a[k] = rc
131*4930cef6SMatthias Ringwald
132*4930cef6SMatthias Ringwald            err *= 1 - rc ** 2
133*4930cef6SMatthias Ringwald
134*4930cef6SMatthias Ringwald        return (r[0] / err, a)
135*4930cef6SMatthias Ringwald
136*4930cef6SMatthias Ringwald    def lpc_weighting(self, pred_gain, a):
137*4930cef6SMatthias Ringwald
138*4930cef6SMatthias Ringwald        gamma = 1 - (1 - 0.85) * (2 - pred_gain) / (2 - 1.5)
139*4930cef6SMatthias Ringwald        return a * np.power(gamma, np.arange(len(a)))
140*4930cef6SMatthias Ringwald
141*4930cef6SMatthias Ringwald    def coeffs_reflexion(self, a):
142*4930cef6SMatthias Ringwald
143*4930cef6SMatthias Ringwald        rc = np.zeros(8)
144*4930cef6SMatthias Ringwald        b  = a.copy()
145*4930cef6SMatthias Ringwald
146*4930cef6SMatthias Ringwald        for k in range(8, 0, -1):
147*4930cef6SMatthias Ringwald            rc[k-1] = b[k]
148*4930cef6SMatthias Ringwald            e = 1 - rc[k-1] ** 2
149*4930cef6SMatthias Ringwald            b[1:k] = (b[1:k] - rc[k-1] * b[k-1:0:-1]) / e
150*4930cef6SMatthias Ringwald
151*4930cef6SMatthias Ringwald        return rc
152*4930cef6SMatthias Ringwald
153*4930cef6SMatthias Ringwald    def quantization(self, rc, lpc_weighting):
154*4930cef6SMatthias Ringwald
155*4930cef6SMatthias Ringwald        delta = np.pi / 17
156*4930cef6SMatthias Ringwald        rc_i = np.rint(np.arcsin(rc) / delta).astype(int) + 8
157*4930cef6SMatthias Ringwald        rc_q = np.sin(delta * (rc_i - 8))
158*4930cef6SMatthias Ringwald
159*4930cef6SMatthias Ringwald        rc_order = len(rc_i) - np.argmin(rc_i[::-1] == 8)
160*4930cef6SMatthias Ringwald
161*4930cef6SMatthias Ringwald        return (rc_order, rc_q, rc_i)
162*4930cef6SMatthias Ringwald
163*4930cef6SMatthias Ringwald    def filtering(self, st, x, rc_order, rc):
164*4930cef6SMatthias Ringwald
165*4930cef6SMatthias Ringwald        y = np.empty(len(x))
166*4930cef6SMatthias Ringwald
167*4930cef6SMatthias Ringwald        for i in range(len(x)):
168*4930cef6SMatthias Ringwald
169*4930cef6SMatthias Ringwald            xi = x[i]
170*4930cef6SMatthias Ringwald            s1 = xi
171*4930cef6SMatthias Ringwald
172*4930cef6SMatthias Ringwald            for k in range(rc_order):
173*4930cef6SMatthias Ringwald                s0 = st[k]
174*4930cef6SMatthias Ringwald                st[k] = s1
175*4930cef6SMatthias Ringwald
176*4930cef6SMatthias Ringwald                s1  = rc[k] * xi + s0
177*4930cef6SMatthias Ringwald                xi += rc[k] * s0
178*4930cef6SMatthias Ringwald
179*4930cef6SMatthias Ringwald            y[i] = xi
180*4930cef6SMatthias Ringwald
181*4930cef6SMatthias Ringwald        return y
182*4930cef6SMatthias Ringwald
183*4930cef6SMatthias Ringwald    def run(self, x, bw, nn_flag, nbytes):
184*4930cef6SMatthias Ringwald
185*4930cef6SMatthias Ringwald        fstate = np.zeros(8)
186*4930cef6SMatthias Ringwald        y = x.copy()
187*4930cef6SMatthias Ringwald
188*4930cef6SMatthias Ringwald        self.nfilters = len(Tns.SUB_LIM[self.dt][bw])
189*4930cef6SMatthias Ringwald        self.lpc_weighting = nbytes * 8 < 48 * T.DT_MS[self.dt]
190*4930cef6SMatthias Ringwald        self.rc_order = np.zeros(2, dtype=np.int)
191*4930cef6SMatthias Ringwald        self.rc = np.zeros((2, 8), dtype=np.int)
192*4930cef6SMatthias Ringwald
193*4930cef6SMatthias Ringwald        for f in range(self.nfilters):
194*4930cef6SMatthias Ringwald
195*4930cef6SMatthias Ringwald            (pred_gain, a) = self.compute_lpc_coeffs(bw, f, x)
196*4930cef6SMatthias Ringwald
197*4930cef6SMatthias Ringwald            tns_off = pred_gain <= 1.5 or nn_flag
198*4930cef6SMatthias Ringwald            if tns_off:
199*4930cef6SMatthias Ringwald                continue
200*4930cef6SMatthias Ringwald
201*4930cef6SMatthias Ringwald            if self.lpc_weighting and pred_gain < 2:
202*4930cef6SMatthias Ringwald                a = self.lpc_weighting(pred_gain, a)
203*4930cef6SMatthias Ringwald
204*4930cef6SMatthias Ringwald            rc = self.coeffs_reflexion(a)
205*4930cef6SMatthias Ringwald
206*4930cef6SMatthias Ringwald            (rc_order, rc_q, rc_i) = \
207*4930cef6SMatthias Ringwald                self.quantization(rc, self.lpc_weighting)
208*4930cef6SMatthias Ringwald
209*4930cef6SMatthias Ringwald            self.rc_order[f] = rc_order
210*4930cef6SMatthias Ringwald            self.rc[f] = rc_i
211*4930cef6SMatthias Ringwald
212*4930cef6SMatthias Ringwald            if rc_order > 0:
213*4930cef6SMatthias Ringwald                i0 = Tns.FREQ_LIM[self.dt][bw][f]
214*4930cef6SMatthias Ringwald                i1 = Tns.FREQ_LIM[self.dt][bw][f+1]
215*4930cef6SMatthias Ringwald
216*4930cef6SMatthias Ringwald                y[i0:i1] = self.filtering(
217*4930cef6SMatthias Ringwald                    fstate, x[i0:i1], rc_order, rc_q)
218*4930cef6SMatthias Ringwald
219*4930cef6SMatthias Ringwald        return y
220*4930cef6SMatthias Ringwald
221*4930cef6SMatthias Ringwald    def store(self, b):
222*4930cef6SMatthias Ringwald
223*4930cef6SMatthias Ringwald        for f in range(self.nfilters):
224*4930cef6SMatthias Ringwald            lpc_weighting = self.lpc_weighting[f]
225*4930cef6SMatthias Ringwald            rc_order = self.rc_order[f]
226*4930cef6SMatthias Ringwald            rc = self.rc[f]
227*4930cef6SMatthias Ringwald
228*4930cef6SMatthias Ringwald            b.write_bit(min(rc_order, 1))
229*4930cef6SMatthias Ringwald
230*4930cef6SMatthias Ringwald            if rc_order > 0:
231*4930cef6SMatthias Ringwald                b.ac_encode(
232*4930cef6SMatthias Ringwald                    T.TNS_ORDER_CUMFREQ[int(lpc_weighting)][rc_order-1],
233*4930cef6SMatthias Ringwald                    T.TNS_ORDER_FREQ[int(lpc_weighting)][rc_order-1]    )
234*4930cef6SMatthias Ringwald
235*4930cef6SMatthias Ringwald            for k in range(rc_order):
236*4930cef6SMatthias Ringwald                b.ac_encode(T.TNS_COEF_CUMFREQ[k][rc[k]],
237*4930cef6SMatthias Ringwald                            T.TNS_COEF_FREQ[k][rc[k]]    )
238*4930cef6SMatthias Ringwald
239*4930cef6SMatthias Ringwald
240*4930cef6SMatthias Ringwaldclass TnsSynthesis(Tns):
241*4930cef6SMatthias Ringwald
242*4930cef6SMatthias Ringwald    def filtering(self, st, x, rc_order, rc):
243*4930cef6SMatthias Ringwald
244*4930cef6SMatthias Ringwald        y = x.copy()
245*4930cef6SMatthias Ringwald
246*4930cef6SMatthias Ringwald        for i in range(len(x)):
247*4930cef6SMatthias Ringwald
248*4930cef6SMatthias Ringwald            xi = x[i] - rc[rc_order-1] * st[rc_order-1]
249*4930cef6SMatthias Ringwald            for k in range(rc_order-2, -1, -1):
250*4930cef6SMatthias Ringwald                xi -= rc[k] * st[k]
251*4930cef6SMatthias Ringwald                st[k+1] = xi * rc[k] + st[k];
252*4930cef6SMatthias Ringwald            st[0] = xi;
253*4930cef6SMatthias Ringwald
254*4930cef6SMatthias Ringwald            y[i] = xi
255*4930cef6SMatthias Ringwald
256*4930cef6SMatthias Ringwald        return y
257*4930cef6SMatthias Ringwald
258*4930cef6SMatthias Ringwald    def load(self, b, bw, nbytes):
259*4930cef6SMatthias Ringwald
260*4930cef6SMatthias Ringwald        self.nfilters = len(Tns.SUB_LIM[self.dt][bw])
261*4930cef6SMatthias Ringwald        self.lpc_weighting = nbytes * 8 < 48 * T.DT_MS[self.dt]
262*4930cef6SMatthias Ringwald        self.rc_order = np.zeros(2, dtype=np.int)
263*4930cef6SMatthias Ringwald        self.rc = 8 * np.ones((2, 8), dtype=np.int)
264*4930cef6SMatthias Ringwald
265*4930cef6SMatthias Ringwald        for f in range(self.nfilters):
266*4930cef6SMatthias Ringwald
267*4930cef6SMatthias Ringwald            if not b.read_bit():
268*4930cef6SMatthias Ringwald                continue
269*4930cef6SMatthias Ringwald
270*4930cef6SMatthias Ringwald            rc_order = 1 + b.ac_decode(
271*4930cef6SMatthias Ringwald                T.TNS_ORDER_CUMFREQ[int(self.lpc_weighting)],
272*4930cef6SMatthias Ringwald                T.TNS_ORDER_FREQ[int(self.lpc_weighting)])
273*4930cef6SMatthias Ringwald
274*4930cef6SMatthias Ringwald            self.rc_order[f] = rc_order
275*4930cef6SMatthias Ringwald
276*4930cef6SMatthias Ringwald            for k in range(rc_order):
277*4930cef6SMatthias Ringwald                rc = b.ac_decode(T.TNS_COEF_CUMFREQ[k], T.TNS_COEF_FREQ[k])
278*4930cef6SMatthias Ringwald                self.rc[f][k] = rc
279*4930cef6SMatthias Ringwald
280*4930cef6SMatthias Ringwald    def run(self, x, bw):
281*4930cef6SMatthias Ringwald
282*4930cef6SMatthias Ringwald        fstate = np.zeros(8)
283*4930cef6SMatthias Ringwald        y = x.copy()
284*4930cef6SMatthias Ringwald
285*4930cef6SMatthias Ringwald        for f in range(self.nfilters):
286*4930cef6SMatthias Ringwald
287*4930cef6SMatthias Ringwald            rc_order = self.rc_order[f]
288*4930cef6SMatthias Ringwald            rc = np.sin((np.pi / 17) * (self.rc[f] - 8))
289*4930cef6SMatthias Ringwald
290*4930cef6SMatthias Ringwald            if rc_order > 0:
291*4930cef6SMatthias Ringwald                i0 = Tns.FREQ_LIM[self.dt][bw][f]
292*4930cef6SMatthias Ringwald                i1 = Tns.FREQ_LIM[self.dt][bw][f+1]
293*4930cef6SMatthias Ringwald
294*4930cef6SMatthias Ringwald                y[i0:i1] = self.filtering(
295*4930cef6SMatthias Ringwald                    fstate, x[i0:i1], rc_order, rc)
296*4930cef6SMatthias Ringwald
297*4930cef6SMatthias Ringwald        return y
298*4930cef6SMatthias Ringwald
299*4930cef6SMatthias Ringwald
300*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
301*4930cef6SMatthias Ringwald
302*4930cef6SMatthias Ringwalddef check_analysis(rng, dt, bw):
303*4930cef6SMatthias Ringwald
304*4930cef6SMatthias Ringwald    ok = True
305*4930cef6SMatthias Ringwald
306*4930cef6SMatthias Ringwald    analysis = TnsAnalysis(dt)
307*4930cef6SMatthias Ringwald    nbytes_lim = int((48 * T.DT_MS[dt]) // 8)
308*4930cef6SMatthias Ringwald
309*4930cef6SMatthias Ringwald    for i in range(10):
310*4930cef6SMatthias Ringwald        x = rng.random(T.NE[dt][bw]) * 1e2
311*4930cef6SMatthias Ringwald        x = pow(x, .5 + i/5)
312*4930cef6SMatthias Ringwald
313*4930cef6SMatthias Ringwald        for nn_flag in (True, False):
314*4930cef6SMatthias Ringwald            for nbytes in (nbytes_lim, nbytes_lim + 1):
315*4930cef6SMatthias Ringwald
316*4930cef6SMatthias Ringwald                y = analysis.run(x, bw, nn_flag, nbytes)
317*4930cef6SMatthias Ringwald                (y_c, data_c) = lc3.tns_analyze(dt, bw, nn_flag, nbytes, x)
318*4930cef6SMatthias Ringwald
319*4930cef6SMatthias Ringwald                ok = ok and data_c['nfilters'] == analysis.nfilters
320*4930cef6SMatthias Ringwald                ok = ok and data_c['lpc_weighting'] == analysis.lpc_weighting
321*4930cef6SMatthias Ringwald                for f in range(analysis.nfilters):
322*4930cef6SMatthias Ringwald                    rc_order = analysis.rc_order[f]
323*4930cef6SMatthias Ringwald                    rc_order_c = data_c['rc_order'][f]
324*4930cef6SMatthias Ringwald                    rc_c = 8 + data_c['rc'][f]
325*4930cef6SMatthias Ringwald                    ok = ok and rc_order_c == rc_order
326*4930cef6SMatthias Ringwald                    ok = ok and not np.any((rc_c - analysis.rc[f])[:rc_order])
327*4930cef6SMatthias Ringwald
328*4930cef6SMatthias Ringwald                ok = ok and lc3.tns_get_nbits(data_c) == analysis.get_nbits()
329*4930cef6SMatthias Ringwald                ok = ok and np.amax(np.abs(y_c - y)) < 1e-2
330*4930cef6SMatthias Ringwald
331*4930cef6SMatthias Ringwald    return ok
332*4930cef6SMatthias Ringwald
333*4930cef6SMatthias Ringwalddef check_synthesis(rng, dt, bw):
334*4930cef6SMatthias Ringwald
335*4930cef6SMatthias Ringwald    ok = True
336*4930cef6SMatthias Ringwald    synthesis = TnsSynthesis(dt)
337*4930cef6SMatthias Ringwald
338*4930cef6SMatthias Ringwald    for i in range(100):
339*4930cef6SMatthias Ringwald
340*4930cef6SMatthias Ringwald        x = rng.random(T.NE[dt][bw]) * 1e2
341*4930cef6SMatthias Ringwald
342*4930cef6SMatthias Ringwald        synthesis.nfilters = 1 + int(bw >= T.SRATE_32K)
343*4930cef6SMatthias Ringwald        synthesis.rc_order = rng.integers(0, 9, 2)
344*4930cef6SMatthias Ringwald        synthesis.rc = rng.integers(0, 17, 16).reshape(2, 8)
345*4930cef6SMatthias Ringwald
346*4930cef6SMatthias Ringwald        y = synthesis.run(x, bw)
347*4930cef6SMatthias Ringwald        y_c = lc3.tns_synthesize(dt, bw, synthesis.get_data(), x)
348*4930cef6SMatthias Ringwald
349*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(y_c - y) < 1e-6)
350*4930cef6SMatthias Ringwald
351*4930cef6SMatthias Ringwald    return ok
352*4930cef6SMatthias Ringwald
353*4930cef6SMatthias Ringwalddef check_analysis_appendix_c(dt):
354*4930cef6SMatthias Ringwald
355*4930cef6SMatthias Ringwald    sr = T.SRATE_16K
356*4930cef6SMatthias Ringwald    ok = True
357*4930cef6SMatthias Ringwald
358*4930cef6SMatthias Ringwald    fs = Tns.FREQ_LIM[dt][sr][0]
359*4930cef6SMatthias Ringwald    fe = Tns.FREQ_LIM[dt][sr][1]
360*4930cef6SMatthias Ringwald    st = np.zeros(8)
361*4930cef6SMatthias Ringwald
362*4930cef6SMatthias Ringwald    for i in range(len(C.X_S[dt])):
363*4930cef6SMatthias Ringwald
364*4930cef6SMatthias Ringwald        (_, a) = lc3.tns_compute_lpc_coeffs(dt, sr, C.X_S[dt][i])
365*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(a[0] - C.TNS_LEV_A[dt][i])) < 1e-5
366*4930cef6SMatthias Ringwald
367*4930cef6SMatthias Ringwald        rc = lc3.tns_lpc_reflection(a[0])
368*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(rc - C.TNS_LEV_RC[dt][i])) < 1e-5
369*4930cef6SMatthias Ringwald
370*4930cef6SMatthias Ringwald        (rc_order, rc_i) = lc3.tns_quantize_rc(C.TNS_LEV_RC[dt][i])
371*4930cef6SMatthias Ringwald        ok = ok and rc_order == C.RC_ORDER[dt][i][0]
372*4930cef6SMatthias Ringwald        ok = ok and np.any((rc_i + 8) - C.RC_I_1[dt][i] == 0)
373*4930cef6SMatthias Ringwald
374*4930cef6SMatthias Ringwald        rc_q = lc3.tns_unquantize_rc(rc_i, rc_order)
375*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(rc_q - C.RC_Q_1[dt][i])) < 1e-6
376*4930cef6SMatthias Ringwald
377*4930cef6SMatthias Ringwald        (x, side) = lc3.tns_analyze(dt, sr, False, C.NBYTES[dt], C.X_S[dt][i])
378*4930cef6SMatthias Ringwald        ok = ok and side['nfilters'] == 1
379*4930cef6SMatthias Ringwald        ok = ok and side['rc_order'][0] == C.RC_ORDER[dt][i][0]
380*4930cef6SMatthias Ringwald        ok = ok and not np.any((side['rc'][0] + 8) - C.RC_I_1[dt][i])
381*4930cef6SMatthias Ringwald        ok = ok and lc3.tns_get_nbits(side) == C.NBITS_TNS[dt][i]
382*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(x - C.X_F[dt][i])) < 1e-3
383*4930cef6SMatthias Ringwald
384*4930cef6SMatthias Ringwald    return ok
385*4930cef6SMatthias Ringwald
386*4930cef6SMatthias Ringwalddef check_synthesis_appendix_c(dt):
387*4930cef6SMatthias Ringwald
388*4930cef6SMatthias Ringwald    sr = T.SRATE_16K
389*4930cef6SMatthias Ringwald    ok = True
390*4930cef6SMatthias Ringwald
391*4930cef6SMatthias Ringwald    for i in range(len(C.X_HAT_Q[dt])):
392*4930cef6SMatthias Ringwald
393*4930cef6SMatthias Ringwald        side = {
394*4930cef6SMatthias Ringwald            'nfilters' : 1,
395*4930cef6SMatthias Ringwald            'lpc_weighting' : C.NBYTES[dt] * 8 < 48 * T.DT_MS[dt],
396*4930cef6SMatthias Ringwald            'rc_order': C.RC_ORDER[dt][i],
397*4930cef6SMatthias Ringwald            'rc': [ C.RC_I_1[dt][i] - 8, C.RC_I_2[dt][i] - 8 ]
398*4930cef6SMatthias Ringwald        }
399*4930cef6SMatthias Ringwald
400*4930cef6SMatthias Ringwald        g_int = C.GG_IND_ADJ[dt][i] + C.GG_OFF[dt][i]
401*4930cef6SMatthias Ringwald        x = C.X_HAT_Q[dt][i] * (10 ** (g_int / 28))
402*4930cef6SMatthias Ringwald
403*4930cef6SMatthias Ringwald        x = lc3.tns_synthesize(dt, sr, side, x)
404*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(x - C.X_HAT_TNS[dt][i])) < 1e-3
405*4930cef6SMatthias Ringwald
406*4930cef6SMatthias Ringwald    if dt != T.DT_10M:
407*4930cef6SMatthias Ringwald        return ok
408*4930cef6SMatthias Ringwald
409*4930cef6SMatthias Ringwald    sr = T.SRATE_48K
410*4930cef6SMatthias Ringwald
411*4930cef6SMatthias Ringwald    side = {
412*4930cef6SMatthias Ringwald        'nfilters' : 2,
413*4930cef6SMatthias Ringwald        'lpc_weighting' : False,
414*4930cef6SMatthias Ringwald        'rc_order': C.RC_ORDER_48K_10M,
415*4930cef6SMatthias Ringwald        'rc': [ C.RC_I_1_48K_10M - 8, C.RC_I_2_48K_10M - 8 ]
416*4930cef6SMatthias Ringwald    }
417*4930cef6SMatthias Ringwald
418*4930cef6SMatthias Ringwald    x = C.X_HAT_F_48K_10M
419*4930cef6SMatthias Ringwald    x = lc3.tns_synthesize(dt, sr, side, x)
420*4930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(x - C.X_HAT_TNS_48K_10M)) < 1e-3
421*4930cef6SMatthias Ringwald
422*4930cef6SMatthias Ringwald    return ok
423*4930cef6SMatthias Ringwald
424*4930cef6SMatthias Ringwalddef check():
425*4930cef6SMatthias Ringwald
426*4930cef6SMatthias Ringwald    rng = np.random.default_rng(1234)
427*4930cef6SMatthias Ringwald    ok = True
428*4930cef6SMatthias Ringwald
429*4930cef6SMatthias Ringwald    for dt in range(T.NUM_DT):
430*4930cef6SMatthias Ringwald        for sr in range(T.NUM_SRATE):
431*4930cef6SMatthias Ringwald            ok = ok and check_analysis(rng, dt, sr)
432*4930cef6SMatthias Ringwald            ok = ok and check_synthesis(rng, dt, sr)
433*4930cef6SMatthias Ringwald
434*4930cef6SMatthias Ringwald    for dt in range(T.NUM_DT):
435*4930cef6SMatthias Ringwald        ok = ok and check_analysis_appendix_c(dt)
436*4930cef6SMatthias Ringwald        ok = ok and check_synthesis_appendix_c(dt)
437*4930cef6SMatthias Ringwald
438*4930cef6SMatthias Ringwald    return ok
439*4930cef6SMatthias Ringwald
440*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
441