1*4930cef6SMatthias Ringwald#!/usr/bin/env python3 2*4930cef6SMatthias Ringwald# 3*4930cef6SMatthias Ringwald# Copyright 2022 Google LLC 4*4930cef6SMatthias Ringwald# 5*4930cef6SMatthias Ringwald# Licensed under the Apache License, Version 2.0 (the "License"); 6*4930cef6SMatthias Ringwald# you may not use this file except in compliance with the License. 7*4930cef6SMatthias Ringwald# You may obtain a copy of the License at 8*4930cef6SMatthias Ringwald# 9*4930cef6SMatthias Ringwald# http://www.apache.org/licenses/LICENSE-2.0 10*4930cef6SMatthias Ringwald# 11*4930cef6SMatthias Ringwald# Unless required by applicable law or agreed to in writing, software 12*4930cef6SMatthias Ringwald# distributed under the License is distributed on an "AS IS" BASIS, 13*4930cef6SMatthias Ringwald# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*4930cef6SMatthias Ringwald# See the License for the specific language governing permissions and 15*4930cef6SMatthias Ringwald# limitations under the License. 16*4930cef6SMatthias Ringwald# 17*4930cef6SMatthias Ringwald 18*4930cef6SMatthias Ringwaldimport numpy as np 19*4930cef6SMatthias Ringwaldimport scipy.signal as signal 20*4930cef6SMatthias Ringwaldimport scipy.io.wavfile as wavfile 21*4930cef6SMatthias Ringwaldimport struct 22*4930cef6SMatthias Ringwaldimport argparse 23*4930cef6SMatthias Ringwald 24*4930cef6SMatthias Ringwaldimport build.lc3 as lc3 25*4930cef6SMatthias Ringwaldimport tables as T, appendix_c as C 26*4930cef6SMatthias Ringwald 27*4930cef6SMatthias Ringwaldimport mdct, energy, bwdet, sns, tns, spec, ltpf 28*4930cef6SMatthias Ringwaldimport bitstream 29*4930cef6SMatthias Ringwald 30*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 31*4930cef6SMatthias Ringwald 32*4930cef6SMatthias Ringwaldclass Decoder: 33*4930cef6SMatthias Ringwald 34*4930cef6SMatthias Ringwald def __init__(self, dt_ms, sr_hz): 35*4930cef6SMatthias Ringwald 36*4930cef6SMatthias Ringwald dt = { 7.5: T.DT_7M5, 10: T.DT_10M }[dt_ms] 37*4930cef6SMatthias Ringwald 38*4930cef6SMatthias Ringwald sr = { 8000: T.SRATE_8K , 16000: T.SRATE_16K, 24000: T.SRATE_24K, 39*4930cef6SMatthias Ringwald 32000: T.SRATE_32K, 48000: T.SRATE_48K }[sr_hz] 40*4930cef6SMatthias Ringwald 41*4930cef6SMatthias Ringwald self.sr = sr 42*4930cef6SMatthias Ringwald self.ne = T.NE[dt][sr] 43*4930cef6SMatthias Ringwald self.ns = T.NS[dt][sr] 44*4930cef6SMatthias Ringwald 45*4930cef6SMatthias Ringwald self.mdct = mdct.MdctInverse(dt, sr) 46*4930cef6SMatthias Ringwald 47*4930cef6SMatthias Ringwald self.bwdet = bwdet.BandwidthDetector(dt, sr) 48*4930cef6SMatthias Ringwald self.spec = spec.SpectrumSynthesis(dt, sr) 49*4930cef6SMatthias Ringwald self.tns = tns.TnsSynthesis(dt) 50*4930cef6SMatthias Ringwald self.sns = sns.SnsSynthesis(dt, sr) 51*4930cef6SMatthias Ringwald self.ltpf = ltpf.LtpfSynthesis(dt, sr) 52*4930cef6SMatthias Ringwald 53*4930cef6SMatthias Ringwald def decode(self, data): 54*4930cef6SMatthias Ringwald 55*4930cef6SMatthias Ringwald b = bitstream.BitstreamReader(data) 56*4930cef6SMatthias Ringwald 57*4930cef6SMatthias Ringwald bw = self.bwdet.get_bw(b) 58*4930cef6SMatthias Ringwald if bw > self.sr: 59*4930cef6SMatthias Ringwald raise ValueError('Invalid bandwidth indication') 60*4930cef6SMatthias Ringwald 61*4930cef6SMatthias Ringwald self.spec.load(b) 62*4930cef6SMatthias Ringwald 63*4930cef6SMatthias Ringwald self.tns.load(b, bw, len(data)) 64*4930cef6SMatthias Ringwald 65*4930cef6SMatthias Ringwald pitch = b.read_bit() 66*4930cef6SMatthias Ringwald 67*4930cef6SMatthias Ringwald self.sns.load(b) 68*4930cef6SMatthias Ringwald 69*4930cef6SMatthias Ringwald if pitch: 70*4930cef6SMatthias Ringwald self.ltpf.load(b) 71*4930cef6SMatthias Ringwald else: 72*4930cef6SMatthias Ringwald self.ltpf.disable() 73*4930cef6SMatthias Ringwald 74*4930cef6SMatthias Ringwald x = self.spec.decode(b, bw, len(data)) 75*4930cef6SMatthias Ringwald 76*4930cef6SMatthias Ringwald return (x, bw, pitch) 77*4930cef6SMatthias Ringwald 78*4930cef6SMatthias Ringwald def synthesize(self, x, bw, pitch, nbytes): 79*4930cef6SMatthias Ringwald 80*4930cef6SMatthias Ringwald x = self.tns.run(x, bw) 81*4930cef6SMatthias Ringwald 82*4930cef6SMatthias Ringwald x = self.sns.run(x) 83*4930cef6SMatthias Ringwald 84*4930cef6SMatthias Ringwald x = np.append(x, np.zeros(self.ns - self.ne)) 85*4930cef6SMatthias Ringwald x = self.mdct.run(x) 86*4930cef6SMatthias Ringwald 87*4930cef6SMatthias Ringwald x = self.ltpf.run(x, len(data)) 88*4930cef6SMatthias Ringwald 89*4930cef6SMatthias Ringwald return x 90*4930cef6SMatthias Ringwald 91*4930cef6SMatthias Ringwald def run(self, data): 92*4930cef6SMatthias Ringwald 93*4930cef6SMatthias Ringwald (x, bw, pitch) = self.decode(data) 94*4930cef6SMatthias Ringwald 95*4930cef6SMatthias Ringwald x = self.synthesize(x, bw, pitch, len(data)) 96*4930cef6SMatthias Ringwald 97*4930cef6SMatthias Ringwald return x 98*4930cef6SMatthias Ringwald 99*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 100*4930cef6SMatthias Ringwald 101*4930cef6SMatthias Ringwalddef check_appendix_c(dt): 102*4930cef6SMatthias Ringwald 103*4930cef6SMatthias Ringwald ok = True 104*4930cef6SMatthias Ringwald 105*4930cef6SMatthias Ringwald dec_c = lc3.setup_decoder(int(T.DT_MS[dt] * 1000), 16000) 106*4930cef6SMatthias Ringwald 107*4930cef6SMatthias Ringwald for i in range(len(C.BYTES_AC[dt])): 108*4930cef6SMatthias Ringwald 109*4930cef6SMatthias Ringwald pcm = lc3.decode(dec_c, bytes(C.BYTES_AC[dt][i])) 110*4930cef6SMatthias Ringwald ok = ok and np.max(np.abs(pcm - C.X_HAT_CLIP[dt][i])) < 1 111*4930cef6SMatthias Ringwald 112*4930cef6SMatthias Ringwald return ok 113*4930cef6SMatthias Ringwald 114*4930cef6SMatthias Ringwalddef check(): 115*4930cef6SMatthias Ringwald 116*4930cef6SMatthias Ringwald ok = True 117*4930cef6SMatthias Ringwald 118*4930cef6SMatthias Ringwald for dt in range(T.NUM_DT): 119*4930cef6SMatthias Ringwald ok = ok and check_appendix_c(dt) 120*4930cef6SMatthias Ringwald 121*4930cef6SMatthias Ringwald return ok 122*4930cef6SMatthias Ringwald 123*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 124*4930cef6SMatthias Ringwald 125*4930cef6SMatthias Ringwaldif __name__ == "__main__": 126*4930cef6SMatthias Ringwald 127*4930cef6SMatthias Ringwald parser = argparse.ArgumentParser(description='LC3 Decoder Test Framework') 128*4930cef6SMatthias Ringwald parser.add_argument('lc3_file', 129*4930cef6SMatthias Ringwald help='Input bitstream file', type=argparse.FileType('r')) 130*4930cef6SMatthias Ringwald parser.add_argument('--pyout', 131*4930cef6SMatthias Ringwald help='Python output file', type=argparse.FileType('w')) 132*4930cef6SMatthias Ringwald parser.add_argument('--cout', 133*4930cef6SMatthias Ringwald help='C output file', type=argparse.FileType('w')) 134*4930cef6SMatthias Ringwald args = parser.parse_args() 135*4930cef6SMatthias Ringwald 136*4930cef6SMatthias Ringwald ### File Header ### 137*4930cef6SMatthias Ringwald 138*4930cef6SMatthias Ringwald f_lc3 = open(args.lc3_file.name, 'rb') 139*4930cef6SMatthias Ringwald 140*4930cef6SMatthias Ringwald header = struct.unpack('=HHHHHHHI', f_lc3.read(18)) 141*4930cef6SMatthias Ringwald 142*4930cef6SMatthias Ringwald if header[0] != 0xcc1c: 143*4930cef6SMatthias Ringwald raise ValueError('Invalid bitstream file') 144*4930cef6SMatthias Ringwald 145*4930cef6SMatthias Ringwald if header[4] != 1: 146*4930cef6SMatthias Ringwald raise ValueError('Unsupported number of channels') 147*4930cef6SMatthias Ringwald 148*4930cef6SMatthias Ringwald sr_hz = header[2] * 100 149*4930cef6SMatthias Ringwald bitrate = header[3] * 100 150*4930cef6SMatthias Ringwald nchannels = header[4] 151*4930cef6SMatthias Ringwald dt_ms = header[5] / 100 152*4930cef6SMatthias Ringwald 153*4930cef6SMatthias Ringwald f_lc3.seek(header[1]) 154*4930cef6SMatthias Ringwald 155*4930cef6SMatthias Ringwald ### Setup ### 156*4930cef6SMatthias Ringwald 157*4930cef6SMatthias Ringwald dec = Decoder(dt_ms, sr_hz) 158*4930cef6SMatthias Ringwald dec_c = lc3.setup_decoder(int(dt_ms * 1000), sr_hz) 159*4930cef6SMatthias Ringwald 160*4930cef6SMatthias Ringwald pcm_c = np.empty(0).astype(np.int16) 161*4930cef6SMatthias Ringwald pcm_py = np.empty(0).astype(np.int16) 162*4930cef6SMatthias Ringwald 163*4930cef6SMatthias Ringwald ### Decoding loop ### 164*4930cef6SMatthias Ringwald 165*4930cef6SMatthias Ringwald nframes = 0 166*4930cef6SMatthias Ringwald 167*4930cef6SMatthias Ringwald while True: 168*4930cef6SMatthias Ringwald 169*4930cef6SMatthias Ringwald data = f_lc3.read(2) 170*4930cef6SMatthias Ringwald if len(data) != 2: 171*4930cef6SMatthias Ringwald break 172*4930cef6SMatthias Ringwald 173*4930cef6SMatthias Ringwald if nframes >= 1000: 174*4930cef6SMatthias Ringwald break 175*4930cef6SMatthias Ringwald 176*4930cef6SMatthias Ringwald (frame_nbytes,) = struct.unpack('=H', data) 177*4930cef6SMatthias Ringwald 178*4930cef6SMatthias Ringwald print('Decoding frame %d' % nframes, end='\r') 179*4930cef6SMatthias Ringwald 180*4930cef6SMatthias Ringwald data = f_lc3.read(frame_nbytes) 181*4930cef6SMatthias Ringwald 182*4930cef6SMatthias Ringwald x = dec.run(data) 183*4930cef6SMatthias Ringwald pcm_py = np.append(pcm_py, 184*4930cef6SMatthias Ringwald np.clip(np.round(x), -32768, 32767).astype(np.int16)) 185*4930cef6SMatthias Ringwald 186*4930cef6SMatthias Ringwald x_c = lc3.decode(dec_c, data) 187*4930cef6SMatthias Ringwald pcm_c = np.append(pcm_c, x_c) 188*4930cef6SMatthias Ringwald 189*4930cef6SMatthias Ringwald nframes += 1 190*4930cef6SMatthias Ringwald 191*4930cef6SMatthias Ringwald print('done ! %16s' % '') 192*4930cef6SMatthias Ringwald 193*4930cef6SMatthias Ringwald ### Terminate ### 194*4930cef6SMatthias Ringwald 195*4930cef6SMatthias Ringwald if args.pyout: 196*4930cef6SMatthias Ringwald wavfile.write(args.pyout.name, sr_hz, pcm_py) 197*4930cef6SMatthias Ringwald if args.cout: 198*4930cef6SMatthias Ringwald wavfile.write(args.cout.name, sr_hz, pcm_c) 199*4930cef6SMatthias Ringwald 200*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 201