1*6897da5cSDirk Helbig#!/usr/bin/env python3 2*6897da5cSDirk Helbig# 3*6897da5cSDirk Helbig# Copyright 2024 Google LLC 4*6897da5cSDirk Helbig# 5*6897da5cSDirk Helbig# Licensed under the Apache License, Version 2.0 (the "License"); 6*6897da5cSDirk Helbig# you may not use this file except in compliance with the License. 7*6897da5cSDirk Helbig# You may obtain a copy of the License at 8*6897da5cSDirk Helbig# 9*6897da5cSDirk Helbig# http://www.apache.org/licenses/LICENSE-2.0 10*6897da5cSDirk Helbig# 11*6897da5cSDirk Helbig# Unless required by applicable law or agreed to in writing, software 12*6897da5cSDirk Helbig# distributed under the License is distributed on an "AS IS" BASIS, 13*6897da5cSDirk Helbig# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*6897da5cSDirk Helbig# See the License for the specific language governing permissions and 15*6897da5cSDirk Helbig# limitations under the License. 16*6897da5cSDirk Helbig# 17*6897da5cSDirk Helbig 18*6897da5cSDirk Helbigimport argparse 19*6897da5cSDirk Helbigimport lc3 20*6897da5cSDirk Helbigimport struct 21*6897da5cSDirk Helbigimport sys 22*6897da5cSDirk Helbigimport wave 23*6897da5cSDirk Helbig 24*6897da5cSDirk Helbigparser = argparse.ArgumentParser(description='LC3 Decoder') 25*6897da5cSDirk Helbig 26*6897da5cSDirk Helbigparser.add_argument( 27*6897da5cSDirk Helbig 'lc3_file', nargs='?', 28*6897da5cSDirk Helbig help='Input bitstream file, default is stdin', 29*6897da5cSDirk Helbig type=argparse.FileType('rb'), default=sys.stdin.buffer) 30*6897da5cSDirk Helbig 31*6897da5cSDirk Helbigparser.add_argument( 32*6897da5cSDirk Helbig 'wav_file', nargs='?', 33*6897da5cSDirk Helbig help='Output wave file, default is stdout', 34*6897da5cSDirk Helbig type=argparse.FileType('wb'), default=sys.stdout.buffer) 35*6897da5cSDirk Helbig 36*6897da5cSDirk Helbigparser.add_argument( 37*6897da5cSDirk Helbig '--bitdepth', 38*6897da5cSDirk Helbig help='Output bitdepth, default is 16 bits', 39*6897da5cSDirk Helbig type=int, choices=[16, 24], default=16) 40*6897da5cSDirk Helbig 41*6897da5cSDirk Helbigparser.add_argument( 42*6897da5cSDirk Helbig '--libpath', help='LC3 Library path') 43*6897da5cSDirk Helbig 44*6897da5cSDirk Helbigargs = parser.parse_args() 45*6897da5cSDirk Helbig 46*6897da5cSDirk Helbig# --- LC3 File input --- 47*6897da5cSDirk Helbig 48*6897da5cSDirk Helbigf_lc3 = args.lc3_file 49*6897da5cSDirk Helbig 50*6897da5cSDirk Helbigheader = struct.unpack('=HHHHHHHI', f_lc3.read(18)) 51*6897da5cSDirk Helbigif header[0] != 0xcc1c: 52*6897da5cSDirk Helbig raise ValueError('Invalid bitstream file') 53*6897da5cSDirk Helbig 54*6897da5cSDirk Helbigsamplerate = header[2] * 100 55*6897da5cSDirk Helbignchannels = header[4] 56*6897da5cSDirk Helbigframe_duration = header[5] / 100 57*6897da5cSDirk Helbigstream_length = header[7] 58*6897da5cSDirk Helbig 59*6897da5cSDirk Helbig# --- Setup output --- 60*6897da5cSDirk Helbig 61*6897da5cSDirk Helbigbitdepth = args.bitdepth 62*6897da5cSDirk Helbigpcm_size = nchannels * (bitdepth // 8) 63*6897da5cSDirk Helbig 64*6897da5cSDirk Helbigf_wav = args.wav_file 65*6897da5cSDirk Helbigwavfile = wave.open(f_wav) 66*6897da5cSDirk Helbigwavfile.setnchannels(nchannels) 67*6897da5cSDirk Helbigwavfile.setsampwidth(bitdepth // 8) 68*6897da5cSDirk Helbigwavfile.setframerate(samplerate) 69*6897da5cSDirk Helbigwavfile.setnframes(stream_length) 70*6897da5cSDirk Helbig 71*6897da5cSDirk Helbig# --- Setup decoder --- 72*6897da5cSDirk Helbig 73*6897da5cSDirk Helbigdec = lc3.Decoder( 74*6897da5cSDirk Helbig frame_duration, samplerate, nchannels, libpath=args.libpath) 75*6897da5cSDirk Helbigframe_length = dec.get_frame_samples() 76*6897da5cSDirk Helbigencoded_length = stream_length + dec.get_delay_samples() 77*6897da5cSDirk Helbig 78*6897da5cSDirk Helbig# --- Decoding loop --- 79*6897da5cSDirk Helbig 80*6897da5cSDirk Helbigfor i in range(0, encoded_length, frame_length): 81*6897da5cSDirk Helbig 82*6897da5cSDirk Helbig lc3_frame_size = struct.unpack('=H', f_lc3.read(2))[0] 83*6897da5cSDirk Helbig pcm = dec.decode(f_lc3.read(lc3_frame_size), bitdepth=bitdepth) 84*6897da5cSDirk Helbig 85*6897da5cSDirk Helbig pcm = pcm[max(encoded_length - stream_length - i, 0) * pcm_size: 86*6897da5cSDirk Helbig min(encoded_length - i, frame_length) * pcm_size] 87*6897da5cSDirk Helbig 88*6897da5cSDirk Helbig wavfile.writeframesraw(pcm) 89*6897da5cSDirk Helbig 90*6897da5cSDirk Helbig# --- Cleanup --- 91*6897da5cSDirk Helbig 92*6897da5cSDirk Helbigwavfile.close() 93*6897da5cSDirk Helbig 94*6897da5cSDirk Helbigfor f in (f_lc3, f_wav): 95*6897da5cSDirk Helbig if f is not sys.stdout.buffer: 96*6897da5cSDirk Helbig f.close() 97