xref: /aosp_15_r20/external/liblc3/test/spec.py (revision 49fe348c0058011ee60b6957cdd9d52742df84bc)
1*49fe348cSAndroid Build Coastguard Worker#
2*49fe348cSAndroid Build Coastguard Worker# Copyright 2022 Google LLC
3*49fe348cSAndroid Build Coastguard Worker#
4*49fe348cSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*49fe348cSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*49fe348cSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*49fe348cSAndroid Build Coastguard Worker#
8*49fe348cSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
9*49fe348cSAndroid Build Coastguard Worker#
10*49fe348cSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*49fe348cSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*49fe348cSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*49fe348cSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*49fe348cSAndroid Build Coastguard Worker# limitations under the License.
15*49fe348cSAndroid Build Coastguard Worker#
16*49fe348cSAndroid Build Coastguard Worker
17*49fe348cSAndroid Build Coastguard Workerimport numpy as np
18*49fe348cSAndroid Build Coastguard Worker
19*49fe348cSAndroid Build Coastguard Workerimport lc3
20*49fe348cSAndroid Build Coastguard Workerimport tables as T, appendix_c as C
21*49fe348cSAndroid Build Coastguard Worker
22*49fe348cSAndroid Build Coastguard Workerimport bwdet as m_bwdet
23*49fe348cSAndroid Build Coastguard Workerimport ltpf as m_ltpf
24*49fe348cSAndroid Build Coastguard Workerimport sns as m_sns
25*49fe348cSAndroid Build Coastguard Workerimport tns as m_tns
26*49fe348cSAndroid Build Coastguard Worker
27*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ###
28*49fe348cSAndroid Build Coastguard Worker
29*49fe348cSAndroid Build Coastguard Workerclass SpectrumQuantization:
30*49fe348cSAndroid Build Coastguard Worker
31*49fe348cSAndroid Build Coastguard Worker    def __init__(self, dt, sr):
32*49fe348cSAndroid Build Coastguard Worker
33*49fe348cSAndroid Build Coastguard Worker        self.dt = dt
34*49fe348cSAndroid Build Coastguard Worker        self.sr = sr
35*49fe348cSAndroid Build Coastguard Worker
36*49fe348cSAndroid Build Coastguard Worker    def get_gain_offset(self, nbytes):
37*49fe348cSAndroid Build Coastguard Worker
38*49fe348cSAndroid Build Coastguard Worker        sr_ind = self.sr if self.sr < T.SRATE_48K_HR \
39*49fe348cSAndroid Build Coastguard Worker            else 4 + (self.sr - T.SRATE_48K_HR)
40*49fe348cSAndroid Build Coastguard Worker
41*49fe348cSAndroid Build Coastguard Worker        g_off = (nbytes * 8) // (10 * (1 + sr_ind))
42*49fe348cSAndroid Build Coastguard Worker        g_off = -min(115, g_off) - (105 + 5*(1 + sr_ind))
43*49fe348cSAndroid Build Coastguard Worker        if self.sr >= T.SRATE_48K_HR:
44*49fe348cSAndroid Build Coastguard Worker            g_off = max(g_off, -181)
45*49fe348cSAndroid Build Coastguard Worker
46*49fe348cSAndroid Build Coastguard Worker        return g_off
47*49fe348cSAndroid Build Coastguard Worker
48*49fe348cSAndroid Build Coastguard Worker    def get_noise_indices(self, bw, xq, lastnz):
49*49fe348cSAndroid Build Coastguard Worker
50*49fe348cSAndroid Build Coastguard Worker        nf_start = [  6, 12, 18, 24 ][self.dt]
51*49fe348cSAndroid Build Coastguard Worker        nf_width = [  1,  1,  2,  3 ][self.dt]
52*49fe348cSAndroid Build Coastguard Worker
53*49fe348cSAndroid Build Coastguard Worker        bw_stop = T.I[self.dt][min(bw, T.SRATE_48K)][-1]
54*49fe348cSAndroid Build Coastguard Worker
55*49fe348cSAndroid Build Coastguard Worker        xq = np.append(xq[:lastnz], np.zeros(len(xq) - lastnz))
56*49fe348cSAndroid Build Coastguard Worker        xq[:nf_start-nf_width] = 1
57*49fe348cSAndroid Build Coastguard Worker
58*49fe348cSAndroid Build Coastguard Worker        return [ np.all(xq[max(k-nf_width, 0):min(k+nf_width+1, bw_stop)] == 0)
59*49fe348cSAndroid Build Coastguard Worker                    for k in range(bw_stop) ]
60*49fe348cSAndroid Build Coastguard Worker
61*49fe348cSAndroid Build Coastguard Workerclass SpectrumAnalysis(SpectrumQuantization):
62*49fe348cSAndroid Build Coastguard Worker
63*49fe348cSAndroid Build Coastguard Worker    def __init__(self, dt, sr):
64*49fe348cSAndroid Build Coastguard Worker
65*49fe348cSAndroid Build Coastguard Worker        super().__init__(dt, sr)
66*49fe348cSAndroid Build Coastguard Worker
67*49fe348cSAndroid Build Coastguard Worker        self.reset_off  = 0
68*49fe348cSAndroid Build Coastguard Worker        self.nbits_off  = 0
69*49fe348cSAndroid Build Coastguard Worker        self.nbits_spec = 0
70*49fe348cSAndroid Build Coastguard Worker        self.nbits_est  = 0
71*49fe348cSAndroid Build Coastguard Worker
72*49fe348cSAndroid Build Coastguard Worker        (self.g_idx, self.noise_factor, self.xq, self.lastnz,
73*49fe348cSAndroid Build Coastguard Worker                self.nbits_residual_max, self.xg) = \
74*49fe348cSAndroid Build Coastguard Worker            (None, None, None, None, None, None)
75*49fe348cSAndroid Build Coastguard Worker
76*49fe348cSAndroid Build Coastguard Worker    def estimate_gain(self, x, nbytes, nbits_spec, nbits_off, g_off):
77*49fe348cSAndroid Build Coastguard Worker
78*49fe348cSAndroid Build Coastguard Worker        nbits = int(nbits_spec + nbits_off + 0.5)
79*49fe348cSAndroid Build Coastguard Worker
80*49fe348cSAndroid Build Coastguard Worker        ### Energy (dB) by 4 MDCT coefficients
81*49fe348cSAndroid Build Coastguard Worker
82*49fe348cSAndroid Build Coastguard Worker        hr = (self.sr >= T.SRATE_48K_HR)
83*49fe348cSAndroid Build Coastguard Worker        nf = 0
84*49fe348cSAndroid Build Coastguard Worker
85*49fe348cSAndroid Build Coastguard Worker        if hr:
86*49fe348cSAndroid Build Coastguard Worker            dt = self.dt
87*49fe348cSAndroid Build Coastguard Worker            sr = self.sr
88*49fe348cSAndroid Build Coastguard Worker
89*49fe348cSAndroid Build Coastguard Worker            dt_ms = T.DT_MS[dt]
90*49fe348cSAndroid Build Coastguard Worker            bitrate = (8 * nbytes / (dt_ms * 1e-3)).astype(int)
91*49fe348cSAndroid Build Coastguard Worker
92*49fe348cSAndroid Build Coastguard Worker            C = [ [ -6, 0, None, 2 ], [ -6, 0, None, 5 ] ]
93*49fe348cSAndroid Build Coastguard Worker
94*49fe348cSAndroid Build Coastguard Worker            reg_bits = np.clip(
95*49fe348cSAndroid Build Coastguard Worker                bitrate // 12500 + C[sr - T.SRATE_48K_HR][dt], 6, 23)
96*49fe348cSAndroid Build Coastguard Worker
97*49fe348cSAndroid Build Coastguard Worker            M0 = np.sum(np.abs(x)) + 1e-5
98*49fe348cSAndroid Build Coastguard Worker            M1 = np.sum(np.arange(len(x)) * np.abs(x)) + 1e-5
99*49fe348cSAndroid Build Coastguard Worker
100*49fe348cSAndroid Build Coastguard Worker            low_bits = (4 / dt_ms) * (2*dt_ms - min(M0/M1, 2*dt_ms))
101*49fe348cSAndroid Build Coastguard Worker
102*49fe348cSAndroid Build Coastguard Worker            nf = np.max(np.abs(x)) * np.exp2(-reg_bits - low_bits)
103*49fe348cSAndroid Build Coastguard Worker
104*49fe348cSAndroid Build Coastguard Worker        e = [ np.sum(x[4*k:4*(k+1)] ** 2) for k in range(len(x) // 4) ]
105*49fe348cSAndroid Build Coastguard Worker        e = 10 * np.log10(2**-31 + np.array(e) + nf)
106*49fe348cSAndroid Build Coastguard Worker
107*49fe348cSAndroid Build Coastguard Worker        ### Compute gain index
108*49fe348cSAndroid Build Coastguard Worker
109*49fe348cSAndroid Build Coastguard Worker        g_idx = 255
110*49fe348cSAndroid Build Coastguard Worker
111*49fe348cSAndroid Build Coastguard Worker        for i in range(8):
112*49fe348cSAndroid Build Coastguard Worker            factor = 1 << (7 - i)
113*49fe348cSAndroid Build Coastguard Worker            g_idx -= factor
114*49fe348cSAndroid Build Coastguard Worker            tmp = 0
115*49fe348cSAndroid Build Coastguard Worker            iszero = 1
116*49fe348cSAndroid Build Coastguard Worker
117*49fe348cSAndroid Build Coastguard Worker            for ei in e[-1::-1]:
118*49fe348cSAndroid Build Coastguard Worker
119*49fe348cSAndroid Build Coastguard Worker                if ei * 28/20 < g_idx + g_off:
120*49fe348cSAndroid Build Coastguard Worker                    if iszero == 0:
121*49fe348cSAndroid Build Coastguard Worker                        tmp += 2.7*28/20
122*49fe348cSAndroid Build Coastguard Worker                else:
123*49fe348cSAndroid Build Coastguard Worker                    if g_idx + g_off < (ei - 43) * 28/20:
124*49fe348cSAndroid Build Coastguard Worker                        tmp += 2*ei*28/20 - 2*(g_idx + g_off) - 36*28/20
125*49fe348cSAndroid Build Coastguard Worker                    else:
126*49fe348cSAndroid Build Coastguard Worker                        tmp += ei*28/20 - (g_idx + g_off) + 7*28/20
127*49fe348cSAndroid Build Coastguard Worker                    iszero = 0
128*49fe348cSAndroid Build Coastguard Worker
129*49fe348cSAndroid Build Coastguard Worker            if tmp > nbits * 1.4 * 28/20 and iszero == 0:
130*49fe348cSAndroid Build Coastguard Worker                g_idx += factor
131*49fe348cSAndroid Build Coastguard Worker
132*49fe348cSAndroid Build Coastguard Worker        ### Limit gain index
133*49fe348cSAndroid Build Coastguard Worker
134*49fe348cSAndroid Build Coastguard Worker        x_max = np.amax(np.abs(x))
135*49fe348cSAndroid Build Coastguard Worker        if x_max > 0:
136*49fe348cSAndroid Build Coastguard Worker            x_lim = [ 2**15 - 0.375,  2**23 ][hr]
137*49fe348cSAndroid Build Coastguard Worker            g_min = 28 * np.log10(x_max / x_lim)
138*49fe348cSAndroid Build Coastguard Worker            g_min = np.ceil(g_min).astype(int) - g_off
139*49fe348cSAndroid Build Coastguard Worker            reset_off = g_idx < g_min
140*49fe348cSAndroid Build Coastguard Worker        else:
141*49fe348cSAndroid Build Coastguard Worker            g_min = 0
142*49fe348cSAndroid Build Coastguard Worker            reset_off = True
143*49fe348cSAndroid Build Coastguard Worker
144*49fe348cSAndroid Build Coastguard Worker        if reset_off:
145*49fe348cSAndroid Build Coastguard Worker            g_idx = g_min
146*49fe348cSAndroid Build Coastguard Worker
147*49fe348cSAndroid Build Coastguard Worker        return (g_min, g_idx + g_off, reset_off)
148*49fe348cSAndroid Build Coastguard Worker
149*49fe348cSAndroid Build Coastguard Worker    def quantize(self, g_int, x):
150*49fe348cSAndroid Build Coastguard Worker
151*49fe348cSAndroid Build Coastguard Worker        xg = x / 10 ** (g_int / 28)
152*49fe348cSAndroid Build Coastguard Worker
153*49fe348cSAndroid Build Coastguard Worker        hr = (self.sr >= T.SRATE_48K_HR)
154*49fe348cSAndroid Build Coastguard Worker        offset = [ 0.375, 0.5 ][hr]
155*49fe348cSAndroid Build Coastguard Worker        xq_min = [ -(2**15)  , -(2**23)   ][hr]
156*49fe348cSAndroid Build Coastguard Worker        xq_max = [  (2**15)-1,  (2**23)-1 ][hr]
157*49fe348cSAndroid Build Coastguard Worker
158*49fe348cSAndroid Build Coastguard Worker        xq = np.where(xg < 0, np.ceil(xg - offset), np.floor(xg + offset))
159*49fe348cSAndroid Build Coastguard Worker        xq = xq.astype(np.int32)
160*49fe348cSAndroid Build Coastguard Worker        xq = np.fmin(np.fmax(xq, xq_min), xq_max)
161*49fe348cSAndroid Build Coastguard Worker
162*49fe348cSAndroid Build Coastguard Worker        nz_pairs = np.any([ xq[::2] != 0, xq[1::2] != 0 ], axis=0)
163*49fe348cSAndroid Build Coastguard Worker        lastnz = len(xq) - 2 * np.argmax(nz_pairs[-1::-1])
164*49fe348cSAndroid Build Coastguard Worker        if not np.any(nz_pairs):
165*49fe348cSAndroid Build Coastguard Worker            lastnz = 0
166*49fe348cSAndroid Build Coastguard Worker
167*49fe348cSAndroid Build Coastguard Worker        return (xg, xq, lastnz)
168*49fe348cSAndroid Build Coastguard Worker
169*49fe348cSAndroid Build Coastguard Worker    def compute_nbits(self, nbytes, x, lastnz, nbits_spec):
170*49fe348cSAndroid Build Coastguard Worker
171*49fe348cSAndroid Build Coastguard Worker        mode = [ 0,   1 ][int(self.sr < T.SRATE_96K_HR and \
172*49fe348cSAndroid Build Coastguard Worker                              nbytes >= 20 * (3 + min(self.sr, T.SRATE_48K)))]
173*49fe348cSAndroid Build Coastguard Worker        rate = [ 0, 512 ][int(self.sr < T.SRATE_96K_HR and \
174*49fe348cSAndroid Build Coastguard Worker                              nbytes >  20 * (1 + min(self.sr, T.SRATE_48K)))]
175*49fe348cSAndroid Build Coastguard Worker
176*49fe348cSAndroid Build Coastguard Worker        nbits_est = 0
177*49fe348cSAndroid Build Coastguard Worker        nbits_trunc = 0
178*49fe348cSAndroid Build Coastguard Worker        nbits_lsb = 0
179*49fe348cSAndroid Build Coastguard Worker        lastnz_trunc = 2
180*49fe348cSAndroid Build Coastguard Worker        c = 0
181*49fe348cSAndroid Build Coastguard Worker
182*49fe348cSAndroid Build Coastguard Worker        for n in range(0, lastnz, 2):
183*49fe348cSAndroid Build Coastguard Worker            t = c + rate
184*49fe348cSAndroid Build Coastguard Worker            if n > len(x) // 2:
185*49fe348cSAndroid Build Coastguard Worker                t += 256
186*49fe348cSAndroid Build Coastguard Worker
187*49fe348cSAndroid Build Coastguard Worker            a = abs(x[n  ])
188*49fe348cSAndroid Build Coastguard Worker            b = abs(x[n+1])
189*49fe348cSAndroid Build Coastguard Worker            lev = 0
190*49fe348cSAndroid Build Coastguard Worker            while max(a, b) >= 4:
191*49fe348cSAndroid Build Coastguard Worker                nbits_est += \
192*49fe348cSAndroid Build Coastguard Worker                    T.AC_SPEC_BITS[T.AC_SPEC_LOOKUP[t + lev*1024]][16];
193*49fe348cSAndroid Build Coastguard Worker                if lev == 0 and mode == 1:
194*49fe348cSAndroid Build Coastguard Worker                    nbits_lsb += 2
195*49fe348cSAndroid Build Coastguard Worker                else:
196*49fe348cSAndroid Build Coastguard Worker                    nbits_est += 2 * 2048
197*49fe348cSAndroid Build Coastguard Worker
198*49fe348cSAndroid Build Coastguard Worker                a >>= 1
199*49fe348cSAndroid Build Coastguard Worker                b >>= 1
200*49fe348cSAndroid Build Coastguard Worker                lev = min(lev + 1, 3)
201*49fe348cSAndroid Build Coastguard Worker
202*49fe348cSAndroid Build Coastguard Worker            nbits_est += \
203*49fe348cSAndroid Build Coastguard Worker                T.AC_SPEC_BITS[T.AC_SPEC_LOOKUP[t + lev*1024]][a + 4*b]
204*49fe348cSAndroid Build Coastguard Worker
205*49fe348cSAndroid Build Coastguard Worker            a_lsb = abs(x[n  ])
206*49fe348cSAndroid Build Coastguard Worker            b_lsb = abs(x[n+1])
207*49fe348cSAndroid Build Coastguard Worker            nbits_est += (min(a_lsb, 1) + min(b_lsb, 1)) * 2048
208*49fe348cSAndroid Build Coastguard Worker            if lev > 0 and mode == 1:
209*49fe348cSAndroid Build Coastguard Worker                a_lsb >>= 1;
210*49fe348cSAndroid Build Coastguard Worker                b_lsb >>= 1;
211*49fe348cSAndroid Build Coastguard Worker                nbits_lsb += int(a_lsb == 0 and x[n  ] != 0)
212*49fe348cSAndroid Build Coastguard Worker                nbits_lsb += int(b_lsb == 0 and x[n+1] != 0)
213*49fe348cSAndroid Build Coastguard Worker
214*49fe348cSAndroid Build Coastguard Worker            if (x[n] != 0 or x[n+1] != 0) and \
215*49fe348cSAndroid Build Coastguard Worker                    (nbits_est <= nbits_spec * 2048):
216*49fe348cSAndroid Build Coastguard Worker                lastnz_trunc = n + 2;
217*49fe348cSAndroid Build Coastguard Worker                nbits_trunc = nbits_est
218*49fe348cSAndroid Build Coastguard Worker
219*49fe348cSAndroid Build Coastguard Worker            t = 1 + (a + b) * (lev + 1) if lev <= 1 else 12 + lev;
220*49fe348cSAndroid Build Coastguard Worker            c = (c & 15) * 16 + t;
221*49fe348cSAndroid Build Coastguard Worker
222*49fe348cSAndroid Build Coastguard Worker        nbits_est = (nbits_est + 2047) // 2048 + nbits_lsb;
223*49fe348cSAndroid Build Coastguard Worker        nbits_trunc = (nbits_trunc + 2047) // 2048
224*49fe348cSAndroid Build Coastguard Worker
225*49fe348cSAndroid Build Coastguard Worker        self.rate = rate
226*49fe348cSAndroid Build Coastguard Worker        self.lsb_mode = mode == 1 and nbits_est > nbits_spec
227*49fe348cSAndroid Build Coastguard Worker
228*49fe348cSAndroid Build Coastguard Worker        return (nbits_est, nbits_trunc, lastnz_trunc, self.lsb_mode)
229*49fe348cSAndroid Build Coastguard Worker
230*49fe348cSAndroid Build Coastguard Worker    def adjust_gain(self, g_idx, nbits, nbits_spec):
231*49fe348cSAndroid Build Coastguard Worker
232*49fe348cSAndroid Build Coastguard Worker        T1 = [  80,  230,  380,  530,  680,  680,  830 ]
233*49fe348cSAndroid Build Coastguard Worker        T2 = [ 500, 1025, 1550, 2075, 2600, 2600, 3125 ]
234*49fe348cSAndroid Build Coastguard Worker        T3 = [ 850, 1700, 2550, 3400, 4250, 4250, 5100 ]
235*49fe348cSAndroid Build Coastguard Worker
236*49fe348cSAndroid Build Coastguard Worker        dt = self.dt
237*49fe348cSAndroid Build Coastguard Worker        sr = self.sr
238*49fe348cSAndroid Build Coastguard Worker
239*49fe348cSAndroid Build Coastguard Worker        if nbits < T1[sr]:
240*49fe348cSAndroid Build Coastguard Worker            delta = (nbits + 48) / 16
241*49fe348cSAndroid Build Coastguard Worker
242*49fe348cSAndroid Build Coastguard Worker        elif nbits < T2[sr]:
243*49fe348cSAndroid Build Coastguard Worker            a = T1[sr] / 16 + 3
244*49fe348cSAndroid Build Coastguard Worker            b = T2[sr] / 48
245*49fe348cSAndroid Build Coastguard Worker            delta = a + (nbits - T1[sr]) * (b - a) / (T2[sr] - T1[sr])
246*49fe348cSAndroid Build Coastguard Worker
247*49fe348cSAndroid Build Coastguard Worker        elif nbits < T3[sr]:
248*49fe348cSAndroid Build Coastguard Worker            delta = nbits / 48
249*49fe348cSAndroid Build Coastguard Worker
250*49fe348cSAndroid Build Coastguard Worker        else:
251*49fe348cSAndroid Build Coastguard Worker            delta = T3[sr] / 48;
252*49fe348cSAndroid Build Coastguard Worker
253*49fe348cSAndroid Build Coastguard Worker        delta = np.fix(delta + 0.5).astype(int)
254*49fe348cSAndroid Build Coastguard Worker
255*49fe348cSAndroid Build Coastguard Worker        if self.sr >= T.SRATE_48K_HR and \
256*49fe348cSAndroid Build Coastguard Worker            (g_idx < 255 and nbits > nbits_spec):
257*49fe348cSAndroid Build Coastguard Worker
258*49fe348cSAndroid Build Coastguard Worker            factor = [ 3 + (nbits >= 520), 2, 0, 1 ][dt]
259*49fe348cSAndroid Build Coastguard Worker            g_incr = int(factor * (1 + (nbits - nbits_spec) / delta))
260*49fe348cSAndroid Build Coastguard Worker            return min(g_idx + g_incr, 255) - g_idx;
261*49fe348cSAndroid Build Coastguard Worker
262*49fe348cSAndroid Build Coastguard Worker        elif self.sr < T.SRATE_48K_HR and \
263*49fe348cSAndroid Build Coastguard Worker            ( (g_idx < 255 and nbits > nbits_spec) or \
264*49fe348cSAndroid Build Coastguard Worker              (g_idx >   0 and nbits < nbits_spec - (delta + 2)) ):
265*49fe348cSAndroid Build Coastguard Worker
266*49fe348cSAndroid Build Coastguard Worker            if nbits < nbits_spec - (delta + 2):
267*49fe348cSAndroid Build Coastguard Worker                return -1
268*49fe348cSAndroid Build Coastguard Worker
269*49fe348cSAndroid Build Coastguard Worker            if g_idx == 254 or nbits < nbits_spec + delta:
270*49fe348cSAndroid Build Coastguard Worker                return 1
271*49fe348cSAndroid Build Coastguard Worker
272*49fe348cSAndroid Build Coastguard Worker            else:
273*49fe348cSAndroid Build Coastguard Worker                return 2
274*49fe348cSAndroid Build Coastguard Worker
275*49fe348cSAndroid Build Coastguard Worker        return 0
276*49fe348cSAndroid Build Coastguard Worker
277*49fe348cSAndroid Build Coastguard Worker    def estimate_noise(self, bw, xq, lastnz, x):
278*49fe348cSAndroid Build Coastguard Worker
279*49fe348cSAndroid Build Coastguard Worker        i_nf = self.get_noise_indices(bw, xq, lastnz)
280*49fe348cSAndroid Build Coastguard Worker        l_nf = sum(abs(x[:len(i_nf)] * i_nf)) / sum(i_nf) \
281*49fe348cSAndroid Build Coastguard Worker            if sum(i_nf) > 0 else 0
282*49fe348cSAndroid Build Coastguard Worker
283*49fe348cSAndroid Build Coastguard Worker        return min(max(np.rint(8 - 16 * l_nf).astype(int), 0), 7)
284*49fe348cSAndroid Build Coastguard Worker
285*49fe348cSAndroid Build Coastguard Worker    def run(self, bw, nbytes, nbits_bw, nbits_ltpf, nbits_sns, nbits_tns, x):
286*49fe348cSAndroid Build Coastguard Worker
287*49fe348cSAndroid Build Coastguard Worker        sr = self.sr
288*49fe348cSAndroid Build Coastguard Worker
289*49fe348cSAndroid Build Coastguard Worker        ### Bit budget
290*49fe348cSAndroid Build Coastguard Worker
291*49fe348cSAndroid Build Coastguard Worker        hr = self.sr >= T.SRATE_48K_HR
292*49fe348cSAndroid Build Coastguard Worker
293*49fe348cSAndroid Build Coastguard Worker        nbits_gain = 8
294*49fe348cSAndroid Build Coastguard Worker        nbits_nf   = 3
295*49fe348cSAndroid Build Coastguard Worker
296*49fe348cSAndroid Build Coastguard Worker        nbits_ari  = np.ceil(np.log2(len(x) / 2)).astype(int)
297*49fe348cSAndroid Build Coastguard Worker        nbits_ari += 3 + int(hr) + min((8*nbytes - 1) // 1280, 2)
298*49fe348cSAndroid Build Coastguard Worker
299*49fe348cSAndroid Build Coastguard Worker        nbits_spec = 8*nbytes - \
300*49fe348cSAndroid Build Coastguard Worker            nbits_bw - nbits_ltpf - nbits_sns - nbits_tns - \
301*49fe348cSAndroid Build Coastguard Worker            nbits_gain - nbits_nf - nbits_ari
302*49fe348cSAndroid Build Coastguard Worker
303*49fe348cSAndroid Build Coastguard Worker        ### Global gain estimation
304*49fe348cSAndroid Build Coastguard Worker
305*49fe348cSAndroid Build Coastguard Worker        nbits_off = self.nbits_off + self.nbits_spec - self.nbits_est
306*49fe348cSAndroid Build Coastguard Worker        nbits_off = min(40, max(-40, nbits_off))
307*49fe348cSAndroid Build Coastguard Worker
308*49fe348cSAndroid Build Coastguard Worker        nbits_off = 0 if self.reset_off else \
309*49fe348cSAndroid Build Coastguard Worker                    0.8 * self.nbits_off + 0.2 * nbits_off
310*49fe348cSAndroid Build Coastguard Worker
311*49fe348cSAndroid Build Coastguard Worker        g_off = self.get_gain_offset(nbytes)
312*49fe348cSAndroid Build Coastguard Worker
313*49fe348cSAndroid Build Coastguard Worker        (g_min, g_int, self.reset_off) = \
314*49fe348cSAndroid Build Coastguard Worker            self.estimate_gain(x, nbytes, nbits_spec, nbits_off, g_off)
315*49fe348cSAndroid Build Coastguard Worker        self.nbits_off = nbits_off
316*49fe348cSAndroid Build Coastguard Worker        self.nbits_spec = nbits_spec
317*49fe348cSAndroid Build Coastguard Worker
318*49fe348cSAndroid Build Coastguard Worker        ### Quantization
319*49fe348cSAndroid Build Coastguard Worker
320*49fe348cSAndroid Build Coastguard Worker        (xg, xq, lastnz) = self.quantize(g_int, x)
321*49fe348cSAndroid Build Coastguard Worker
322*49fe348cSAndroid Build Coastguard Worker        (nbits_est, nbits_trunc, lastnz_trunc, _) = \
323*49fe348cSAndroid Build Coastguard Worker            self.compute_nbits(nbytes, xq, lastnz, nbits_spec)
324*49fe348cSAndroid Build Coastguard Worker
325*49fe348cSAndroid Build Coastguard Worker        self.nbits_est = nbits_est
326*49fe348cSAndroid Build Coastguard Worker
327*49fe348cSAndroid Build Coastguard Worker        ### Adjust gain and requantize
328*49fe348cSAndroid Build Coastguard Worker
329*49fe348cSAndroid Build Coastguard Worker        g_adj = self.adjust_gain(g_int - g_off, nbits_est, nbits_spec)
330*49fe348cSAndroid Build Coastguard Worker        g_adj = max(g_int + g_adj, g_min + g_off) - g_int
331*49fe348cSAndroid Build Coastguard Worker
332*49fe348cSAndroid Build Coastguard Worker        (xg, xq, lastnz) = self.quantize(g_adj, xg)
333*49fe348cSAndroid Build Coastguard Worker
334*49fe348cSAndroid Build Coastguard Worker        (nbits_est, nbits_trunc, lastnz_trunc, lsb_mode) = \
335*49fe348cSAndroid Build Coastguard Worker            self.compute_nbits(nbytes, xq, lastnz, nbits_spec)
336*49fe348cSAndroid Build Coastguard Worker
337*49fe348cSAndroid Build Coastguard Worker        self.g_idx = g_int + g_adj - g_off
338*49fe348cSAndroid Build Coastguard Worker        self.xq = xq
339*49fe348cSAndroid Build Coastguard Worker        self.lastnz = lastnz_trunc
340*49fe348cSAndroid Build Coastguard Worker
341*49fe348cSAndroid Build Coastguard Worker        self.nbits_residual_max = nbits_spec - nbits_trunc + 4
342*49fe348cSAndroid Build Coastguard Worker        self.xg = xg
343*49fe348cSAndroid Build Coastguard Worker
344*49fe348cSAndroid Build Coastguard Worker        ### Noise factor
345*49fe348cSAndroid Build Coastguard Worker
346*49fe348cSAndroid Build Coastguard Worker        self.noise_factor = self.estimate_noise(bw, xq, lastnz, x)
347*49fe348cSAndroid Build Coastguard Worker
348*49fe348cSAndroid Build Coastguard Worker        return (self.xq, self.lastnz, self.xg)
349*49fe348cSAndroid Build Coastguard Worker
350*49fe348cSAndroid Build Coastguard Worker    def store(self, b):
351*49fe348cSAndroid Build Coastguard Worker
352*49fe348cSAndroid Build Coastguard Worker        ne = T.I[self.dt][self.sr][-1]
353*49fe348cSAndroid Build Coastguard Worker        nbits_lastnz = np.ceil(np.log2(ne/2)).astype(int)
354*49fe348cSAndroid Build Coastguard Worker
355*49fe348cSAndroid Build Coastguard Worker        b.write_uint((self.lastnz >> 1) - 1, nbits_lastnz)
356*49fe348cSAndroid Build Coastguard Worker        b.write_uint(self.lsb_mode, 1)
357*49fe348cSAndroid Build Coastguard Worker        b.write_uint(self.g_idx, 8)
358*49fe348cSAndroid Build Coastguard Worker
359*49fe348cSAndroid Build Coastguard Worker    def encode(self, bits):
360*49fe348cSAndroid Build Coastguard Worker
361*49fe348cSAndroid Build Coastguard Worker        ### Noise factor
362*49fe348cSAndroid Build Coastguard Worker
363*49fe348cSAndroid Build Coastguard Worker        bits.write_uint(self.noise_factor, 3)
364*49fe348cSAndroid Build Coastguard Worker
365*49fe348cSAndroid Build Coastguard Worker        ### Quantized data
366*49fe348cSAndroid Build Coastguard Worker
367*49fe348cSAndroid Build Coastguard Worker        lsbs = []
368*49fe348cSAndroid Build Coastguard Worker
369*49fe348cSAndroid Build Coastguard Worker        x = self.xq
370*49fe348cSAndroid Build Coastguard Worker        c = 0
371*49fe348cSAndroid Build Coastguard Worker
372*49fe348cSAndroid Build Coastguard Worker        for n in range(0, self.lastnz, 2):
373*49fe348cSAndroid Build Coastguard Worker            t = c + self.rate
374*49fe348cSAndroid Build Coastguard Worker            if n > len(x) // 2:
375*49fe348cSAndroid Build Coastguard Worker                t += 256
376*49fe348cSAndroid Build Coastguard Worker
377*49fe348cSAndroid Build Coastguard Worker            a = abs(x[n  ])
378*49fe348cSAndroid Build Coastguard Worker            b = abs(x[n+1])
379*49fe348cSAndroid Build Coastguard Worker            lev = 0
380*49fe348cSAndroid Build Coastguard Worker            while max(a, b) >= 4:
381*49fe348cSAndroid Build Coastguard Worker
382*49fe348cSAndroid Build Coastguard Worker                bits.ac_encode(
383*49fe348cSAndroid Build Coastguard Worker                    T.AC_SPEC_CUMFREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][16],
384*49fe348cSAndroid Build Coastguard Worker                    T.AC_SPEC_FREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][16])
385*49fe348cSAndroid Build Coastguard Worker
386*49fe348cSAndroid Build Coastguard Worker                if lev == 0 and self.lsb_mode:
387*49fe348cSAndroid Build Coastguard Worker                    lsb_0 = a & 1
388*49fe348cSAndroid Build Coastguard Worker                    lsb_1 = b & 1
389*49fe348cSAndroid Build Coastguard Worker                else:
390*49fe348cSAndroid Build Coastguard Worker                    bits.write_bit(a & 1)
391*49fe348cSAndroid Build Coastguard Worker                    bits.write_bit(b & 1)
392*49fe348cSAndroid Build Coastguard Worker
393*49fe348cSAndroid Build Coastguard Worker                a >>= 1
394*49fe348cSAndroid Build Coastguard Worker                b >>= 1
395*49fe348cSAndroid Build Coastguard Worker                lev = min(lev + 1, 3)
396*49fe348cSAndroid Build Coastguard Worker
397*49fe348cSAndroid Build Coastguard Worker            bits.ac_encode(
398*49fe348cSAndroid Build Coastguard Worker                T.AC_SPEC_CUMFREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][a + 4*b],
399*49fe348cSAndroid Build Coastguard Worker                T.AC_SPEC_FREQ[T.AC_SPEC_LOOKUP[t + lev*1024]][a + 4*b])
400*49fe348cSAndroid Build Coastguard Worker
401*49fe348cSAndroid Build Coastguard Worker            a_lsb = abs(x[n  ])
402*49fe348cSAndroid Build Coastguard Worker            b_lsb = abs(x[n+1])
403*49fe348cSAndroid Build Coastguard Worker            if lev > 0 and self.lsb_mode:
404*49fe348cSAndroid Build Coastguard Worker                a_lsb >>= 1
405*49fe348cSAndroid Build Coastguard Worker                b_lsb >>= 1
406*49fe348cSAndroid Build Coastguard Worker
407*49fe348cSAndroid Build Coastguard Worker                lsbs.append(lsb_0)
408*49fe348cSAndroid Build Coastguard Worker                if a_lsb == 0 and x[n+0] != 0:
409*49fe348cSAndroid Build Coastguard Worker                    lsbs.append(int(x[n+0] < 0))
410*49fe348cSAndroid Build Coastguard Worker
411*49fe348cSAndroid Build Coastguard Worker                lsbs.append(lsb_1)
412*49fe348cSAndroid Build Coastguard Worker                if b_lsb == 0 and x[n+1] != 0:
413*49fe348cSAndroid Build Coastguard Worker                    lsbs.append(int(x[n+1] < 0))
414*49fe348cSAndroid Build Coastguard Worker
415*49fe348cSAndroid Build Coastguard Worker            if a_lsb > 0:
416*49fe348cSAndroid Build Coastguard Worker                bits.write_bit(int(x[n+0] < 0))
417*49fe348cSAndroid Build Coastguard Worker
418*49fe348cSAndroid Build Coastguard Worker            if b_lsb > 0:
419*49fe348cSAndroid Build Coastguard Worker                bits.write_bit(int(x[n+1] < 0))
420*49fe348cSAndroid Build Coastguard Worker
421*49fe348cSAndroid Build Coastguard Worker            t = 1 + (a + b) * (lev + 1) if lev <= 1 else 12 + lev;
422*49fe348cSAndroid Build Coastguard Worker            c = (c & 15) * 16 + t;
423*49fe348cSAndroid Build Coastguard Worker
424*49fe348cSAndroid Build Coastguard Worker        ### Residual data
425*49fe348cSAndroid Build Coastguard Worker
426*49fe348cSAndroid Build Coastguard Worker        if self.lsb_mode == 0:
427*49fe348cSAndroid Build Coastguard Worker            nbits_residual = min(bits.get_bits_left(), self.nbits_residual_max)
428*49fe348cSAndroid Build Coastguard Worker
429*49fe348cSAndroid Build Coastguard Worker            for i in range(len(self.xg)):
430*49fe348cSAndroid Build Coastguard Worker
431*49fe348cSAndroid Build Coastguard Worker                if self.xq[i] == 0:
432*49fe348cSAndroid Build Coastguard Worker                    continue
433*49fe348cSAndroid Build Coastguard Worker
434*49fe348cSAndroid Build Coastguard Worker                bits.write_bit(self.xg[i] >= self.xq[i])
435*49fe348cSAndroid Build Coastguard Worker                nbits_residual -= 1
436*49fe348cSAndroid Build Coastguard Worker                if nbits_residual <= 0:
437*49fe348cSAndroid Build Coastguard Worker                    break
438*49fe348cSAndroid Build Coastguard Worker
439*49fe348cSAndroid Build Coastguard Worker        else:
440*49fe348cSAndroid Build Coastguard Worker            nbits_residual = min(bits.get_bits_left(), len(lsbs))
441*49fe348cSAndroid Build Coastguard Worker            for lsb in lsbs[:nbits_residual]:
442*49fe348cSAndroid Build Coastguard Worker                bits.write_bit(lsb)
443*49fe348cSAndroid Build Coastguard Worker
444*49fe348cSAndroid Build Coastguard Worker
445*49fe348cSAndroid Build Coastguard Workerclass SpectrumSynthesis(SpectrumQuantization):
446*49fe348cSAndroid Build Coastguard Worker
447*49fe348cSAndroid Build Coastguard Worker    def __init__(self, dt, sr):
448*49fe348cSAndroid Build Coastguard Worker
449*49fe348cSAndroid Build Coastguard Worker        super().__init__(dt, sr)
450*49fe348cSAndroid Build Coastguard Worker
451*49fe348cSAndroid Build Coastguard Worker        (self.lastnz, self.lsb_mode, self.g_idx) = \
452*49fe348cSAndroid Build Coastguard Worker            (None, None, None)
453*49fe348cSAndroid Build Coastguard Worker
454*49fe348cSAndroid Build Coastguard Worker    def fill_noise(self, bw, x, lastnz, f_nf, nf_seed):
455*49fe348cSAndroid Build Coastguard Worker
456*49fe348cSAndroid Build Coastguard Worker        i_nf = self.get_noise_indices(bw, x, lastnz)
457*49fe348cSAndroid Build Coastguard Worker
458*49fe348cSAndroid Build Coastguard Worker        k_nf = np.argwhere(i_nf)
459*49fe348cSAndroid Build Coastguard Worker        l_nf = (8 - f_nf)/16
460*49fe348cSAndroid Build Coastguard Worker
461*49fe348cSAndroid Build Coastguard Worker        for k in k_nf:
462*49fe348cSAndroid Build Coastguard Worker            nf_seed = (13849 + nf_seed * 31821) & 0xffff
463*49fe348cSAndroid Build Coastguard Worker            x[k] = [ -l_nf, l_nf ][nf_seed < 0x8000]
464*49fe348cSAndroid Build Coastguard Worker
465*49fe348cSAndroid Build Coastguard Worker        return x
466*49fe348cSAndroid Build Coastguard Worker
467*49fe348cSAndroid Build Coastguard Worker    def load(self, b):
468*49fe348cSAndroid Build Coastguard Worker
469*49fe348cSAndroid Build Coastguard Worker        ne = T.I[self.dt][self.sr][-1]
470*49fe348cSAndroid Build Coastguard Worker        nbits_lastnz = np.ceil(np.log2(ne/2)).astype(int)
471*49fe348cSAndroid Build Coastguard Worker
472*49fe348cSAndroid Build Coastguard Worker        self.lastnz = (b.read_uint(nbits_lastnz) + 1) << 1
473*49fe348cSAndroid Build Coastguard Worker        self.lsb_mode = b.read_uint(1)
474*49fe348cSAndroid Build Coastguard Worker        self.g_idx = b.read_uint(8)
475*49fe348cSAndroid Build Coastguard Worker
476*49fe348cSAndroid Build Coastguard Worker        if self.lastnz > ne:
477*49fe348cSAndroid Build Coastguard Worker            raise ValueError('Invalid count of coded samples')
478*49fe348cSAndroid Build Coastguard Worker
479*49fe348cSAndroid Build Coastguard Worker    def decode(self, bits, bw, nbytes):
480*49fe348cSAndroid Build Coastguard Worker
481*49fe348cSAndroid Build Coastguard Worker        ### Noise factor
482*49fe348cSAndroid Build Coastguard Worker
483*49fe348cSAndroid Build Coastguard Worker        f_nf = bits.read_uint(3)
484*49fe348cSAndroid Build Coastguard Worker
485*49fe348cSAndroid Build Coastguard Worker        ### Quantized data
486*49fe348cSAndroid Build Coastguard Worker
487*49fe348cSAndroid Build Coastguard Worker        ne = T.I[self.dt][self.sr][-1]
488*49fe348cSAndroid Build Coastguard Worker        x  = np.zeros(ne)
489*49fe348cSAndroid Build Coastguard Worker        rate = [ 0, 512 ][int(self.sr < T.SRATE_96K_HR and \
490*49fe348cSAndroid Build Coastguard Worker                              nbytes >  20 * (1 + min(self.sr, T.SRATE_48K)))]
491*49fe348cSAndroid Build Coastguard Worker
492*49fe348cSAndroid Build Coastguard Worker        levs = np.zeros(len(x), dtype=np.intc)
493*49fe348cSAndroid Build Coastguard Worker        c = 0
494*49fe348cSAndroid Build Coastguard Worker
495*49fe348cSAndroid Build Coastguard Worker        for n in range(0, self.lastnz, 2):
496*49fe348cSAndroid Build Coastguard Worker            t = c + rate
497*49fe348cSAndroid Build Coastguard Worker            if n > len(x) // 2:
498*49fe348cSAndroid Build Coastguard Worker                t += 256
499*49fe348cSAndroid Build Coastguard Worker
500*49fe348cSAndroid Build Coastguard Worker            for lev in range(14):
501*49fe348cSAndroid Build Coastguard Worker
502*49fe348cSAndroid Build Coastguard Worker                s = t + min(lev, 3) * 1024
503*49fe348cSAndroid Build Coastguard Worker
504*49fe348cSAndroid Build Coastguard Worker                sym = bits.ac_decode(
505*49fe348cSAndroid Build Coastguard Worker                    T.AC_SPEC_CUMFREQ[T.AC_SPEC_LOOKUP[s]],
506*49fe348cSAndroid Build Coastguard Worker                    T.AC_SPEC_FREQ[T.AC_SPEC_LOOKUP[s]])
507*49fe348cSAndroid Build Coastguard Worker
508*49fe348cSAndroid Build Coastguard Worker                if sym < 16:
509*49fe348cSAndroid Build Coastguard Worker                    break
510*49fe348cSAndroid Build Coastguard Worker
511*49fe348cSAndroid Build Coastguard Worker                if self.lsb_mode == 0 or lev > 0:
512*49fe348cSAndroid Build Coastguard Worker                    x[n  ] += bits.read_bit() << lev
513*49fe348cSAndroid Build Coastguard Worker                    x[n+1] += bits.read_bit() << lev
514*49fe348cSAndroid Build Coastguard Worker
515*49fe348cSAndroid Build Coastguard Worker            if lev >= 14:
516*49fe348cSAndroid Build Coastguard Worker                raise ValueError('Out of range value')
517*49fe348cSAndroid Build Coastguard Worker
518*49fe348cSAndroid Build Coastguard Worker            a = sym %  4
519*49fe348cSAndroid Build Coastguard Worker            b = sym // 4
520*49fe348cSAndroid Build Coastguard Worker
521*49fe348cSAndroid Build Coastguard Worker            levs[n  ] = lev
522*49fe348cSAndroid Build Coastguard Worker            levs[n+1] = lev
523*49fe348cSAndroid Build Coastguard Worker
524*49fe348cSAndroid Build Coastguard Worker            x[n  ] += a << lev
525*49fe348cSAndroid Build Coastguard Worker            x[n+1] += b << lev
526*49fe348cSAndroid Build Coastguard Worker
527*49fe348cSAndroid Build Coastguard Worker            if x[n] and bits.read_bit():
528*49fe348cSAndroid Build Coastguard Worker                x[n] = -x[n]
529*49fe348cSAndroid Build Coastguard Worker
530*49fe348cSAndroid Build Coastguard Worker            if x[n+1] and bits.read_bit():
531*49fe348cSAndroid Build Coastguard Worker                x[n+1] = -x[n+1]
532*49fe348cSAndroid Build Coastguard Worker
533*49fe348cSAndroid Build Coastguard Worker            lev = min(lev, 3)
534*49fe348cSAndroid Build Coastguard Worker            t = 1 + (a + b) * (lev + 1) if lev <= 1 else 12 + lev;
535*49fe348cSAndroid Build Coastguard Worker            c = (c & 15) * 16 + t;
536*49fe348cSAndroid Build Coastguard Worker
537*49fe348cSAndroid Build Coastguard Worker        ### Residual data
538*49fe348cSAndroid Build Coastguard Worker
539*49fe348cSAndroid Build Coastguard Worker        nbits_residual = bits.get_bits_left()
540*49fe348cSAndroid Build Coastguard Worker        if nbits_residual < 0:
541*49fe348cSAndroid Build Coastguard Worker            raise ValueError('Out of bitstream')
542*49fe348cSAndroid Build Coastguard Worker
543*49fe348cSAndroid Build Coastguard Worker        if self.lsb_mode == 0:
544*49fe348cSAndroid Build Coastguard Worker
545*49fe348cSAndroid Build Coastguard Worker            xr = np.zeros(len(x), dtype=np.bool)
546*49fe348cSAndroid Build Coastguard Worker
547*49fe348cSAndroid Build Coastguard Worker            for i in range(len(x)):
548*49fe348cSAndroid Build Coastguard Worker
549*49fe348cSAndroid Build Coastguard Worker                if nbits_residual <= 0:
550*49fe348cSAndroid Build Coastguard Worker                    xr.resize(i)
551*49fe348cSAndroid Build Coastguard Worker                    break
552*49fe348cSAndroid Build Coastguard Worker
553*49fe348cSAndroid Build Coastguard Worker                if x[i] == 0:
554*49fe348cSAndroid Build Coastguard Worker                    continue
555*49fe348cSAndroid Build Coastguard Worker
556*49fe348cSAndroid Build Coastguard Worker                xr[i] = bits.read_bit()
557*49fe348cSAndroid Build Coastguard Worker                nbits_residual -= 1
558*49fe348cSAndroid Build Coastguard Worker
559*49fe348cSAndroid Build Coastguard Worker        else:
560*49fe348cSAndroid Build Coastguard Worker
561*49fe348cSAndroid Build Coastguard Worker            for i in range(len(levs)):
562*49fe348cSAndroid Build Coastguard Worker
563*49fe348cSAndroid Build Coastguard Worker                if nbits_residual <= 0:
564*49fe348cSAndroid Build Coastguard Worker                    break
565*49fe348cSAndroid Build Coastguard Worker
566*49fe348cSAndroid Build Coastguard Worker                if levs[i] <= 0:
567*49fe348cSAndroid Build Coastguard Worker                    continue
568*49fe348cSAndroid Build Coastguard Worker
569*49fe348cSAndroid Build Coastguard Worker                lsb = bits.read_bit()
570*49fe348cSAndroid Build Coastguard Worker                nbits_residual -= 1
571*49fe348cSAndroid Build Coastguard Worker                if not lsb:
572*49fe348cSAndroid Build Coastguard Worker                    continue
573*49fe348cSAndroid Build Coastguard Worker
574*49fe348cSAndroid Build Coastguard Worker                sign = int(x[i] < 0)
575*49fe348cSAndroid Build Coastguard Worker
576*49fe348cSAndroid Build Coastguard Worker                if x[i] == 0:
577*49fe348cSAndroid Build Coastguard Worker
578*49fe348cSAndroid Build Coastguard Worker                    if nbits_residual <= 0:
579*49fe348cSAndroid Build Coastguard Worker                        break
580*49fe348cSAndroid Build Coastguard Worker
581*49fe348cSAndroid Build Coastguard Worker                    sign = bits.read_bit()
582*49fe348cSAndroid Build Coastguard Worker                    nbits_residual -= 1
583*49fe348cSAndroid Build Coastguard Worker
584*49fe348cSAndroid Build Coastguard Worker                x[i] += [ 1, -1 ][sign]
585*49fe348cSAndroid Build Coastguard Worker
586*49fe348cSAndroid Build Coastguard Worker        ### Set residual and noise
587*49fe348cSAndroid Build Coastguard Worker
588*49fe348cSAndroid Build Coastguard Worker        nf_seed = sum(abs(x.astype(np.intc)) * range(len(x)))
589*49fe348cSAndroid Build Coastguard Worker
590*49fe348cSAndroid Build Coastguard Worker        zero_frame = (self.lastnz <= 2 and x[0] == 0 and x[1] == 0
591*49fe348cSAndroid Build Coastguard Worker                      and self.g_idx <= 0 and f_nf >= 7)
592*49fe348cSAndroid Build Coastguard Worker
593*49fe348cSAndroid Build Coastguard Worker        if self.lsb_mode == 0:
594*49fe348cSAndroid Build Coastguard Worker
595*49fe348cSAndroid Build Coastguard Worker            for i in range(len(xr)):
596*49fe348cSAndroid Build Coastguard Worker
597*49fe348cSAndroid Build Coastguard Worker                if x[i] and xr[i] == 0:
598*49fe348cSAndroid Build Coastguard Worker                    x[i] += [ -0.1875, -0.3125 ][x[i] < 0]
599*49fe348cSAndroid Build Coastguard Worker                elif x[i]:
600*49fe348cSAndroid Build Coastguard Worker                    x[i] += [  0.1875,  0.3125 ][x[i] > 0]
601*49fe348cSAndroid Build Coastguard Worker
602*49fe348cSAndroid Build Coastguard Worker        if not zero_frame:
603*49fe348cSAndroid Build Coastguard Worker            x = self.fill_noise(bw, x, self.lastnz, f_nf, nf_seed)
604*49fe348cSAndroid Build Coastguard Worker
605*49fe348cSAndroid Build Coastguard Worker        ### Rescale coefficients
606*49fe348cSAndroid Build Coastguard Worker
607*49fe348cSAndroid Build Coastguard Worker        g_int = self.get_gain_offset(nbytes) + self.g_idx
608*49fe348cSAndroid Build Coastguard Worker        x *= 10 ** (g_int / 28)
609*49fe348cSAndroid Build Coastguard Worker
610*49fe348cSAndroid Build Coastguard Worker        return x
611*49fe348cSAndroid Build Coastguard Worker
612*49fe348cSAndroid Build Coastguard Worker
613*49fe348cSAndroid Build Coastguard Workerdef initial_state():
614*49fe348cSAndroid Build Coastguard Worker    return { 'nbits_off' : 0.0, 'nbits_spare' : 0 }
615*49fe348cSAndroid Build Coastguard Worker
616*49fe348cSAndroid Build Coastguard Worker
617*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ###
618*49fe348cSAndroid Build Coastguard Worker
619*49fe348cSAndroid Build Coastguard Workerdef check_estimate_gain(rng, dt, sr):
620*49fe348cSAndroid Build Coastguard Worker
621*49fe348cSAndroid Build Coastguard Worker    ok = True
622*49fe348cSAndroid Build Coastguard Worker
623*49fe348cSAndroid Build Coastguard Worker    analysis = SpectrumAnalysis(dt, sr)
624*49fe348cSAndroid Build Coastguard Worker
625*49fe348cSAndroid Build Coastguard Worker    mismatch_count = 0
626*49fe348cSAndroid Build Coastguard Worker    for i in range(10):
627*49fe348cSAndroid Build Coastguard Worker        ne = T.I[dt][sr][-1]
628*49fe348cSAndroid Build Coastguard Worker        x  = rng.random(ne) * i * 1e2
629*49fe348cSAndroid Build Coastguard Worker
630*49fe348cSAndroid Build Coastguard Worker        nbytes = 20 + int(rng.random() * 100)
631*49fe348cSAndroid Build Coastguard Worker        nbits_budget = 8 * nbytes - int(rng.random() * 100)
632*49fe348cSAndroid Build Coastguard Worker        nbits_off = rng.random() * 10
633*49fe348cSAndroid Build Coastguard Worker        g_off = 10 - int(rng.random() * 20)
634*49fe348cSAndroid Build Coastguard Worker
635*49fe348cSAndroid Build Coastguard Worker        (_, g_int, reset_off) = \
636*49fe348cSAndroid Build Coastguard Worker            analysis.estimate_gain(x, nbytes, nbits_budget, nbits_off, g_off)
637*49fe348cSAndroid Build Coastguard Worker
638*49fe348cSAndroid Build Coastguard Worker        (g_int_c, reset_off_c, _) = lc3.spec_estimate_gain(
639*49fe348cSAndroid Build Coastguard Worker            dt, sr, x, nbytes, nbits_budget, nbits_off, -g_off)
640*49fe348cSAndroid Build Coastguard Worker
641*49fe348cSAndroid Build Coastguard Worker        if g_int_c != g_int:
642*49fe348cSAndroid Build Coastguard Worker            mismatch_count += 1
643*49fe348cSAndroid Build Coastguard Worker
644*49fe348cSAndroid Build Coastguard Worker        ok = ok and (g_int_c == g_int or mismatch_count <= 1)
645*49fe348cSAndroid Build Coastguard Worker        ok = ok and (reset_off_c == reset_off or mismatch_count <= 1)
646*49fe348cSAndroid Build Coastguard Worker
647*49fe348cSAndroid Build Coastguard Worker    return ok
648*49fe348cSAndroid Build Coastguard Worker
649*49fe348cSAndroid Build Coastguard Workerdef check_quantization(rng, dt, sr):
650*49fe348cSAndroid Build Coastguard Worker
651*49fe348cSAndroid Build Coastguard Worker    ok = True
652*49fe348cSAndroid Build Coastguard Worker
653*49fe348cSAndroid Build Coastguard Worker    analysis = SpectrumAnalysis(dt, sr)
654*49fe348cSAndroid Build Coastguard Worker
655*49fe348cSAndroid Build Coastguard Worker    for g_int in range(-128, 128):
656*49fe348cSAndroid Build Coastguard Worker
657*49fe348cSAndroid Build Coastguard Worker        ne = T.I[dt][sr][-1]
658*49fe348cSAndroid Build Coastguard Worker        x  = rng.random(ne) * 1e2
659*49fe348cSAndroid Build Coastguard Worker        nbytes = 20 + int(rng.random() * 30)
660*49fe348cSAndroid Build Coastguard Worker
661*49fe348cSAndroid Build Coastguard Worker        (xg, xq, nq) = analysis.quantize(g_int, x)
662*49fe348cSAndroid Build Coastguard Worker        (xg_c, nq_c) = lc3.spec_quantize(dt, sr, g_int, x)
663*49fe348cSAndroid Build Coastguard Worker
664*49fe348cSAndroid Build Coastguard Worker        ok = ok and np.amax(np.abs(1 - xg_c/xg)) < 1e-6
665*49fe348cSAndroid Build Coastguard Worker        ok = ok and nq_c == nq
666*49fe348cSAndroid Build Coastguard Worker
667*49fe348cSAndroid Build Coastguard Worker    return ok
668*49fe348cSAndroid Build Coastguard Worker
669*49fe348cSAndroid Build Coastguard Workerdef check_compute_nbits(rng, dt, sr):
670*49fe348cSAndroid Build Coastguard Worker
671*49fe348cSAndroid Build Coastguard Worker    ok = True
672*49fe348cSAndroid Build Coastguard Worker
673*49fe348cSAndroid Build Coastguard Worker    analysis = SpectrumAnalysis(dt, sr)
674*49fe348cSAndroid Build Coastguard Worker
675*49fe348cSAndroid Build Coastguard Worker    for nbytes in range(20, 150):
676*49fe348cSAndroid Build Coastguard Worker
677*49fe348cSAndroid Build Coastguard Worker        nbits_budget = nbytes * 8 - int(rng.random() * 100)
678*49fe348cSAndroid Build Coastguard Worker        ne = T.I[dt][sr][-1]
679*49fe348cSAndroid Build Coastguard Worker        xq = (rng.random(ne) * 8).astype(int)
680*49fe348cSAndroid Build Coastguard Worker        nq = ne // 2 + int(rng.random() * ne // 2)
681*49fe348cSAndroid Build Coastguard Worker
682*49fe348cSAndroid Build Coastguard Worker        nq = nq - nq % 2
683*49fe348cSAndroid Build Coastguard Worker        if xq[nq-2] == 0 and xq[nq-1] == 0:
684*49fe348cSAndroid Build Coastguard Worker            xq[nq-2] = 1
685*49fe348cSAndroid Build Coastguard Worker
686*49fe348cSAndroid Build Coastguard Worker        (nbits, nbits_trunc, nq_trunc, lsb_mode) = \
687*49fe348cSAndroid Build Coastguard Worker            analysis.compute_nbits(nbytes, xq, nq, nbits_budget)
688*49fe348cSAndroid Build Coastguard Worker
689*49fe348cSAndroid Build Coastguard Worker        (nbits_c, nq_c, _) = \
690*49fe348cSAndroid Build Coastguard Worker            lc3.spec_compute_nbits(dt, sr, nbytes, xq, nq, 0)
691*49fe348cSAndroid Build Coastguard Worker
692*49fe348cSAndroid Build Coastguard Worker        (nbits_trunc_c, nq_trunc_c, lsb_mode_c) = \
693*49fe348cSAndroid Build Coastguard Worker            lc3.spec_compute_nbits(dt, sr, nbytes, xq, nq, nbits_budget)
694*49fe348cSAndroid Build Coastguard Worker
695*49fe348cSAndroid Build Coastguard Worker        ok = ok and nbits_c == nbits
696*49fe348cSAndroid Build Coastguard Worker        ok = ok and nbits_trunc_c == nbits_trunc
697*49fe348cSAndroid Build Coastguard Worker        ok = ok and nq_trunc_c == nq_trunc
698*49fe348cSAndroid Build Coastguard Worker        ok = ok and lsb_mode_c == lsb_mode
699*49fe348cSAndroid Build Coastguard Worker
700*49fe348cSAndroid Build Coastguard Worker    return ok
701*49fe348cSAndroid Build Coastguard Worker
702*49fe348cSAndroid Build Coastguard Workerdef check_adjust_gain(rng, dt, sr):
703*49fe348cSAndroid Build Coastguard Worker
704*49fe348cSAndroid Build Coastguard Worker    ok = True
705*49fe348cSAndroid Build Coastguard Worker
706*49fe348cSAndroid Build Coastguard Worker    analysis = SpectrumAnalysis(dt, sr)
707*49fe348cSAndroid Build Coastguard Worker
708*49fe348cSAndroid Build Coastguard Worker    for g_idx in (0, 128, 254, 255):
709*49fe348cSAndroid Build Coastguard Worker        for nbits in range(50, 5000, 5):
710*49fe348cSAndroid Build Coastguard Worker            nbits_budget = int(nbits * (0.95 + (rng.random() * 0.1)))
711*49fe348cSAndroid Build Coastguard Worker
712*49fe348cSAndroid Build Coastguard Worker            g_adj = analysis.adjust_gain(g_idx, nbits, nbits_budget)
713*49fe348cSAndroid Build Coastguard Worker
714*49fe348cSAndroid Build Coastguard Worker            g_adj_c = lc3.spec_adjust_gain(
715*49fe348cSAndroid Build Coastguard Worker                dt, sr, g_idx, nbits, nbits_budget, 0)
716*49fe348cSAndroid Build Coastguard Worker
717*49fe348cSAndroid Build Coastguard Worker            ok = ok and g_adj_c == g_adj
718*49fe348cSAndroid Build Coastguard Worker
719*49fe348cSAndroid Build Coastguard Worker    return ok
720*49fe348cSAndroid Build Coastguard Worker
721*49fe348cSAndroid Build Coastguard Workerdef check_unit(rng, dt, sr):
722*49fe348cSAndroid Build Coastguard Worker
723*49fe348cSAndroid Build Coastguard Worker    ok = True
724*49fe348cSAndroid Build Coastguard Worker
725*49fe348cSAndroid Build Coastguard Worker    state_c = initial_state()
726*49fe348cSAndroid Build Coastguard Worker
727*49fe348cSAndroid Build Coastguard Worker    bwdet = m_bwdet.BandwidthDetector(dt, sr)
728*49fe348cSAndroid Build Coastguard Worker    ltpf = m_ltpf.LtpfAnalysis(dt, sr)
729*49fe348cSAndroid Build Coastguard Worker    tns = m_tns.TnsAnalysis(dt)
730*49fe348cSAndroid Build Coastguard Worker    sns = m_sns.SnsAnalysis(dt, sr)
731*49fe348cSAndroid Build Coastguard Worker    analysis = SpectrumAnalysis(dt, sr)
732*49fe348cSAndroid Build Coastguard Worker
733*49fe348cSAndroid Build Coastguard Worker    nbytes = 100
734*49fe348cSAndroid Build Coastguard Worker
735*49fe348cSAndroid Build Coastguard Worker    for i in range(10):
736*49fe348cSAndroid Build Coastguard Worker        ns = T.NS[dt][sr]
737*49fe348cSAndroid Build Coastguard Worker        ne = T.I[dt][sr][-1]
738*49fe348cSAndroid Build Coastguard Worker
739*49fe348cSAndroid Build Coastguard Worker        x = rng.random(ns) * 1e4
740*49fe348cSAndroid Build Coastguard Worker        e = rng.random(min(len(x), 64)) * 1e10
741*49fe348cSAndroid Build Coastguard Worker
742*49fe348cSAndroid Build Coastguard Worker        if sr < T.SRATE_48K_HR:
743*49fe348cSAndroid Build Coastguard Worker            bwdet.run(e)
744*49fe348cSAndroid Build Coastguard Worker        pitch_present = ltpf.run(x)
745*49fe348cSAndroid Build Coastguard Worker        tns.run(x[:ne], sr, False, nbytes)
746*49fe348cSAndroid Build Coastguard Worker        sns.run(e, False, 0, x)
747*49fe348cSAndroid Build Coastguard Worker
748*49fe348cSAndroid Build Coastguard Worker        (xq, nq, xg) = analysis.run(sr, nbytes,
749*49fe348cSAndroid Build Coastguard Worker            0 if sr >= T.SRATE_48K_HR else bwdet.get_nbits(),
750*49fe348cSAndroid Build Coastguard Worker            ltpf.get_nbits(), sns.get_nbits(), tns.get_nbits(), x[:ne])
751*49fe348cSAndroid Build Coastguard Worker
752*49fe348cSAndroid Build Coastguard Worker        (xg_c, side_c) = lc3.spec_analyze(dt, sr,
753*49fe348cSAndroid Build Coastguard Worker            nbytes, pitch_present, tns.get_data(), state_c, x[:ne])
754*49fe348cSAndroid Build Coastguard Worker
755*49fe348cSAndroid Build Coastguard Worker        ok = ok and side_c['g_idx'] == analysis.g_idx
756*49fe348cSAndroid Build Coastguard Worker        ok = ok and side_c['nq'] == nq
757*49fe348cSAndroid Build Coastguard Worker        ok = ok and np.amax(np.abs(1 - xg_c/xg)) < 1e-6
758*49fe348cSAndroid Build Coastguard Worker
759*49fe348cSAndroid Build Coastguard Worker    return ok
760*49fe348cSAndroid Build Coastguard Worker
761*49fe348cSAndroid Build Coastguard Workerdef check_noise(rng, dt, bw, hrmode = False):
762*49fe348cSAndroid Build Coastguard Worker
763*49fe348cSAndroid Build Coastguard Worker    ok = True
764*49fe348cSAndroid Build Coastguard Worker
765*49fe348cSAndroid Build Coastguard Worker    analysis = SpectrumAnalysis(dt, bw)
766*49fe348cSAndroid Build Coastguard Worker
767*49fe348cSAndroid Build Coastguard Worker    xq_off = [ 0.375, 0.5 ][hrmode]
768*49fe348cSAndroid Build Coastguard Worker
769*49fe348cSAndroid Build Coastguard Worker    for i in range(10):
770*49fe348cSAndroid Build Coastguard Worker        ne = T.I[dt][bw][-1]
771*49fe348cSAndroid Build Coastguard Worker        xq = ((rng.random(ne) - 0.5) * 10 ** (0.5)).astype(int)
772*49fe348cSAndroid Build Coastguard Worker        nq = ne - int(rng.random() * 5)
773*49fe348cSAndroid Build Coastguard Worker        x  = xq - np.select([xq < 0, xq > 0], np.array([ xq_off, -xq_off ]))
774*49fe348cSAndroid Build Coastguard Worker
775*49fe348cSAndroid Build Coastguard Worker        nf = analysis.estimate_noise(bw, xq, nq, x)
776*49fe348cSAndroid Build Coastguard Worker        nf_c = lc3.spec_estimate_noise(dt, bw, hrmode, x, nq)
777*49fe348cSAndroid Build Coastguard Worker
778*49fe348cSAndroid Build Coastguard Worker        ok = ok and nf_c == nf
779*49fe348cSAndroid Build Coastguard Worker
780*49fe348cSAndroid Build Coastguard Worker    return ok
781*49fe348cSAndroid Build Coastguard Worker
782*49fe348cSAndroid Build Coastguard Workerdef check_appendix_c(dt):
783*49fe348cSAndroid Build Coastguard Worker
784*49fe348cSAndroid Build Coastguard Worker    i0 = dt - T.DT_7M5
785*49fe348cSAndroid Build Coastguard Worker    sr = T.SRATE_16K
786*49fe348cSAndroid Build Coastguard Worker
787*49fe348cSAndroid Build Coastguard Worker    ok = True
788*49fe348cSAndroid Build Coastguard Worker
789*49fe348cSAndroid Build Coastguard Worker    state_c = initial_state()
790*49fe348cSAndroid Build Coastguard Worker
791*49fe348cSAndroid Build Coastguard Worker    for i in range(len(C.X_F[i0])):
792*49fe348cSAndroid Build Coastguard Worker
793*49fe348cSAndroid Build Coastguard Worker        ne = T.I[dt][sr][-1]
794*49fe348cSAndroid Build Coastguard Worker
795*49fe348cSAndroid Build Coastguard Worker        g_int = lc3.spec_estimate_gain(dt, sr, C.X_F[i0][i],
796*49fe348cSAndroid Build Coastguard Worker            0, C.NBITS_SPEC[i0][i], C.NBITS_OFFSET[i0][i], -C.GG_OFF[i0][i])[0]
797*49fe348cSAndroid Build Coastguard Worker        ok = ok and g_int == C.GG_IND[i0][i] + C.GG_OFF[i0][i]
798*49fe348cSAndroid Build Coastguard Worker
799*49fe348cSAndroid Build Coastguard Worker        (x, nq) = lc3.spec_quantize(dt, sr,
800*49fe348cSAndroid Build Coastguard Worker            C.GG_IND[i0][i] + C.GG_OFF[i0][i], C.X_F[i0][i])
801*49fe348cSAndroid Build Coastguard Worker        x += np.select([x < 0, x > 0], np.array([ 0.375, -0.375 ]))
802*49fe348cSAndroid Build Coastguard Worker        ok = ok and np.any((np.trunc(x) - C.X_Q[i0][i]) == 0)
803*49fe348cSAndroid Build Coastguard Worker        ok = ok and nq == C.LASTNZ[i0][i]
804*49fe348cSAndroid Build Coastguard Worker        nbits = lc3.spec_compute_nbits(dt, sr,
805*49fe348cSAndroid Build Coastguard Worker            C.NBYTES[i0], C.X_Q[i0][i], C.LASTNZ[i0][i], 0)[0]
806*49fe348cSAndroid Build Coastguard Worker        ok = ok and nbits == C.NBITS_EST[i0][i]
807*49fe348cSAndroid Build Coastguard Worker
808*49fe348cSAndroid Build Coastguard Worker        g_adj = lc3.spec_adjust_gain(dt, sr,
809*49fe348cSAndroid Build Coastguard Worker            C.GG_IND[i0][i], C.NBITS_EST[i0][i], C.NBITS_SPEC[i0][i], 0)
810*49fe348cSAndroid Build Coastguard Worker        ok = ok and g_adj == C.GG_IND_ADJ[i0][i] - C.GG_IND[i0][i]
811*49fe348cSAndroid Build Coastguard Worker
812*49fe348cSAndroid Build Coastguard Worker        if C.GG_IND_ADJ[i0][i] != C.GG_IND[i0][i]:
813*49fe348cSAndroid Build Coastguard Worker
814*49fe348cSAndroid Build Coastguard Worker            (x, nq) = lc3.spec_quantize(dt, sr,
815*49fe348cSAndroid Build Coastguard Worker                C.GG_IND_ADJ[i0][i] + C.GG_OFF[i0][i], C.X_F[i0][i])
816*49fe348cSAndroid Build Coastguard Worker            lastnz = C.LASTNZ_REQ[i0][i]
817*49fe348cSAndroid Build Coastguard Worker            x += np.select([x < 0, x > 0], np.array([ 0.375, -0.375 ]))
818*49fe348cSAndroid Build Coastguard Worker            ok = ok and np.any(((np.trunc(x) - C.X_Q_REQ[i0][i])[:lastnz]) == 0)
819*49fe348cSAndroid Build Coastguard Worker
820*49fe348cSAndroid Build Coastguard Worker        tns_data = {
821*49fe348cSAndroid Build Coastguard Worker            'nfilters' : C.NUM_TNS_FILTERS[i0][i],
822*49fe348cSAndroid Build Coastguard Worker            'lpc_weighting' : [ True, True ],
823*49fe348cSAndroid Build Coastguard Worker            'rc_order' : [ C.RC_ORDER[i0][i][0], 0 ],
824*49fe348cSAndroid Build Coastguard Worker            'rc' : [ C.RC_I_1[i0][i] - 8, np.zeros(8, dtype = np.intc) ]
825*49fe348cSAndroid Build Coastguard Worker        }
826*49fe348cSAndroid Build Coastguard Worker
827*49fe348cSAndroid Build Coastguard Worker        (x, side) = lc3.spec_analyze(dt, sr, C.NBYTES[i0],
828*49fe348cSAndroid Build Coastguard Worker            C.PITCH_PRESENT[i0][i], tns_data, state_c, C.X_F[i0][i])
829*49fe348cSAndroid Build Coastguard Worker
830*49fe348cSAndroid Build Coastguard Worker        xq = x + np.select([x < 0, x > 0], np.array([ 0.375, -0.375 ]))
831*49fe348cSAndroid Build Coastguard Worker        xq = np.trunc(xq)
832*49fe348cSAndroid Build Coastguard Worker
833*49fe348cSAndroid Build Coastguard Worker        ok = ok and np.abs(state_c['nbits_off'] - C.NBITS_OFFSET[i0][i]) < 1e-5
834*49fe348cSAndroid Build Coastguard Worker        if C.GG_IND_ADJ[i0][i] != C.GG_IND[i0][i]:
835*49fe348cSAndroid Build Coastguard Worker            xq = C.X_Q_REQ[i0][i]
836*49fe348cSAndroid Build Coastguard Worker            nq = C.LASTNZ_REQ[i0][i]
837*49fe348cSAndroid Build Coastguard Worker            ok = ok and side['g_idx'] == C.GG_IND_ADJ[i0][i]
838*49fe348cSAndroid Build Coastguard Worker            ok = ok and side['nq'] == nq
839*49fe348cSAndroid Build Coastguard Worker            ok = ok and np.any(((xq[:nq] - xq[:nq])) == 0)
840*49fe348cSAndroid Build Coastguard Worker        else:
841*49fe348cSAndroid Build Coastguard Worker            xq = C.X_Q[i0][i]
842*49fe348cSAndroid Build Coastguard Worker            nq = C.LASTNZ[i0][i]
843*49fe348cSAndroid Build Coastguard Worker            ok = ok and side['g_idx'] == C.GG_IND[i0][i]
844*49fe348cSAndroid Build Coastguard Worker            ok = ok and side['nq'] == nq
845*49fe348cSAndroid Build Coastguard Worker            ok = ok and np.any((xq[:nq] - C.X_Q[i0][i][:nq]) == 0)
846*49fe348cSAndroid Build Coastguard Worker        ok = ok and side['lsb_mode'] == C.LSB_MODE[i0][i]
847*49fe348cSAndroid Build Coastguard Worker
848*49fe348cSAndroid Build Coastguard Worker        gg = C.GG[i0][i] if C.GG_IND_ADJ[i0][i] == C.GG_IND[i0][i] \
849*49fe348cSAndroid Build Coastguard Worker                else C.GG_ADJ[i0][i]
850*49fe348cSAndroid Build Coastguard Worker
851*49fe348cSAndroid Build Coastguard Worker        nf = lc3.spec_estimate_noise(
852*49fe348cSAndroid Build Coastguard Worker                dt, C.P_BW[i0][i], False, C.X_F[i0][i] / gg, nq)
853*49fe348cSAndroid Build Coastguard Worker        ok = ok and nf == C.F_NF[i0][i]
854*49fe348cSAndroid Build Coastguard Worker
855*49fe348cSAndroid Build Coastguard Worker    return ok
856*49fe348cSAndroid Build Coastguard Worker
857*49fe348cSAndroid Build Coastguard Workerdef check():
858*49fe348cSAndroid Build Coastguard Worker
859*49fe348cSAndroid Build Coastguard Worker    rng = np.random.default_rng(1234)
860*49fe348cSAndroid Build Coastguard Worker    ok = True
861*49fe348cSAndroid Build Coastguard Worker
862*49fe348cSAndroid Build Coastguard Worker    for dt in range(T.NUM_DT):
863*49fe348cSAndroid Build Coastguard Worker        for sr in range(T.SRATE_8K, T.SRATE_48K + 1):
864*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_estimate_gain(rng, dt, sr)
865*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_quantization(rng, dt, sr)
866*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_compute_nbits(rng, dt, sr)
867*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_adjust_gain(rng, dt, sr)
868*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_unit(rng, dt, sr)
869*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_noise(rng, dt, sr)
870*49fe348cSAndroid Build Coastguard Worker
871*49fe348cSAndroid Build Coastguard Worker    for dt in ( T.DT_2M5, T.DT_5M, T.DT_10M ):
872*49fe348cSAndroid Build Coastguard Worker        for sr in ( T.SRATE_48K_HR, T.SRATE_96K_HR ):
873*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_estimate_gain(rng, dt, sr)
874*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_quantization(rng, dt, sr)
875*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_compute_nbits(rng, dt, sr)
876*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_adjust_gain(rng, dt, sr)
877*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_unit(rng, dt, sr)
878*49fe348cSAndroid Build Coastguard Worker            ok = ok and check_noise(rng, dt, sr, True)
879*49fe348cSAndroid Build Coastguard Worker
880*49fe348cSAndroid Build Coastguard Worker    for dt in ( T.DT_7M5, T.DT_10M ):
881*49fe348cSAndroid Build Coastguard Worker        ok = ok and check_appendix_c(dt)
882*49fe348cSAndroid Build Coastguard Worker
883*49fe348cSAndroid Build Coastguard Worker    return ok
884*49fe348cSAndroid Build Coastguard Worker
885*49fe348cSAndroid Build Coastguard Worker### ------------------------------------------------------------------------ ###
886