xref: /btstack/3rd-party/lc3-google/test/tns.py (revision 6897da5c53aac5b1f90f41b5b15d0bd43d61dfff)
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 Ringwald
194c4eb519SMatthias Ringwaldimport lc3
204930cef6SMatthias Ringwaldimport tables as T, appendix_c as C
214930cef6SMatthias Ringwald
224930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
234930cef6SMatthias Ringwald
244930cef6SMatthias Ringwaldclass Tns:
25*6897da5cSDirk Helbig    SUB_LIM_2M5_NB   = [ [   3,  10,  20  ] ]
26*6897da5cSDirk Helbig    SUB_LIM_2M5_WB   = [ [   3,  20,  40  ] ]
27*6897da5cSDirk Helbig    SUB_LIM_2M5_SSWB = [ [   3,  30,  60  ] ]
28*6897da5cSDirk Helbig    SUB_LIM_2M5_SWB  = [ [   3,  40,  80  ] ]
29*6897da5cSDirk Helbig    SUB_LIM_2M5_FB   = [ [   3,  51, 100  ] ]
304930cef6SMatthias Ringwald
31*6897da5cSDirk Helbig    SUB_LIM_2M5 = [
32*6897da5cSDirk Helbig        SUB_LIM_2M5_NB , SUB_LIM_2M5_WB, SUB_LIM_2M5_SSWB,
33*6897da5cSDirk Helbig        SUB_LIM_2M5_SWB, SUB_LIM_2M5_FB, SUB_LIM_2M5_FB, SUB_LIM_2M5_FB ]
344930cef6SMatthias Ringwald
35*6897da5cSDirk Helbig    SUB_LIM_5M_NB    = [ [  6,  23,  40 ] ]
36*6897da5cSDirk Helbig    SUB_LIM_5M_WB    = [ [  6,  43,  80 ] ]
37*6897da5cSDirk Helbig    SUB_LIM_5M_SSWB  = [ [  6,  63, 120 ] ]
38*6897da5cSDirk Helbig    SUB_LIM_5M_SWB   = [ [  6,  43,  80 ], [  80, 120, 160 ] ]
39*6897da5cSDirk Helbig    SUB_LIM_5M_FB    = [ [  6,  53, 100 ], [ 100, 150, 200 ] ]
40*6897da5cSDirk Helbig
41*6897da5cSDirk Helbig    SUB_LIM_5M = [
42*6897da5cSDirk Helbig        SUB_LIM_5M_NB , SUB_LIM_5M_WB, SUB_LIM_5M_SSWB,
43*6897da5cSDirk Helbig        SUB_LIM_5M_SWB, SUB_LIM_5M_FB, SUB_LIM_5M_FB, SUB_LIM_5M_FB ]
444930cef6SMatthias Ringwald
454930cef6SMatthias Ringwald    SUB_LIM_7M5_NB   = [ [   9,  26,  43,  60 ] ]
464930cef6SMatthias Ringwald    SUB_LIM_7M5_WB   = [ [   9,  46,  83, 120 ] ]
474930cef6SMatthias Ringwald    SUB_LIM_7M5_SSWB = [ [   9,  66, 123, 180 ] ]
484930cef6SMatthias Ringwald    SUB_LIM_7M5_SWB  = [ [   9,  46,  82, 120 ], [ 120, 159, 200, 240 ] ]
494930cef6SMatthias Ringwald    SUB_LIM_7M5_FB   = [ [   9,  56, 103, 150 ], [ 150, 200, 250, 300 ] ]
504930cef6SMatthias Ringwald
51*6897da5cSDirk Helbig    SUB_LIM_7M5 = [
52*6897da5cSDirk Helbig        SUB_LIM_7M5_NB , SUB_LIM_7M5_WB, SUB_LIM_7M5_SSWB,
53*6897da5cSDirk Helbig        SUB_LIM_7M5_SWB, SUB_LIM_7M5_FB, None, None ]
544930cef6SMatthias Ringwald
55*6897da5cSDirk Helbig    SUB_LIM_10M_NB   = [ [  12,  34,  57,  80 ] ]
56*6897da5cSDirk Helbig    SUB_LIM_10M_WB   = [ [  12,  61, 110, 160 ] ]
57*6897da5cSDirk Helbig    SUB_LIM_10M_SSWB = [ [  12,  88, 164, 240 ] ]
58*6897da5cSDirk Helbig    SUB_LIM_10M_SWB  = [ [  12,  61, 110, 160 ], [ 160, 213, 266, 320 ] ]
59*6897da5cSDirk Helbig    SUB_LIM_10M_FB   = [ [  12,  74, 137, 200 ], [ 200, 266, 333, 400 ] ]
604930cef6SMatthias Ringwald
61*6897da5cSDirk Helbig    SUB_LIM_10M = [
62*6897da5cSDirk Helbig        SUB_LIM_10M_NB , SUB_LIM_10M_WB, SUB_LIM_10M_SSWB,
63*6897da5cSDirk Helbig        SUB_LIM_10M_SWB, SUB_LIM_10M_FB, SUB_LIM_10M_FB, SUB_LIM_10M_FB ]
644930cef6SMatthias Ringwald
65*6897da5cSDirk Helbig    SUB_LIM = [ SUB_LIM_2M5, SUB_LIM_5M, SUB_LIM_7M5, SUB_LIM_10M ]
66*6897da5cSDirk Helbig
67*6897da5cSDirk Helbig
68*6897da5cSDirk Helbig    FREQ_LIM_2M5_NB   = [   3,  20 ]
69*6897da5cSDirk Helbig    FREQ_LIM_2M5_WB   = [   3,  40 ]
70*6897da5cSDirk Helbig    FREQ_LIM_2M5_SSWB = [   3,  60 ]
71*6897da5cSDirk Helbig    FREQ_LIM_2M5_SWB  = [   3,  80 ]
72*6897da5cSDirk Helbig    FREQ_LIM_2M5_FB   = [   3, 100 ]
73*6897da5cSDirk Helbig
74*6897da5cSDirk Helbig    FREQ_LIM_2M5 = [
75*6897da5cSDirk Helbig        FREQ_LIM_2M5_NB , FREQ_LIM_2M5_WB, FREQ_LIM_2M5_SSWB,
76*6897da5cSDirk Helbig        FREQ_LIM_2M5_SWB, FREQ_LIM_2M5_FB, FREQ_LIM_2M5_FB, FREQ_LIM_2M5_FB ]
77*6897da5cSDirk Helbig
78*6897da5cSDirk Helbig    FREQ_LIM_5M_NB    = [   6,  40 ]
79*6897da5cSDirk Helbig    FREQ_LIM_5M_WB    = [   6,  80 ]
80*6897da5cSDirk Helbig    FREQ_LIM_5M_SSWB  = [   6, 120 ]
81*6897da5cSDirk Helbig    FREQ_LIM_5M_SWB   = [   6,  80, 160 ]
82*6897da5cSDirk Helbig    FREQ_LIM_5M_FB    = [   6, 100, 200 ]
83*6897da5cSDirk Helbig
84*6897da5cSDirk Helbig    FREQ_LIM_5M = [
85*6897da5cSDirk Helbig        FREQ_LIM_5M_NB , FREQ_LIM_5M_WB, FREQ_LIM_5M_SSWB,
86*6897da5cSDirk Helbig        FREQ_LIM_5M_SWB, FREQ_LIM_5M_FB, FREQ_LIM_5M_FB, FREQ_LIM_5M_FB ]
874930cef6SMatthias Ringwald
884930cef6SMatthias Ringwald    FREQ_LIM_7M5_NB   = [   9,  60 ]
894930cef6SMatthias Ringwald    FREQ_LIM_7M5_WB   = [   9, 120 ]
904930cef6SMatthias Ringwald    FREQ_LIM_7M5_SSWB = [   9, 180 ]
914930cef6SMatthias Ringwald    FREQ_LIM_7M5_SWB  = [   9, 120, 240 ]
924930cef6SMatthias Ringwald    FREQ_LIM_7M5_FB   = [   9, 150, 300 ]
934930cef6SMatthias Ringwald
94*6897da5cSDirk Helbig    FREQ_LIM_7M5 = [
95*6897da5cSDirk Helbig        FREQ_LIM_7M5_NB , FREQ_LIM_7M5_WB, FREQ_LIM_7M5_SSWB,
96*6897da5cSDirk Helbig        FREQ_LIM_7M5_SWB, FREQ_LIM_7M5_FB, None, None ]
974930cef6SMatthias Ringwald
98*6897da5cSDirk Helbig    FREQ_LIM_10M_NB   = [  12,  80 ]
99*6897da5cSDirk Helbig    FREQ_LIM_10M_WB   = [  12, 160 ]
100*6897da5cSDirk Helbig    FREQ_LIM_10M_SSWB = [  12, 240 ]
101*6897da5cSDirk Helbig    FREQ_LIM_10M_SWB  = [  12, 160, 320 ]
102*6897da5cSDirk Helbig    FREQ_LIM_10M_FB   = [  12, 200, 400 ]
103*6897da5cSDirk Helbig
104*6897da5cSDirk Helbig    FREQ_LIM_10M = [
105*6897da5cSDirk Helbig        FREQ_LIM_10M_NB , FREQ_LIM_10M_WB, FREQ_LIM_10M_SSWB,
106*6897da5cSDirk Helbig        FREQ_LIM_10M_SWB, FREQ_LIM_10M_FB, FREQ_LIM_10M_FB, FREQ_LIM_10M_FB ]
107*6897da5cSDirk Helbig
108*6897da5cSDirk Helbig    FREQ_LIM = [ FREQ_LIM_2M5, FREQ_LIM_5M, FREQ_LIM_7M5, FREQ_LIM_10M ]
109*6897da5cSDirk Helbig
1104930cef6SMatthias Ringwald
1114930cef6SMatthias Ringwald    def __init__(self, dt):
1124930cef6SMatthias Ringwald
1134930cef6SMatthias Ringwald        self.dt = dt
1144930cef6SMatthias Ringwald
1154930cef6SMatthias Ringwald        (self.nfilters, self.lpc_weighting, self.rc_order, self.rc) = \
1164c4eb519SMatthias Ringwald            (0, False, np.array([ 0, 0 ]), np.array([ 0, 0 ]))
1174930cef6SMatthias Ringwald
1184930cef6SMatthias Ringwald    def get_data(self):
1194930cef6SMatthias Ringwald
120*6897da5cSDirk Helbig        rc = np.append(self.rc - 8, np.zeros((2, 8 - len(self.rc[0]))), axis=1)
121*6897da5cSDirk Helbig
1224930cef6SMatthias Ringwald        return { 'nfilters' : self.nfilters,
1234930cef6SMatthias Ringwald                 'lpc_weighting' : self.lpc_weighting,
124*6897da5cSDirk Helbig                 'rc_order' : self.rc_order, 'rc' : rc }
1254930cef6SMatthias Ringwald
1264930cef6SMatthias Ringwald    def get_nbits(self):
1274930cef6SMatthias Ringwald
1284930cef6SMatthias Ringwald        lpc_weighting = self.lpc_weighting
1294930cef6SMatthias Ringwald        nbits = 0
1304930cef6SMatthias Ringwald
1314930cef6SMatthias Ringwald        for f in range(self.nfilters):
1324930cef6SMatthias Ringwald            rc_order = self.rc_order[f]
1334930cef6SMatthias Ringwald            rc = self.rc[f]
1344930cef6SMatthias Ringwald
1354930cef6SMatthias Ringwald            nbits_order = T.TNS_ORDER_BITS[int(lpc_weighting)][rc_order]
1364930cef6SMatthias Ringwald            nbits_coef = sum([ T.TNS_COEF_BITS[k][rc[k]]
1374930cef6SMatthias Ringwald                                  for k in range(rc_order) ])
1384930cef6SMatthias Ringwald
1394930cef6SMatthias Ringwald            nbits += ((2048 + nbits_order + nbits_coef) + 2047) >> 11
1404930cef6SMatthias Ringwald
1414930cef6SMatthias Ringwald        return nbits
1424930cef6SMatthias Ringwald
1434930cef6SMatthias Ringwald
1444930cef6SMatthias Ringwaldclass TnsAnalysis(Tns):
1454930cef6SMatthias Ringwald
1464930cef6SMatthias Ringwald    def __init__(self, dt):
1474930cef6SMatthias Ringwald
1484930cef6SMatthias Ringwald        super().__init__(dt)
1494930cef6SMatthias Ringwald
1504930cef6SMatthias Ringwald    def compute_lpc_coeffs(self, bw, f, x):
1514930cef6SMatthias Ringwald
1524930cef6SMatthias Ringwald        ### Normalized autocorrelation function
1534930cef6SMatthias Ringwald
1544930cef6SMatthias Ringwald        S = Tns.SUB_LIM[self.dt][bw][f]
155*6897da5cSDirk Helbig        maxorder = [ 4, 8 ][self.dt > T.DT_5M]
1564930cef6SMatthias Ringwald
157*6897da5cSDirk Helbig        r = np.append([ 3 ], np.zeros(maxorder))
158*6897da5cSDirk Helbig        e = [ sum(x[S[s]:S[s+1]] ** 2) for s in range(len(S)-1) ]
1594930cef6SMatthias Ringwald
1604930cef6SMatthias Ringwald        for k in range(len(r) if sum(e) > 0 else 0):
1614930cef6SMatthias Ringwald            c = [ np.dot(x[S[s]:S[s+1]-k], x[S[s]+k:S[s+1]])
162*6897da5cSDirk Helbig                      for s in range(len(S)-1) ]
1634930cef6SMatthias Ringwald
1644930cef6SMatthias Ringwald            r[k] = np.sum( np.array(c) / np.array(e) )
1654930cef6SMatthias Ringwald
166*6897da5cSDirk Helbig        r *= np.exp(-0.5 * (0.02 * np.pi * np.arange(1+maxorder)) ** 2)
1674930cef6SMatthias Ringwald
1684930cef6SMatthias Ringwald        ### Levinson-Durbin recursion
1694930cef6SMatthias Ringwald
1704930cef6SMatthias Ringwald        err = r[0]
1714930cef6SMatthias Ringwald        a = np.ones(len(r))
1724930cef6SMatthias Ringwald
1734930cef6SMatthias Ringwald        for k in range(1, len(a)):
1744930cef6SMatthias Ringwald
1754930cef6SMatthias Ringwald            rc = -sum(a[:k] * r[k:0:-1]) / err
1764930cef6SMatthias Ringwald
1774930cef6SMatthias Ringwald            a[1:k] += rc * a[k-1:0:-1]
1784930cef6SMatthias Ringwald            a[k] = rc
1794930cef6SMatthias Ringwald
1804930cef6SMatthias Ringwald            err *= 1 - rc ** 2
1814930cef6SMatthias Ringwald
1824930cef6SMatthias Ringwald        return (r[0] / err, a)
1834930cef6SMatthias Ringwald
1844c4eb519SMatthias Ringwald    def lpc_weight(self, pred_gain, a):
1854930cef6SMatthias Ringwald
1864930cef6SMatthias Ringwald        gamma = 1 - (1 - 0.85) * (2 - pred_gain) / (2 - 1.5)
1874930cef6SMatthias Ringwald        return a * np.power(gamma, np.arange(len(a)))
1884930cef6SMatthias Ringwald
1894930cef6SMatthias Ringwald    def coeffs_reflexion(self, a):
1904930cef6SMatthias Ringwald
191*6897da5cSDirk Helbig        rc = np.zeros(len(a)-1)
1924930cef6SMatthias Ringwald        b  = a.copy()
1934930cef6SMatthias Ringwald
194*6897da5cSDirk Helbig        for k in range(len(rc), 0, -1):
1954930cef6SMatthias Ringwald            rc[k-1] = b[k]
1964930cef6SMatthias Ringwald            e = 1 - rc[k-1] ** 2
1974930cef6SMatthias Ringwald            b[1:k] = (b[1:k] - rc[k-1] * b[k-1:0:-1]) / e
1984930cef6SMatthias Ringwald
1994930cef6SMatthias Ringwald        return rc
2004930cef6SMatthias Ringwald
2014930cef6SMatthias Ringwald    def quantization(self, rc, lpc_weighting):
2024930cef6SMatthias Ringwald
2034930cef6SMatthias Ringwald        delta = np.pi / 17
2044930cef6SMatthias Ringwald        rc_i = np.rint(np.arcsin(rc) / delta).astype(int) + 8
2054930cef6SMatthias Ringwald        rc_q = np.sin(delta * (rc_i - 8))
206*6897da5cSDirk Helbig        rc_q = np.rint(rc_q * 2**15) / 2**15
2074930cef6SMatthias Ringwald
2084930cef6SMatthias Ringwald        rc_order = len(rc_i) - np.argmin(rc_i[::-1] == 8)
2094930cef6SMatthias Ringwald
2104930cef6SMatthias Ringwald        return (rc_order, rc_q, rc_i)
2114930cef6SMatthias Ringwald
2124930cef6SMatthias Ringwald    def filtering(self, st, x, rc_order, rc):
2134930cef6SMatthias Ringwald
2144930cef6SMatthias Ringwald        y = np.empty(len(x))
2154930cef6SMatthias Ringwald
2164930cef6SMatthias Ringwald        for i in range(len(x)):
2174930cef6SMatthias Ringwald
2184930cef6SMatthias Ringwald            xi = x[i]
2194930cef6SMatthias Ringwald            s1 = xi
2204930cef6SMatthias Ringwald
2214930cef6SMatthias Ringwald            for k in range(rc_order):
2224930cef6SMatthias Ringwald                s0 = st[k]
2234930cef6SMatthias Ringwald                st[k] = s1
2244930cef6SMatthias Ringwald
2254930cef6SMatthias Ringwald                s1  = rc[k] * xi + s0
2264930cef6SMatthias Ringwald                xi += rc[k] * s0
2274930cef6SMatthias Ringwald
2284930cef6SMatthias Ringwald            y[i] = xi
2294930cef6SMatthias Ringwald
2304930cef6SMatthias Ringwald        return y
2314930cef6SMatthias Ringwald
2324930cef6SMatthias Ringwald    def run(self, x, bw, nn_flag, nbytes):
2334930cef6SMatthias Ringwald
2344930cef6SMatthias Ringwald        fstate = np.zeros(8)
2354930cef6SMatthias Ringwald        y = x.copy()
2364930cef6SMatthias Ringwald
2374930cef6SMatthias Ringwald        self.nfilters = len(Tns.SUB_LIM[self.dt][bw])
238*6897da5cSDirk Helbig        maxorder = [ 4, 8 ][self.dt > T.DT_5M]
239*6897da5cSDirk Helbig
240*6897da5cSDirk Helbig        self.lpc_weighting = nbytes < 120 * (1 + self.dt) / 8
241*6897da5cSDirk Helbig
242*6897da5cSDirk Helbig        self.rc_order = np.zeros(2, dtype=np.intc)
243*6897da5cSDirk Helbig        self.rc = np.zeros((2, maxorder), dtype=np.intc)
2444930cef6SMatthias Ringwald
2454930cef6SMatthias Ringwald        for f in range(self.nfilters):
2464930cef6SMatthias Ringwald
2474930cef6SMatthias Ringwald            (pred_gain, a) = self.compute_lpc_coeffs(bw, f, x)
2484930cef6SMatthias Ringwald
2494930cef6SMatthias Ringwald            tns_off = pred_gain <= 1.5 or nn_flag
2504930cef6SMatthias Ringwald            if tns_off:
2514930cef6SMatthias Ringwald                continue
2524930cef6SMatthias Ringwald
2534930cef6SMatthias Ringwald            if self.lpc_weighting and pred_gain < 2:
2544c4eb519SMatthias Ringwald                a = self.lpc_weight(pred_gain, a)
2554930cef6SMatthias Ringwald
2564930cef6SMatthias Ringwald            rc = self.coeffs_reflexion(a)
2574930cef6SMatthias Ringwald
2584930cef6SMatthias Ringwald            (rc_order, rc_q, rc_i) = \
2594930cef6SMatthias Ringwald                self.quantization(rc, self.lpc_weighting)
2604930cef6SMatthias Ringwald
2614930cef6SMatthias Ringwald            self.rc_order[f] = rc_order
2624930cef6SMatthias Ringwald            self.rc[f] = rc_i
2634930cef6SMatthias Ringwald
2644930cef6SMatthias Ringwald            if rc_order > 0:
2654930cef6SMatthias Ringwald                i0 = Tns.FREQ_LIM[self.dt][bw][f]
2664930cef6SMatthias Ringwald                i1 = Tns.FREQ_LIM[self.dt][bw][f+1]
2674930cef6SMatthias Ringwald
2684930cef6SMatthias Ringwald                y[i0:i1] = self.filtering(
2694930cef6SMatthias Ringwald                    fstate, x[i0:i1], rc_order, rc_q)
2704930cef6SMatthias Ringwald
2714930cef6SMatthias Ringwald        return y
2724930cef6SMatthias Ringwald
2734930cef6SMatthias Ringwald    def store(self, b):
2744930cef6SMatthias Ringwald
2754930cef6SMatthias Ringwald        for f in range(self.nfilters):
2764c4eb519SMatthias Ringwald            lpc_weighting = self.lpc_weighting
2774930cef6SMatthias Ringwald            rc_order = self.rc_order[f]
2784930cef6SMatthias Ringwald            rc = self.rc[f]
2794930cef6SMatthias Ringwald
2804930cef6SMatthias Ringwald            b.write_bit(min(rc_order, 1))
2814930cef6SMatthias Ringwald
2824930cef6SMatthias Ringwald            if rc_order > 0:
2834930cef6SMatthias Ringwald                b.ac_encode(
2844930cef6SMatthias Ringwald                    T.TNS_ORDER_CUMFREQ[int(lpc_weighting)][rc_order-1],
2854930cef6SMatthias Ringwald                    T.TNS_ORDER_FREQ[int(lpc_weighting)][rc_order-1]    )
2864930cef6SMatthias Ringwald
2874930cef6SMatthias Ringwald            for k in range(rc_order):
2884930cef6SMatthias Ringwald                b.ac_encode(T.TNS_COEF_CUMFREQ[k][rc[k]],
2894930cef6SMatthias Ringwald                            T.TNS_COEF_FREQ[k][rc[k]]    )
2904930cef6SMatthias Ringwald
2914930cef6SMatthias Ringwald
2924930cef6SMatthias Ringwaldclass TnsSynthesis(Tns):
2934930cef6SMatthias Ringwald
2944930cef6SMatthias Ringwald    def filtering(self, st, x, rc_order, rc):
2954930cef6SMatthias Ringwald
2964930cef6SMatthias Ringwald        y = x.copy()
2974930cef6SMatthias Ringwald
2984930cef6SMatthias Ringwald        for i in range(len(x)):
2994930cef6SMatthias Ringwald
3004930cef6SMatthias Ringwald            xi = x[i] - rc[rc_order-1] * st[rc_order-1]
3014930cef6SMatthias Ringwald            for k in range(rc_order-2, -1, -1):
3024930cef6SMatthias Ringwald                xi -= rc[k] * st[k]
3034930cef6SMatthias Ringwald                st[k+1] = xi * rc[k] + st[k];
3044930cef6SMatthias Ringwald            st[0] = xi;
3054930cef6SMatthias Ringwald
3064930cef6SMatthias Ringwald            y[i] = xi
3074930cef6SMatthias Ringwald
3084930cef6SMatthias Ringwald        return y
3094930cef6SMatthias Ringwald
3104930cef6SMatthias Ringwald    def load(self, b, bw, nbytes):
3114930cef6SMatthias Ringwald
3124930cef6SMatthias Ringwald        self.nfilters = len(Tns.SUB_LIM[self.dt][bw])
313*6897da5cSDirk Helbig        self.lpc_weighting = nbytes < 120 * (1 + self.dt) / 8
314*6897da5cSDirk Helbig        self.rc_order = np.zeros(2, dtype=np.intc)
315*6897da5cSDirk Helbig        self.rc = 8 * np.ones((2, 8), dtype=np.intc)
3164930cef6SMatthias Ringwald
3174930cef6SMatthias Ringwald        for f in range(self.nfilters):
3184930cef6SMatthias Ringwald
3194930cef6SMatthias Ringwald            if not b.read_bit():
3204930cef6SMatthias Ringwald                continue
3214930cef6SMatthias Ringwald
3224930cef6SMatthias Ringwald            rc_order = 1 + b.ac_decode(
3234930cef6SMatthias Ringwald                T.TNS_ORDER_CUMFREQ[int(self.lpc_weighting)],
3244930cef6SMatthias Ringwald                T.TNS_ORDER_FREQ[int(self.lpc_weighting)])
3254930cef6SMatthias Ringwald
3264930cef6SMatthias Ringwald            self.rc_order[f] = rc_order
3274930cef6SMatthias Ringwald
3284930cef6SMatthias Ringwald            for k in range(rc_order):
3294930cef6SMatthias Ringwald                rc = b.ac_decode(T.TNS_COEF_CUMFREQ[k], T.TNS_COEF_FREQ[k])
3304930cef6SMatthias Ringwald                self.rc[f][k] = rc
3314930cef6SMatthias Ringwald
3324930cef6SMatthias Ringwald    def run(self, x, bw):
3334930cef6SMatthias Ringwald
3344930cef6SMatthias Ringwald        fstate = np.zeros(8)
3354930cef6SMatthias Ringwald        y = x.copy()
3364930cef6SMatthias Ringwald
3374930cef6SMatthias Ringwald        for f in range(self.nfilters):
3384930cef6SMatthias Ringwald
3394930cef6SMatthias Ringwald            rc_order = self.rc_order[f]
3404930cef6SMatthias Ringwald            rc = np.sin((np.pi / 17) * (self.rc[f] - 8))
341*6897da5cSDirk Helbig            rc = np.rint(rc * 2**15) / 2**15
3424930cef6SMatthias Ringwald
3434930cef6SMatthias Ringwald            if rc_order > 0:
3444930cef6SMatthias Ringwald                i0 = Tns.FREQ_LIM[self.dt][bw][f]
3454930cef6SMatthias Ringwald                i1 = Tns.FREQ_LIM[self.dt][bw][f+1]
3464930cef6SMatthias Ringwald
3474930cef6SMatthias Ringwald                y[i0:i1] = self.filtering(
3484930cef6SMatthias Ringwald                    fstate, x[i0:i1], rc_order, rc)
3494930cef6SMatthias Ringwald
3504930cef6SMatthias Ringwald        return y
3514930cef6SMatthias Ringwald
3524930cef6SMatthias Ringwald
3534930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
3544930cef6SMatthias Ringwald
3554930cef6SMatthias Ringwalddef check_analysis(rng, dt, bw):
3564930cef6SMatthias Ringwald
3574930cef6SMatthias Ringwald    ok = True
3584930cef6SMatthias Ringwald
3594930cef6SMatthias Ringwald    analysis = TnsAnalysis(dt)
3604930cef6SMatthias Ringwald    nbytes_lim = int((48 * T.DT_MS[dt]) // 8)
3614930cef6SMatthias Ringwald
3624930cef6SMatthias Ringwald    for i in range(10):
363*6897da5cSDirk Helbig        ne = T.I[dt][bw][-1]
364*6897da5cSDirk Helbig        x  = rng.random(ne) * 1e2
3654930cef6SMatthias Ringwald        x  = pow(x, .5 + i/5)
3664930cef6SMatthias Ringwald
3674930cef6SMatthias Ringwald        for nn_flag in (True, False):
3684930cef6SMatthias Ringwald            for nbytes in (nbytes_lim, nbytes_lim + 1):
3694930cef6SMatthias Ringwald
3704930cef6SMatthias Ringwald                y = analysis.run(x, bw, nn_flag, nbytes)
3714930cef6SMatthias Ringwald                (y_c, data_c) = lc3.tns_analyze(dt, bw, nn_flag, nbytes, x)
3724930cef6SMatthias Ringwald
3734930cef6SMatthias Ringwald                ok = ok and data_c['lpc_weighting'] == analysis.lpc_weighting
374*6897da5cSDirk Helbig                ok = ok and data_c['nfilters'] == analysis.nfilters
3754930cef6SMatthias Ringwald                for f in range(analysis.nfilters):
3764930cef6SMatthias Ringwald                    rc_order = analysis.rc_order[f]
3774930cef6SMatthias Ringwald                    rc_order_c = data_c['rc_order'][f]
3784930cef6SMatthias Ringwald                    rc_c = 8 + data_c['rc'][f]
3794930cef6SMatthias Ringwald                    ok = ok and rc_order_c == rc_order
380*6897da5cSDirk Helbig                    ok = ok and not np.any(rc_c[:rc_order] - analysis.rc[f][:rc_order])
3814930cef6SMatthias Ringwald
3824930cef6SMatthias Ringwald                ok = ok and lc3.tns_get_nbits(data_c) == analysis.get_nbits()
3834930cef6SMatthias Ringwald                ok = ok and np.amax(np.abs(y_c - y)) < 1e-2
3844930cef6SMatthias Ringwald
3854930cef6SMatthias Ringwald    return ok
3864930cef6SMatthias Ringwald
3874930cef6SMatthias Ringwalddef check_synthesis(rng, dt, bw):
3884930cef6SMatthias Ringwald
3894930cef6SMatthias Ringwald    ok = True
3904930cef6SMatthias Ringwald    synthesis = TnsSynthesis(dt)
3914930cef6SMatthias Ringwald
3924930cef6SMatthias Ringwald    for i in range(100):
3934930cef6SMatthias Ringwald
394*6897da5cSDirk Helbig        ne = T.I[dt][bw][-1]
395*6897da5cSDirk Helbig        x  = rng.random(ne) * 1e2
3964930cef6SMatthias Ringwald
397*6897da5cSDirk Helbig        maxorder = [ 4, 8 ][dt > T.DT_5M]
398*6897da5cSDirk Helbig        synthesis.nfilters = 1 + int(dt >= T.DT_5M and bw >= T.SRATE_32K)
399*6897da5cSDirk Helbig        synthesis.rc_order = rng.integers(0, 1+maxorder, 2)
4004930cef6SMatthias Ringwald        synthesis.rc = rng.integers(0, 17, 16).reshape(2, 8)
4014930cef6SMatthias Ringwald
4024930cef6SMatthias Ringwald        y = synthesis.run(x, bw)
4034930cef6SMatthias Ringwald        y_c = lc3.tns_synthesize(dt, bw, synthesis.get_data(), x)
4044930cef6SMatthias Ringwald
405*6897da5cSDirk Helbig        ok = ok and np.amax(np.abs(y_c - y) < 1e-4)
4064930cef6SMatthias Ringwald
4074930cef6SMatthias Ringwald    return ok
4084930cef6SMatthias Ringwald
4094930cef6SMatthias Ringwalddef check_analysis_appendix_c(dt):
4104930cef6SMatthias Ringwald
411*6897da5cSDirk Helbig    i0 = dt - T.DT_7M5
4124930cef6SMatthias Ringwald    sr = T.SRATE_16K
413*6897da5cSDirk Helbig
4144930cef6SMatthias Ringwald    ok = True
4154930cef6SMatthias Ringwald
416*6897da5cSDirk Helbig    fs = Tns.FREQ_LIM[i0][sr][0]
417*6897da5cSDirk Helbig    fe = Tns.FREQ_LIM[i0][sr][1]
4184930cef6SMatthias Ringwald    st = np.zeros(8)
4194930cef6SMatthias Ringwald
420*6897da5cSDirk Helbig    for i in range(len(C.X_S[i0])):
4214930cef6SMatthias Ringwald
422*6897da5cSDirk Helbig        (_, a) = lc3.tns_compute_lpc_coeffs(dt, sr, C.X_S[i0][i])
423*6897da5cSDirk Helbig        ok = ok and np.amax(np.abs(a[0] - C.TNS_LEV_A[i0][i])) < 1e-5
4244930cef6SMatthias Ringwald
425*6897da5cSDirk Helbig        rc = lc3.tns_lpc_reflection(dt, a[0])
426*6897da5cSDirk Helbig        ok = ok and np.amax(np.abs(rc - C.TNS_LEV_RC[i0][i])) < 1e-5
4274930cef6SMatthias Ringwald
428*6897da5cSDirk Helbig        (rc_order, rc_i) = lc3.tns_quantize_rc(dt, C.TNS_LEV_RC[i0][i])
429*6897da5cSDirk Helbig        ok = ok and rc_order == C.RC_ORDER[i0][i][0]
430*6897da5cSDirk Helbig        ok = ok and np.any((rc_i + 8) - C.RC_I_1[i0][i] == 0)
4314930cef6SMatthias Ringwald
4324930cef6SMatthias Ringwald        rc_q = lc3.tns_unquantize_rc(rc_i, rc_order)
433*6897da5cSDirk Helbig        ok = ok and np.amax(np.abs(rc_q - C.RC_Q_1[i0][i])) < 1e-6
4344930cef6SMatthias Ringwald
435*6897da5cSDirk Helbig        (x, side) = lc3.tns_analyze(dt, sr, False, C.NBYTES[i0], C.X_S[i0][i])
4364930cef6SMatthias Ringwald        ok = ok and side['nfilters'] == 1
437*6897da5cSDirk Helbig        ok = ok and side['rc_order'][0] == C.RC_ORDER[i0][i][0]
438*6897da5cSDirk Helbig        ok = ok and not np.any((side['rc'][0] + 8) - C.RC_I_1[i0][i])
439*6897da5cSDirk Helbig        ok = ok and lc3.tns_get_nbits(side) == C.NBITS_TNS[i0][i]
440*6897da5cSDirk Helbig        ok = ok and np.amax(np.abs(x - C.X_F[i0][i])) < 1e-3
4414930cef6SMatthias Ringwald
4424930cef6SMatthias Ringwald    return ok
4434930cef6SMatthias Ringwald
4444930cef6SMatthias Ringwalddef check_synthesis_appendix_c(dt):
4454930cef6SMatthias Ringwald
446*6897da5cSDirk Helbig    i0 = dt - T.DT_7M5
4474930cef6SMatthias Ringwald    sr = T.SRATE_16K
448*6897da5cSDirk Helbig
4494930cef6SMatthias Ringwald    ok = True
4504930cef6SMatthias Ringwald
451*6897da5cSDirk Helbig    for i in range(len(C.X_HAT_Q[i0])):
4524930cef6SMatthias Ringwald
4534930cef6SMatthias Ringwald        side = {
4544930cef6SMatthias Ringwald            'nfilters' : 1,
455*6897da5cSDirk Helbig            'lpc_weighting' : C.NBYTES[i0] < 120 * (1 + dt) / 8,
456*6897da5cSDirk Helbig            'rc_order': C.RC_ORDER[i0][i],
457*6897da5cSDirk Helbig            'rc': [ C.RC_I_1[i0][i] - 8, C.RC_I_2[i0][i] - 8 ]
4584930cef6SMatthias Ringwald        }
4594930cef6SMatthias Ringwald
460*6897da5cSDirk Helbig        g_int = C.GG_IND_ADJ[i0][i] + C.GG_OFF[i0][i]
461*6897da5cSDirk Helbig        x = C.X_HAT_Q[i0][i] * (10 ** (g_int / 28))
4624930cef6SMatthias Ringwald
4634930cef6SMatthias Ringwald        x = lc3.tns_synthesize(dt, sr, side, x)
464*6897da5cSDirk Helbig        ok = ok and np.amax(np.abs(x - C.X_HAT_TNS[i0][i])) < 1e-3
4654930cef6SMatthias Ringwald
4664930cef6SMatthias Ringwald    sr = T.SRATE_48K
467*6897da5cSDirk Helbig    if dt != T.DT_10M:
468*6897da5cSDirk Helbig        return ok
4694930cef6SMatthias Ringwald
4704930cef6SMatthias Ringwald    side = {
4714930cef6SMatthias Ringwald        'nfilters' : 2,
4724930cef6SMatthias Ringwald        'lpc_weighting' : False,
4734930cef6SMatthias Ringwald        'rc_order': C.RC_ORDER_48K_10M,
4744930cef6SMatthias Ringwald        'rc': [ C.RC_I_1_48K_10M - 8, C.RC_I_2_48K_10M - 8 ]
4754930cef6SMatthias Ringwald    }
4764930cef6SMatthias Ringwald
4774930cef6SMatthias Ringwald    x = C.X_HAT_F_48K_10M
4784930cef6SMatthias Ringwald    x = lc3.tns_synthesize(dt, sr, side, x)
4794930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(x - C.X_HAT_TNS_48K_10M)) < 1e-3
4804930cef6SMatthias Ringwald
4814930cef6SMatthias Ringwald    return ok
4824930cef6SMatthias Ringwald
4834930cef6SMatthias Ringwalddef check():
4844930cef6SMatthias Ringwald
4854930cef6SMatthias Ringwald    rng = np.random.default_rng(1234)
4864930cef6SMatthias Ringwald    ok = True
4874930cef6SMatthias Ringwald
4884930cef6SMatthias Ringwald    for dt in range(T.NUM_DT):
489*6897da5cSDirk Helbig        for sr in range(T.SRATE_8K, T.SRATE_48K + 1):
4904930cef6SMatthias Ringwald            ok = ok and check_analysis(rng, dt, sr)
4914930cef6SMatthias Ringwald            ok = ok and check_synthesis(rng, dt, sr)
4924930cef6SMatthias Ringwald
493*6897da5cSDirk Helbig    for dt in ( T.DT_2M5, T.DT_5M, T.DT_10M ):
494*6897da5cSDirk Helbig        for sr in ( T.SRATE_48K_HR, T.SRATE_96K_HR ):
495*6897da5cSDirk Helbig            ok = ok and check_analysis(rng, dt, sr)
496*6897da5cSDirk Helbig
497*6897da5cSDirk Helbig    for dt in ( T.DT_7M5, T.DT_10M ):
498*6897da5cSDirk Helbig        check_analysis_appendix_c(dt)
499*6897da5cSDirk Helbig        check_synthesis_appendix_c(dt)
5004930cef6SMatthias Ringwald
5014930cef6SMatthias Ringwald    return ok
5024930cef6SMatthias Ringwald
5034930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
504