xref: /btstack/3rd-party/lc3-google/test/ltpf.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 Ringwaldimport scipy.signal as signal
19*4930cef6SMatthias Ringwald
20*4930cef6SMatthias Ringwaldimport build.lc3 as lc3
21*4930cef6SMatthias Ringwaldimport tables as T, appendix_c as C
22*4930cef6SMatthias Ringwald
23*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
24*4930cef6SMatthias Ringwald
25*4930cef6SMatthias Ringwaldclass Resampler_12k8:
26*4930cef6SMatthias Ringwald
27*4930cef6SMatthias Ringwald    def __init__(self, dt, sr, history = 0):
28*4930cef6SMatthias Ringwald
29*4930cef6SMatthias Ringwald        self.sr = sr
30*4930cef6SMatthias Ringwald        self.p = 192 // T.SRATE_KHZ[sr]
31*4930cef6SMatthias Ringwald        self.w = 240 // self.p
32*4930cef6SMatthias Ringwald
33*4930cef6SMatthias Ringwald        self.n = ((T.DT_MS[dt] * 128) / 10).astype(int)
34*4930cef6SMatthias Ringwald        self.d = [ 44, 24 ][dt]
35*4930cef6SMatthias Ringwald
36*4930cef6SMatthias Ringwald        self.x = np.zeros(self.w + T.NS[dt][sr])
37*4930cef6SMatthias Ringwald        self.u = np.zeros(self.n + 2)
38*4930cef6SMatthias Ringwald        self.y = np.zeros(self.n + self.d + history)
39*4930cef6SMatthias Ringwald
40*4930cef6SMatthias Ringwald    def resample(self, x):
41*4930cef6SMatthias Ringwald
42*4930cef6SMatthias Ringwald        p = self.p
43*4930cef6SMatthias Ringwald        w = self.w
44*4930cef6SMatthias Ringwald        d = self.d
45*4930cef6SMatthias Ringwald        n = self.n
46*4930cef6SMatthias Ringwald
47*4930cef6SMatthias Ringwald        ### Sliding window
48*4930cef6SMatthias Ringwald
49*4930cef6SMatthias Ringwald        self.x[:w] = self.x[-w:]
50*4930cef6SMatthias Ringwald        self.x[w:] = x
51*4930cef6SMatthias Ringwald        self.u[:2] = self.u[-2:]
52*4930cef6SMatthias Ringwald
53*4930cef6SMatthias Ringwald        if len(self.y) > 2*n + d:
54*4930cef6SMatthias Ringwald            self.y[n+d:-n] = self.y[d+2*n:]
55*4930cef6SMatthias Ringwald        if len(self.y) > n + d:
56*4930cef6SMatthias Ringwald            self.y[-n:] = self.y[:n]
57*4930cef6SMatthias Ringwald        self.y[:d] = self.y[n:d+n]
58*4930cef6SMatthias Ringwald
59*4930cef6SMatthias Ringwald        x = self.x
60*4930cef6SMatthias Ringwald        u = self.u
61*4930cef6SMatthias Ringwald
62*4930cef6SMatthias Ringwald        ### 3.3.9.3 Resampling
63*4930cef6SMatthias Ringwald
64*4930cef6SMatthias Ringwald        h = np.zeros(240 + p)
65*4930cef6SMatthias Ringwald        h[-119:] = T.LTPF_H12K8[:119]
66*4930cef6SMatthias Ringwald        h[ :120] = T.LTPF_H12K8[119:]
67*4930cef6SMatthias Ringwald
68*4930cef6SMatthias Ringwald        for i in range(n):
69*4930cef6SMatthias Ringwald            e = (15 * i) // p
70*4930cef6SMatthias Ringwald            f = (15 * i)  % p
71*4930cef6SMatthias Ringwald            k = np.arange(-120, 120 + p, p) - f
72*4930cef6SMatthias Ringwald            u[2+i] = p * np.dot( x[e:e+w+1], np.take(h, k) )
73*4930cef6SMatthias Ringwald
74*4930cef6SMatthias Ringwald        if self.sr == T.SRATE_8K:
75*4930cef6SMatthias Ringwald            u = 0.5 * u
76*4930cef6SMatthias Ringwald
77*4930cef6SMatthias Ringwald        ### 3.3.9.4 High-pass filtering
78*4930cef6SMatthias Ringwald
79*4930cef6SMatthias Ringwald        b = [ 0.9827947082978771, -1.9655894165957540, 0.9827947082978771 ]
80*4930cef6SMatthias Ringwald        a = [ 1                 , -1.9652933726226904, 0.9658854605688177 ]
81*4930cef6SMatthias Ringwald
82*4930cef6SMatthias Ringwald        self.y[d:d+n] = b[0] * u[2:] + b[1] * u[1:-1] + b[2] * u[:-2]
83*4930cef6SMatthias Ringwald        for i in range(n):
84*4930cef6SMatthias Ringwald            self.y[d+i] -= a[1] * self.y[d+i-1] + a[2] * self.y[d+i-2]
85*4930cef6SMatthias Ringwald
86*4930cef6SMatthias Ringwald        return self.y
87*4930cef6SMatthias Ringwald
88*4930cef6SMatthias Ringwald
89*4930cef6SMatthias Ringwaldclass Resampler_6k4:
90*4930cef6SMatthias Ringwald
91*4930cef6SMatthias Ringwald    def __init__(self, n, history = 0):
92*4930cef6SMatthias Ringwald
93*4930cef6SMatthias Ringwald        self.x = np.zeros(n + 5)
94*4930cef6SMatthias Ringwald        self.n = n // 2
95*4930cef6SMatthias Ringwald
96*4930cef6SMatthias Ringwald        self.y = np.zeros(self.n + history)
97*4930cef6SMatthias Ringwald
98*4930cef6SMatthias Ringwald    def resample(self, x):
99*4930cef6SMatthias Ringwald
100*4930cef6SMatthias Ringwald        n = self.n
101*4930cef6SMatthias Ringwald
102*4930cef6SMatthias Ringwald        ### Sliding window
103*4930cef6SMatthias Ringwald
104*4930cef6SMatthias Ringwald        self.x[:3] = self.x[-5:-2]
105*4930cef6SMatthias Ringwald        self.x[3:] = x[:2*n+2]
106*4930cef6SMatthias Ringwald        x = self.x
107*4930cef6SMatthias Ringwald
108*4930cef6SMatthias Ringwald        if len(self.y) > 2*n:
109*4930cef6SMatthias Ringwald            self.y[n:-n] = self.y[2*n:]
110*4930cef6SMatthias Ringwald        if len(self.y) > n:
111*4930cef6SMatthias Ringwald            self.y[-n:] = self.y[:n]
112*4930cef6SMatthias Ringwald
113*4930cef6SMatthias Ringwald        ### 3.3.9.5 Downsampling to 6.4 KHz
114*4930cef6SMatthias Ringwald
115*4930cef6SMatthias Ringwald        h = [ 0.1236796411180537, 0.2353512128364889, 0.2819382920909148,
116*4930cef6SMatthias Ringwald              0.2353512128364889, 0.1236796411180537 ]
117*4930cef6SMatthias Ringwald
118*4930cef6SMatthias Ringwald        self.y[:n] = [ np.dot(x[2*i:2*i+5], h) for i in range(self.n) ]
119*4930cef6SMatthias Ringwald        return self.y
120*4930cef6SMatthias Ringwald
121*4930cef6SMatthias Ringwald
122*4930cef6SMatthias Ringwalddef initial_hp50_state():
123*4930cef6SMatthias Ringwald    return { 's1': 0, 's2': 0 }
124*4930cef6SMatthias Ringwald
125*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
126*4930cef6SMatthias Ringwald
127*4930cef6SMatthias Ringwaldclass Ltpf:
128*4930cef6SMatthias Ringwald
129*4930cef6SMatthias Ringwald    def __init__(self, dt, sr):
130*4930cef6SMatthias Ringwald
131*4930cef6SMatthias Ringwald        self.dt = dt
132*4930cef6SMatthias Ringwald        self.sr = sr
133*4930cef6SMatthias Ringwald
134*4930cef6SMatthias Ringwald        (self.pitch_present, self.pitch_index) = (None, None)
135*4930cef6SMatthias Ringwald
136*4930cef6SMatthias Ringwald    def get_data(self):
137*4930cef6SMatthias Ringwald
138*4930cef6SMatthias Ringwald        return { 'active' : self.active,
139*4930cef6SMatthias Ringwald                 'pitch_index' : self.pitch_index }
140*4930cef6SMatthias Ringwald
141*4930cef6SMatthias Ringwald    def get_nbits(self):
142*4930cef6SMatthias Ringwald
143*4930cef6SMatthias Ringwald        return 1 + 10 * int(self.pitch_present)
144*4930cef6SMatthias Ringwald
145*4930cef6SMatthias Ringwald
146*4930cef6SMatthias Ringwaldclass LtpfAnalysis(Ltpf):
147*4930cef6SMatthias Ringwald
148*4930cef6SMatthias Ringwald    def __init__(self, dt, sr):
149*4930cef6SMatthias Ringwald
150*4930cef6SMatthias Ringwald        super().__init__(dt, sr)
151*4930cef6SMatthias Ringwald
152*4930cef6SMatthias Ringwald        self.resampler_12k8 = Resampler_12k8(
153*4930cef6SMatthias Ringwald                dt, sr, history = 232)
154*4930cef6SMatthias Ringwald
155*4930cef6SMatthias Ringwald        self.resampler_6k4 = Resampler_6k4(
156*4930cef6SMatthias Ringwald                self.resampler_12k8.n, history = 114)
157*4930cef6SMatthias Ringwald
158*4930cef6SMatthias Ringwald        self.active = False
159*4930cef6SMatthias Ringwald        self.tc = 0
160*4930cef6SMatthias Ringwald        self.pitch = 0
161*4930cef6SMatthias Ringwald        self.nc = np.zeros(2)
162*4930cef6SMatthias Ringwald
163*4930cef6SMatthias Ringwald    def correlate(self, x, n, k0, k1):
164*4930cef6SMatthias Ringwald
165*4930cef6SMatthias Ringwald        return [ np.dot(x[:n], np.take(x, np.arange(n) - k)) \
166*4930cef6SMatthias Ringwald                    for k in range(k0, 1+k1) ]
167*4930cef6SMatthias Ringwald
168*4930cef6SMatthias Ringwald    def norm_corr(self, x, n, k):
169*4930cef6SMatthias Ringwald
170*4930cef6SMatthias Ringwald        u  = x[:n]
171*4930cef6SMatthias Ringwald        v  = np.take(x, np.arange(n) - k)
172*4930cef6SMatthias Ringwald        uv = np.dot(u, v)
173*4930cef6SMatthias Ringwald        return uv / np.sqrt(np.dot(u, u) * np.dot(v, v)) if uv > 0 else 0
174*4930cef6SMatthias Ringwald
175*4930cef6SMatthias Ringwald    def run(self, x):
176*4930cef6SMatthias Ringwald
177*4930cef6SMatthias Ringwald        ### 3.3.9.3-4 Resampling
178*4930cef6SMatthias Ringwald
179*4930cef6SMatthias Ringwald        x_12k8 = self.resampler_12k8.resample(x)
180*4930cef6SMatthias Ringwald
181*4930cef6SMatthias Ringwald        ### 3.3.9.5-6 Pitch detection algorithm
182*4930cef6SMatthias Ringwald
183*4930cef6SMatthias Ringwald        x = self.resampler_6k4.resample(x_12k8)
184*4930cef6SMatthias Ringwald        n = self.resampler_6k4.n
185*4930cef6SMatthias Ringwald
186*4930cef6SMatthias Ringwald        r  = self.correlate(x, n, 17, 114)
187*4930cef6SMatthias Ringwald        rw = r * (1 - 0.5 * np.arange(len(r)) / (len(r) - 1))
188*4930cef6SMatthias Ringwald
189*4930cef6SMatthias Ringwald        tc = self.tc
190*4930cef6SMatthias Ringwald        k0 = max(0, tc-4)
191*4930cef6SMatthias Ringwald        k1 = min(len(r)-1, tc+4)
192*4930cef6SMatthias Ringwald        t  = [ 17 + np.argmax(rw), 17 + k0 + np.argmax(r[k0:1+k1]) ]
193*4930cef6SMatthias Ringwald
194*4930cef6SMatthias Ringwald        nc = [ self.norm_corr(x, n, t[i]) for i in range(2) ]
195*4930cef6SMatthias Ringwald        ti = int(nc[1] > 0.85 * nc[0])
196*4930cef6SMatthias Ringwald        self.tc = t[ti] - 17
197*4930cef6SMatthias Ringwald
198*4930cef6SMatthias Ringwald        self.pitch_present = bool(nc[ti] > 0.6)
199*4930cef6SMatthias Ringwald
200*4930cef6SMatthias Ringwald        ### 3.3.9.7 Pitch-lag parameter
201*4930cef6SMatthias Ringwald
202*4930cef6SMatthias Ringwald        if self.pitch_present:
203*4930cef6SMatthias Ringwald            tc = self.tc + 17
204*4930cef6SMatthias Ringwald
205*4930cef6SMatthias Ringwald            x = x_12k8
206*4930cef6SMatthias Ringwald            n = self.resampler_12k8.n
207*4930cef6SMatthias Ringwald
208*4930cef6SMatthias Ringwald            k0 = max( 32, 2*tc-4)
209*4930cef6SMatthias Ringwald            k1 = min(228, 2*tc+4)
210*4930cef6SMatthias Ringwald            r  = self.correlate(x, n, k0-4, k1+4)
211*4930cef6SMatthias Ringwald            e  = k0 + np.argmax(r[4:-4])
212*4930cef6SMatthias Ringwald
213*4930cef6SMatthias Ringwald            h = np.zeros(42)
214*4930cef6SMatthias Ringwald            h[-15:] = T.LTPF_H4[:15]
215*4930cef6SMatthias Ringwald            h[ :16] = T.LTPF_H4[15:]
216*4930cef6SMatthias Ringwald
217*4930cef6SMatthias Ringwald            m = np.arange(-4, 5)
218*4930cef6SMatthias Ringwald            s = [ np.dot( np.take(r, e-k0+4 + m), np.take(h, 4*m-d) ) \
219*4930cef6SMatthias Ringwald                      for d in range(-3, 4) ]
220*4930cef6SMatthias Ringwald
221*4930cef6SMatthias Ringwald            f = np.argmax(s[3:])            if e <=  32 else \
222*4930cef6SMatthias Ringwald                -3 + np.argmax(s)           if e <  127 else \
223*4930cef6SMatthias Ringwald                -2 + 2*np.argmax(s[1:-1:2]) if e <  157 else 0
224*4930cef6SMatthias Ringwald
225*4930cef6SMatthias Ringwald            e -=   (f < 0)
226*4930cef6SMatthias Ringwald            f += 4*(f < 0)
227*4930cef6SMatthias Ringwald
228*4930cef6SMatthias Ringwald            self.pitch_index = 4*e + f    - 128 if e < 127 else \
229*4930cef6SMatthias Ringwald                               2*e + f//2 + 126 if e < 157 else e + 283
230*4930cef6SMatthias Ringwald
231*4930cef6SMatthias Ringwald        else:
232*4930cef6SMatthias Ringwald            e = f = 0
233*4930cef6SMatthias Ringwald            self.pitch_index = 0
234*4930cef6SMatthias Ringwald
235*4930cef6SMatthias Ringwald        ### 3.3.9.8 Activation bit
236*4930cef6SMatthias Ringwald
237*4930cef6SMatthias Ringwald        h = np.zeros(24)
238*4930cef6SMatthias Ringwald        h[-7:] = T.LTPF_HI[:7]
239*4930cef6SMatthias Ringwald        h[ :8] = T.LTPF_HI[7:]
240*4930cef6SMatthias Ringwald
241*4930cef6SMatthias Ringwald        k = np.arange(-2, 3)
242*4930cef6SMatthias Ringwald        u = [ np.dot( np.take(x, i-k), np.take(h, 4*k) ) \
243*4930cef6SMatthias Ringwald                  for i in range(n) ]
244*4930cef6SMatthias Ringwald        v = [ np.dot( np.take(x, i-k), np.take(h, 4*k-f) ) \
245*4930cef6SMatthias Ringwald                  for i in range(-e, n-e) ]
246*4930cef6SMatthias Ringwald
247*4930cef6SMatthias Ringwald        nc = max(0, np.dot(u, v)) / np.sqrt(np.dot(u, u) * np.dot(v, v)) \
248*4930cef6SMatthias Ringwald                if self.pitch_present else 0
249*4930cef6SMatthias Ringwald
250*4930cef6SMatthias Ringwald        pitch = e + f/4
251*4930cef6SMatthias Ringwald
252*4930cef6SMatthias Ringwald        if not self.active:
253*4930cef6SMatthias Ringwald            active = (self.dt == T.DT_10M or self.nc[1] > 0.94) \
254*4930cef6SMatthias Ringwald                     and self.nc[0] > 0.94 and nc > 0.94
255*4930cef6SMatthias Ringwald
256*4930cef6SMatthias Ringwald        else:
257*4930cef6SMatthias Ringwald            dp = abs(pitch - self.pitch)
258*4930cef6SMatthias Ringwald            dc = nc - self.nc[0]
259*4930cef6SMatthias Ringwald            active = nc > 0.9 or (dp < 2 and dc > -0.1 and nc > 0.84)
260*4930cef6SMatthias Ringwald
261*4930cef6SMatthias Ringwald        if not self.pitch_present:
262*4930cef6SMatthias Ringwald            active = False
263*4930cef6SMatthias Ringwald            pitch = 0
264*4930cef6SMatthias Ringwald            nc = 0
265*4930cef6SMatthias Ringwald
266*4930cef6SMatthias Ringwald        self.active = active
267*4930cef6SMatthias Ringwald        self.pitch = pitch
268*4930cef6SMatthias Ringwald        self.nc[1] = self.nc[0]
269*4930cef6SMatthias Ringwald        self.nc[0] = nc
270*4930cef6SMatthias Ringwald
271*4930cef6SMatthias Ringwald        return self.pitch_present
272*4930cef6SMatthias Ringwald
273*4930cef6SMatthias Ringwald    def disable(self):
274*4930cef6SMatthias Ringwald
275*4930cef6SMatthias Ringwald        self.active = False
276*4930cef6SMatthias Ringwald
277*4930cef6SMatthias Ringwald    def store(self, b):
278*4930cef6SMatthias Ringwald
279*4930cef6SMatthias Ringwald        b.write_uint(self.active, 1)
280*4930cef6SMatthias Ringwald        b.write_uint(self.pitch_index, 9)
281*4930cef6SMatthias Ringwald
282*4930cef6SMatthias Ringwald
283*4930cef6SMatthias Ringwaldclass LtpfSynthesis(Ltpf):
284*4930cef6SMatthias Ringwald
285*4930cef6SMatthias Ringwald    C_N = [ T.LTPF_N_8K , T.LTPF_N_16K,
286*4930cef6SMatthias Ringwald            T.LTPF_N_24K, T.LTPF_N_32K, T.LTPF_N_48K ]
287*4930cef6SMatthias Ringwald
288*4930cef6SMatthias Ringwald    C_D = [ T.LTPF_D_8K , T.LTPF_D_16K,
289*4930cef6SMatthias Ringwald            T.LTPF_D_24K, T.LTPF_D_32K, T.LTPF_D_48K ]
290*4930cef6SMatthias Ringwald
291*4930cef6SMatthias Ringwald    def __init__(self, dt, sr):
292*4930cef6SMatthias Ringwald
293*4930cef6SMatthias Ringwald        super().__init__(dt, sr)
294*4930cef6SMatthias Ringwald
295*4930cef6SMatthias Ringwald        self.C_N = LtpfSynthesis.C_N[sr]
296*4930cef6SMatthias Ringwald        self.C_D = LtpfSynthesis.C_D[sr]
297*4930cef6SMatthias Ringwald
298*4930cef6SMatthias Ringwald        ns = T.NS[dt][sr]
299*4930cef6SMatthias Ringwald
300*4930cef6SMatthias Ringwald        self.active = [ False, False ]
301*4930cef6SMatthias Ringwald        self.pitch_index = 0
302*4930cef6SMatthias Ringwald
303*4930cef6SMatthias Ringwald        max_pitch_12k8 = 228
304*4930cef6SMatthias Ringwald        max_pitch = max_pitch_12k8 * T.SRATE_KHZ[self.sr] / 12.8
305*4930cef6SMatthias Ringwald        max_pitch = np.ceil(max_pitch).astype(int)
306*4930cef6SMatthias Ringwald
307*4930cef6SMatthias Ringwald        self.x = np.zeros(ns)
308*4930cef6SMatthias Ringwald        self.y = np.zeros(max_pitch + len(self.C_D[0]))
309*4930cef6SMatthias Ringwald
310*4930cef6SMatthias Ringwald        self.p_e = [ 0, 0 ]
311*4930cef6SMatthias Ringwald        self.p_f = [ 0, 0 ]
312*4930cef6SMatthias Ringwald        self.c_n = [ None, None ]
313*4930cef6SMatthias Ringwald        self.c_d = [ None, None ]
314*4930cef6SMatthias Ringwald
315*4930cef6SMatthias Ringwald    def load(self, b):
316*4930cef6SMatthias Ringwald
317*4930cef6SMatthias Ringwald        self.active[0] = bool(b.read_uint(1))
318*4930cef6SMatthias Ringwald        self.pitch_index = b.read_uint(9)
319*4930cef6SMatthias Ringwald
320*4930cef6SMatthias Ringwald    def disable(self):
321*4930cef6SMatthias Ringwald
322*4930cef6SMatthias Ringwald        self.active[0] = False
323*4930cef6SMatthias Ringwald        self.pitch_index = 0
324*4930cef6SMatthias Ringwald
325*4930cef6SMatthias Ringwald    def run(self, x, nbytes):
326*4930cef6SMatthias Ringwald
327*4930cef6SMatthias Ringwald        sr = self.sr
328*4930cef6SMatthias Ringwald        dt = self.dt
329*4930cef6SMatthias Ringwald
330*4930cef6SMatthias Ringwald        ### 3.4.9.4 Filter parameters
331*4930cef6SMatthias Ringwald
332*4930cef6SMatthias Ringwald        pitch_index = self.pitch_index
333*4930cef6SMatthias Ringwald
334*4930cef6SMatthias Ringwald        if pitch_index >= 440:
335*4930cef6SMatthias Ringwald            p_e = pitch_index - 283
336*4930cef6SMatthias Ringwald            p_f = 0
337*4930cef6SMatthias Ringwald        elif pitch_index >= 380:
338*4930cef6SMatthias Ringwald            p_e = pitch_index // 2 - 63
339*4930cef6SMatthias Ringwald            p_f = 2*(pitch_index - 2*(p_e + 63))
340*4930cef6SMatthias Ringwald        else:
341*4930cef6SMatthias Ringwald            p_e = pitch_index // 4 + 32
342*4930cef6SMatthias Ringwald            p_f = pitch_index - 4*(p_e - 32)
343*4930cef6SMatthias Ringwald
344*4930cef6SMatthias Ringwald        p = (p_e + p_f / 4) * T.SRATE_KHZ[self.sr] / 12.8
345*4930cef6SMatthias Ringwald
346*4930cef6SMatthias Ringwald        self.p_e[0] = int(p * 4 + 0.5) // 4
347*4930cef6SMatthias Ringwald        self.p_f[0] = int(p * 4 + 0.5) - 4*self.p_e[0]
348*4930cef6SMatthias Ringwald
349*4930cef6SMatthias Ringwald        nbits = round(nbytes*80 / T.DT_MS[dt])
350*4930cef6SMatthias Ringwald        g_idx = max(nbits // 80, 3+sr) - (3+sr)
351*4930cef6SMatthias Ringwald
352*4930cef6SMatthias Ringwald        g = [ 0.4, 0.35, 0.3, 0.25 ][g_idx] if g_idx < 4 else 0
353*4930cef6SMatthias Ringwald        g_idx = min(g_idx, 3)
354*4930cef6SMatthias Ringwald
355*4930cef6SMatthias Ringwald        self.c_n[0] = 0.85 * g * LtpfSynthesis.C_N[sr][g_idx]
356*4930cef6SMatthias Ringwald        self.c_d[0] = g * LtpfSynthesis.C_D[sr][self.p_f[0]]
357*4930cef6SMatthias Ringwald
358*4930cef6SMatthias Ringwald        ### 3.4.9.2 Transition handling
359*4930cef6SMatthias Ringwald
360*4930cef6SMatthias Ringwald        n0 = (T.SRATE_KHZ[sr] * 1000) // 400
361*4930cef6SMatthias Ringwald        ns = T.NS[dt][sr]
362*4930cef6SMatthias Ringwald
363*4930cef6SMatthias Ringwald        x  = np.append(x, self.x)
364*4930cef6SMatthias Ringwald        y  = np.append(np.zeros(ns), self.y)
365*4930cef6SMatthias Ringwald        yc = y.copy()
366*4930cef6SMatthias Ringwald
367*4930cef6SMatthias Ringwald        c_n = self.c_n
368*4930cef6SMatthias Ringwald        c_d = self.c_d
369*4930cef6SMatthias Ringwald
370*4930cef6SMatthias Ringwald        l_n = len(c_n[0])
371*4930cef6SMatthias Ringwald        l_d = len(c_d[0])
372*4930cef6SMatthias Ringwald
373*4930cef6SMatthias Ringwald        d = [ self.p_e[0] - (l_d - 1) // 2,
374*4930cef6SMatthias Ringwald              self.p_e[1] - (l_d - 1) // 2 ]
375*4930cef6SMatthias Ringwald
376*4930cef6SMatthias Ringwald        for k in range(n0):
377*4930cef6SMatthias Ringwald
378*4930cef6SMatthias Ringwald            if not self.active[0] and not self.active[1]:
379*4930cef6SMatthias Ringwald                y[k] = x[k]
380*4930cef6SMatthias Ringwald
381*4930cef6SMatthias Ringwald            elif self.active[0] and not self.active[1]:
382*4930cef6SMatthias Ringwald                u = np.dot(c_n[0], np.take(x, k - np.arange(l_n))) - \
383*4930cef6SMatthias Ringwald                    np.dot(c_d[0], np.take(y, k - d[0] - np.arange(l_d)))
384*4930cef6SMatthias Ringwald                y[k] = x[k] - (k/n0) * u
385*4930cef6SMatthias Ringwald
386*4930cef6SMatthias Ringwald            elif not self.active[0] and self.active[1]:
387*4930cef6SMatthias Ringwald                u = np.dot(c_n[1], np.take(x, k - np.arange(l_n))) - \
388*4930cef6SMatthias Ringwald                    np.dot(c_d[1], np.take(y, k - d[1] - np.arange(l_d)))
389*4930cef6SMatthias Ringwald                y[k] = x[k] - (1 - k/n0) * u
390*4930cef6SMatthias Ringwald
391*4930cef6SMatthias Ringwald            elif self.p_e[0] == self.p_e[1] and self.p_f[0] == self.p_f[1]:
392*4930cef6SMatthias Ringwald                u = np.dot(c_n[0], np.take(x, k - np.arange(l_n))) - \
393*4930cef6SMatthias Ringwald                    np.dot(c_d[0], np.take(y, k - d[0] - np.arange(l_d)))
394*4930cef6SMatthias Ringwald                y[k] = x[k] - u
395*4930cef6SMatthias Ringwald
396*4930cef6SMatthias Ringwald            else:
397*4930cef6SMatthias Ringwald                u = np.dot(c_n[1], np.take(x, k - np.arange(l_n))) - \
398*4930cef6SMatthias Ringwald                    np.dot(c_d[1], np.take(y, k - d[1] - np.arange(l_d)))
399*4930cef6SMatthias Ringwald                yc[k] = x[k] - (1 - k/n0) * u
400*4930cef6SMatthias Ringwald
401*4930cef6SMatthias Ringwald                u = np.dot(c_n[0], np.take(yc, k - np.arange(l_n))) - \
402*4930cef6SMatthias Ringwald                    np.dot(c_d[0], np.take(y , k - d[0] - np.arange(l_d)))
403*4930cef6SMatthias Ringwald                y[k] = yc[k] - (k/n0) * u
404*4930cef6SMatthias Ringwald
405*4930cef6SMatthias Ringwald
406*4930cef6SMatthias Ringwald        ### 3.4.9.3 Remainder of the frame
407*4930cef6SMatthias Ringwald
408*4930cef6SMatthias Ringwald        for k in range(n0, ns):
409*4930cef6SMatthias Ringwald
410*4930cef6SMatthias Ringwald            if not self.active[0]:
411*4930cef6SMatthias Ringwald                y[k] = x[k]
412*4930cef6SMatthias Ringwald
413*4930cef6SMatthias Ringwald            else:
414*4930cef6SMatthias Ringwald                u = np.dot(c_n[0], np.take(x, k - np.arange(l_n))) - \
415*4930cef6SMatthias Ringwald                    np.dot(c_d[0], np.take(y, k - d[0] - np.arange(l_d)))
416*4930cef6SMatthias Ringwald                y[k] = x[k] - u
417*4930cef6SMatthias Ringwald
418*4930cef6SMatthias Ringwald        ### Sliding window
419*4930cef6SMatthias Ringwald
420*4930cef6SMatthias Ringwald        self.active[1] = self.active[0]
421*4930cef6SMatthias Ringwald        self.p_e[1] = self.p_e[0]
422*4930cef6SMatthias Ringwald        self.p_f[1] = self.p_f[0]
423*4930cef6SMatthias Ringwald        self.c_n[1] = self.c_n[0]
424*4930cef6SMatthias Ringwald        self.c_d[1] = self.c_d[0]
425*4930cef6SMatthias Ringwald
426*4930cef6SMatthias Ringwald        self.x = x[:ns]
427*4930cef6SMatthias Ringwald        self.y = np.append(self.y[ns:], y[:ns])
428*4930cef6SMatthias Ringwald
429*4930cef6SMatthias Ringwald        return y[:ns]
430*4930cef6SMatthias Ringwald
431*4930cef6SMatthias Ringwalddef initial_state():
432*4930cef6SMatthias Ringwald    return { 'active' : False, 'pitch': 0, 'nc':  np.zeros(2),
433*4930cef6SMatthias Ringwald             'hp50' : initial_hp50_state(),
434*4930cef6SMatthias Ringwald             'x_12k8' : np.zeros(384), 'x_6k4' : np.zeros(178), 'tc' : 0 }
435*4930cef6SMatthias Ringwald
436*4930cef6SMatthias Ringwalddef initial_sstate():
437*4930cef6SMatthias Ringwald    return { 'active': False, 'pitch': 0,
438*4930cef6SMatthias Ringwald             'c': np.zeros(2*12), 'x': np.zeros(12) }
439*4930cef6SMatthias Ringwald
440*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
441*4930cef6SMatthias Ringwald
442*4930cef6SMatthias Ringwalddef check_resampler(rng, dt, sr):
443*4930cef6SMatthias Ringwald
444*4930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
445*4930cef6SMatthias Ringwald    nt = (5 * T.SRATE_KHZ[sr]) // 4
446*4930cef6SMatthias Ringwald    ok = True
447*4930cef6SMatthias Ringwald
448*4930cef6SMatthias Ringwald    r = Resampler_12k8(dt, sr)
449*4930cef6SMatthias Ringwald
450*4930cef6SMatthias Ringwald    hp50_c = initial_hp50_state()
451*4930cef6SMatthias Ringwald    x_c = np.zeros(nt)
452*4930cef6SMatthias Ringwald    y_c = np.zeros(384)
453*4930cef6SMatthias Ringwald
454*4930cef6SMatthias Ringwald    for run in range(10):
455*4930cef6SMatthias Ringwald
456*4930cef6SMatthias Ringwald        x = ((2 * rng.random(ns)) - 1) * (2 ** 15 - 1)
457*4930cef6SMatthias Ringwald        y = r.resample(x)
458*4930cef6SMatthias Ringwald
459*4930cef6SMatthias Ringwald        x_c = np.append(x_c[-nt:], x.astype(np.int16))
460*4930cef6SMatthias Ringwald        y_c[:-r.n] = y_c[r.n:]
461*4930cef6SMatthias Ringwald        y_c = lc3.ltpf_resample(dt, sr, hp50_c, x_c, y_c)
462*4930cef6SMatthias Ringwald
463*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(y_c[-r.d-r.n:] - y[:r.d+r.n]/2)) < 4
464*4930cef6SMatthias Ringwald
465*4930cef6SMatthias Ringwald    return ok
466*4930cef6SMatthias Ringwald
467*4930cef6SMatthias Ringwalddef check_resampler_appendix_c(dt):
468*4930cef6SMatthias Ringwald
469*4930cef6SMatthias Ringwald    sr = T.SRATE_16K
470*4930cef6SMatthias Ringwald    ok = True
471*4930cef6SMatthias Ringwald
472*4930cef6SMatthias Ringwald    nt = (5 * T.SRATE_KHZ[sr]) // 4
473*4930cef6SMatthias Ringwald    n  = [ 96, 128 ][dt]
474*4930cef6SMatthias Ringwald    k  = [ 44,  24 ][dt] + n
475*4930cef6SMatthias Ringwald
476*4930cef6SMatthias Ringwald    state = initial_hp50_state()
477*4930cef6SMatthias Ringwald
478*4930cef6SMatthias Ringwald    x = np.append(np.zeros(nt), C.X_PCM[dt][0])
479*4930cef6SMatthias Ringwald    y = np.zeros(384)
480*4930cef6SMatthias Ringwald    y = lc3.ltpf_resample(dt, sr, state, x, y)
481*4930cef6SMatthias Ringwald    u = y[-k:len(C.X_TILDE_12K8D[dt][0])-k]
482*4930cef6SMatthias Ringwald
483*4930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[dt][0]/2)) < 2
484*4930cef6SMatthias Ringwald
485*4930cef6SMatthias Ringwald    x = np.append(x[-nt:], C.X_PCM[dt][1])
486*4930cef6SMatthias Ringwald    y[:-n] = y[n:]
487*4930cef6SMatthias Ringwald    y = lc3.ltpf_resample(dt, sr, state, x, y)
488*4930cef6SMatthias Ringwald    u = y[-k:len(C.X_TILDE_12K8D[dt][1])-k]
489*4930cef6SMatthias Ringwald
490*4930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[dt][1]/2)) < 2
491*4930cef6SMatthias Ringwald
492*4930cef6SMatthias Ringwald    return ok
493*4930cef6SMatthias Ringwald
494*4930cef6SMatthias Ringwalddef check_analysis(rng, dt, sr):
495*4930cef6SMatthias Ringwald
496*4930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
497*4930cef6SMatthias Ringwald    nt = (5 * T.SRATE_KHZ[sr]) // 4
498*4930cef6SMatthias Ringwald    ok = True
499*4930cef6SMatthias Ringwald
500*4930cef6SMatthias Ringwald    state_c = initial_state()
501*4930cef6SMatthias Ringwald    x_c = np.zeros(ns+nt)
502*4930cef6SMatthias Ringwald
503*4930cef6SMatthias Ringwald    ltpf = LtpfAnalysis(dt, sr)
504*4930cef6SMatthias Ringwald
505*4930cef6SMatthias Ringwald    t = np.arange(100 * ns) / (T.SRATE_KHZ[sr] * 1000)
506*4930cef6SMatthias Ringwald    s = signal.chirp(t, f0=10, f1=3e3, t1=t[-1], method='logarithmic')
507*4930cef6SMatthias Ringwald
508*4930cef6SMatthias Ringwald    for i in range(20):
509*4930cef6SMatthias Ringwald
510*4930cef6SMatthias Ringwald        x = s[i*ns:(i+1)*ns] * (2 ** 15 - 1)
511*4930cef6SMatthias Ringwald
512*4930cef6SMatthias Ringwald        pitch_present = ltpf.run(x)
513*4930cef6SMatthias Ringwald        data = ltpf.get_data()
514*4930cef6SMatthias Ringwald
515*4930cef6SMatthias Ringwald        x_c = np.append(x_c[-nt:], x.astype(np.int16))
516*4930cef6SMatthias Ringwald        (pitch_present_c, data_c) = lc3.ltpf_analyse(dt, sr, state_c, x_c)
517*4930cef6SMatthias Ringwald
518*4930cef6SMatthias Ringwald        ok = ok and (not pitch_present or state_c['tc'] == ltpf.tc)
519*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(state_c['nc'][0] - ltpf.nc[0])) < 1e-2
520*4930cef6SMatthias Ringwald        ok = ok and pitch_present_c == pitch_present
521*4930cef6SMatthias Ringwald        ok = ok and data_c['active'] == data['active']
522*4930cef6SMatthias Ringwald        ok = ok and data_c['pitch_index'] == data['pitch_index']
523*4930cef6SMatthias Ringwald        ok = ok and lc3.ltpf_get_nbits(pitch_present) == ltpf.get_nbits()
524*4930cef6SMatthias Ringwald
525*4930cef6SMatthias Ringwald    return ok
526*4930cef6SMatthias Ringwald
527*4930cef6SMatthias Ringwalddef check_synthesis(rng, dt, sr):
528*4930cef6SMatthias Ringwald
529*4930cef6SMatthias Ringwald    ok = True
530*4930cef6SMatthias Ringwald
531*4930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
532*4930cef6SMatthias Ringwald    nd = 18 * T.SRATE_KHZ[sr]
533*4930cef6SMatthias Ringwald
534*4930cef6SMatthias Ringwald    synthesis = LtpfSynthesis(dt, sr)
535*4930cef6SMatthias Ringwald
536*4930cef6SMatthias Ringwald    state_c = initial_sstate()
537*4930cef6SMatthias Ringwald    x_c = np.zeros(nd+ns)
538*4930cef6SMatthias Ringwald
539*4930cef6SMatthias Ringwald    for i in range(50):
540*4930cef6SMatthias Ringwald        pitch_present = bool(rng.integers(0, 10) >= 1)
541*4930cef6SMatthias Ringwald        if not pitch_present:
542*4930cef6SMatthias Ringwald            synthesis.disable()
543*4930cef6SMatthias Ringwald        else:
544*4930cef6SMatthias Ringwald            synthesis.active[0] = bool(rng.integers(0, 5) >= 1)
545*4930cef6SMatthias Ringwald            synthesis.pitch_index = rng.integers(0, 512)
546*4930cef6SMatthias Ringwald
547*4930cef6SMatthias Ringwald        data_c = None if not pitch_present else \
548*4930cef6SMatthias Ringwald            { 'active' : synthesis.active[0],
549*4930cef6SMatthias Ringwald              'pitch_index' : synthesis.pitch_index }
550*4930cef6SMatthias Ringwald
551*4930cef6SMatthias Ringwald        x = rng.random(ns) * 1e4
552*4930cef6SMatthias Ringwald        nbytes = rng.integers(10*(2+sr), 10*(6+sr))
553*4930cef6SMatthias Ringwald
554*4930cef6SMatthias Ringwald        x_c[:nd] = x_c[ns:]
555*4930cef6SMatthias Ringwald        x_c[nd:] = x
556*4930cef6SMatthias Ringwald
557*4930cef6SMatthias Ringwald        y = synthesis.run(x, nbytes)
558*4930cef6SMatthias Ringwald        x_c = lc3.ltpf_synthesize(dt, sr, nbytes, state_c, data_c, x_c)
559*4930cef6SMatthias Ringwald
560*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(x_c[nd:] - y)) < 1e-2
561*4930cef6SMatthias Ringwald
562*4930cef6SMatthias Ringwald    return ok
563*4930cef6SMatthias Ringwald
564*4930cef6SMatthias Ringwalddef check_analysis_appendix_c(dt):
565*4930cef6SMatthias Ringwald
566*4930cef6SMatthias Ringwald    sr = T.SRATE_16K
567*4930cef6SMatthias Ringwald    nt = (5 * T.SRATE_KHZ[sr]) // 4
568*4930cef6SMatthias Ringwald    ok = True
569*4930cef6SMatthias Ringwald
570*4930cef6SMatthias Ringwald    state = initial_state()
571*4930cef6SMatthias Ringwald
572*4930cef6SMatthias Ringwald    x = np.append(np.zeros(nt), C.X_PCM[dt][0])
573*4930cef6SMatthias Ringwald    (pitch_present, data) = lc3.ltpf_analyse(dt, sr, state, x)
574*4930cef6SMatthias Ringwald
575*4930cef6SMatthias Ringwald    ok = ok and C.T_CURR[dt][0] - state['tc'] == 17
576*4930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[dt][0])) < 1e-5
577*4930cef6SMatthias Ringwald    ok = ok and pitch_present == C.PITCH_PRESENT[dt][0]
578*4930cef6SMatthias Ringwald    ok = ok and data['pitch_index'] == C.PITCH_INDEX[dt][0]
579*4930cef6SMatthias Ringwald    ok = ok and data['active'] == C.LTPF_ACTIVE[dt][0]
580*4930cef6SMatthias Ringwald
581*4930cef6SMatthias Ringwald    x = np.append(x[-nt:], C.X_PCM[dt][1])
582*4930cef6SMatthias Ringwald    (pitch_present, data) = lc3.ltpf_analyse(dt, sr, state, x)
583*4930cef6SMatthias Ringwald
584*4930cef6SMatthias Ringwald    ok = ok and C.T_CURR[dt][1] - state['tc'] == 17
585*4930cef6SMatthias Ringwald    ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[dt][1])) < 1e-5
586*4930cef6SMatthias Ringwald    ok = ok and pitch_present == C.PITCH_PRESENT[dt][1]
587*4930cef6SMatthias Ringwald    ok = ok and data['pitch_index'] == C.PITCH_INDEX[dt][1]
588*4930cef6SMatthias Ringwald    ok = ok and data['active'] == C.LTPF_ACTIVE[dt][1]
589*4930cef6SMatthias Ringwald
590*4930cef6SMatthias Ringwald    return ok
591*4930cef6SMatthias Ringwald
592*4930cef6SMatthias Ringwalddef check_synthesis_appendix_c(dt):
593*4930cef6SMatthias Ringwald
594*4930cef6SMatthias Ringwald    sr = T.SRATE_16K
595*4930cef6SMatthias Ringwald    ok = True
596*4930cef6SMatthias Ringwald
597*4930cef6SMatthias Ringwald    if dt != T.DT_10M:
598*4930cef6SMatthias Ringwald        return ok
599*4930cef6SMatthias Ringwald
600*4930cef6SMatthias Ringwald    ns = T.NS[dt][sr]
601*4930cef6SMatthias Ringwald    nd = 18 * T.SRATE_KHZ[sr]
602*4930cef6SMatthias Ringwald
603*4930cef6SMatthias Ringwald    NBYTES = [ C.LTPF_C2_NBITS // 8, C.LTPF_C3_NBITS // 8,
604*4930cef6SMatthias Ringwald               C.LTPF_C4_NBITS // 8, C.LTPF_C5_NBITS // 8 ]
605*4930cef6SMatthias Ringwald
606*4930cef6SMatthias Ringwald    ACTIVE = [ C.LTPF_C2_ACTIVE, C.LTPF_C3_ACTIVE,
607*4930cef6SMatthias Ringwald               C.LTPF_C4_ACTIVE, C.LTPF_C5_ACTIVE ]
608*4930cef6SMatthias Ringwald
609*4930cef6SMatthias Ringwald    PITCH_INDEX = [ C.LTPF_C2_PITCH_INDEX, C.LTPF_C3_PITCH_INDEX,
610*4930cef6SMatthias Ringwald                    C.LTPF_C4_PITCH_INDEX, C.LTPF_C5_PITCH_INDEX ]
611*4930cef6SMatthias Ringwald
612*4930cef6SMatthias Ringwald    X = [ C.LTPF_C2_X, C.LTPF_C3_X,
613*4930cef6SMatthias Ringwald          C.LTPF_C4_X, C.LTPF_C5_X ]
614*4930cef6SMatthias Ringwald
615*4930cef6SMatthias Ringwald    PREV = [ C.LTPF_C2_PREV, C.LTPF_C3_PREV,
616*4930cef6SMatthias Ringwald             C.LTPF_C4_PREV, C.LTPF_C5_PREV  ]
617*4930cef6SMatthias Ringwald
618*4930cef6SMatthias Ringwald    TRANS = [ C.LTPF_C2_TRANS, C.LTPF_C3_TRANS,
619*4930cef6SMatthias Ringwald              C.LTPF_C4_TRANS, C.LTPF_C5_TRANS ]
620*4930cef6SMatthias Ringwald
621*4930cef6SMatthias Ringwald    for i in range(4):
622*4930cef6SMatthias Ringwald
623*4930cef6SMatthias Ringwald        state = initial_sstate()
624*4930cef6SMatthias Ringwald        nbytes = NBYTES[i]
625*4930cef6SMatthias Ringwald
626*4930cef6SMatthias Ringwald        data = { 'active' : ACTIVE[i][0], 'pitch_index' : PITCH_INDEX[i][0] }
627*4930cef6SMatthias Ringwald        x = np.append(np.zeros(nd), X[i][0])
628*4930cef6SMatthias Ringwald
629*4930cef6SMatthias Ringwald        lc3.ltpf_synthesize(dt, sr, nbytes, state, data, x)
630*4930cef6SMatthias Ringwald
631*4930cef6SMatthias Ringwald        data = { 'active' : ACTIVE[i][1], 'pitch_index' : PITCH_INDEX[i][1] }
632*4930cef6SMatthias Ringwald        x[  :nd-ns] = PREV[i][0][-nd+ns:]
633*4930cef6SMatthias Ringwald        x[nd-ns:nd] = PREV[i][1]
634*4930cef6SMatthias Ringwald        x[nd:nd+ns] = X[i][1]
635*4930cef6SMatthias Ringwald
636*4930cef6SMatthias Ringwald        y = lc3.ltpf_synthesize(dt, sr, nbytes, state, data, x)[nd:]
637*4930cef6SMatthias Ringwald
638*4930cef6SMatthias Ringwald        ok = ok and np.amax(np.abs(y - TRANS[i])) < 1e-3
639*4930cef6SMatthias Ringwald
640*4930cef6SMatthias Ringwald    return ok
641*4930cef6SMatthias Ringwald
642*4930cef6SMatthias Ringwalddef check():
643*4930cef6SMatthias Ringwald
644*4930cef6SMatthias Ringwald    rng = np.random.default_rng(1234)
645*4930cef6SMatthias Ringwald    ok = True
646*4930cef6SMatthias Ringwald
647*4930cef6SMatthias Ringwald    for dt in range(T.NUM_DT):
648*4930cef6SMatthias Ringwald        for sr in range(T.NUM_SRATE):
649*4930cef6SMatthias Ringwald            ok = ok and check_resampler(rng, dt, sr)
650*4930cef6SMatthias Ringwald            ok = ok and check_analysis(rng, dt, sr)
651*4930cef6SMatthias Ringwald            ok = ok and check_synthesis(rng, dt, sr)
652*4930cef6SMatthias Ringwald
653*4930cef6SMatthias Ringwald    for dt in range(T.NUM_DT):
654*4930cef6SMatthias Ringwald        ok = ok and check_resampler_appendix_c(dt)
655*4930cef6SMatthias Ringwald        ok = ok and check_analysis_appendix_c(dt)
656*4930cef6SMatthias Ringwald        ok = ok and check_synthesis_appendix_c(dt)
657*4930cef6SMatthias Ringwald
658*4930cef6SMatthias Ringwald    return ok
659*4930cef6SMatthias Ringwald
660*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ###
661