blob: c10c1e4b27c347f8b011c10ecefe732bd846f3ee [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import argparse
import lc3
import struct
import sys
import wave
parser = argparse.ArgumentParser(description='LC3 Decoder')
parser.add_argument(
'lc3_file', nargs='?',
help='Input bitstream file, default is stdin',
type=argparse.FileType('rb'), default=sys.stdin.buffer)
parser.add_argument(
'wav_file', nargs='?',
help='Output wave file, default is stdout',
type=argparse.FileType('wb'), default=sys.stdout.buffer)
parser.add_argument(
'--bitdepth',
help='Output bitdepth, default is 16 bits',
type=int, choices=[16, 24], default=16)
parser.add_argument(
'--libpath', help='LC3 Library path')
args = parser.parse_args()
# --- LC3 File input ---
f_lc3 = args.lc3_file
header = struct.unpack('=HHHHHHHI', f_lc3.read(18))
if header[0] != 0xcc1c:
raise ValueError('Invalid bitstream file')
samplerate = header[2] * 100
nchannels = header[4]
frame_duration = header[5] / 100
stream_length = header[7]
# --- Setup output ---
bitdepth = args.bitdepth
pcm_size = nchannels * (bitdepth // 8)
f_wav = args.wav_file
wavfile = wave.open(f_wav)
wavfile.setnchannels(nchannels)
wavfile.setsampwidth(bitdepth // 8)
wavfile.setframerate(samplerate)
wavfile.setnframes(stream_length)
# --- Setup decoder ---
dec = lc3.Decoder(
frame_duration, samplerate, nchannels, libpath=args.libpath)
frame_length = dec.get_frame_samples()
encoded_length = stream_length + dec.get_delay_samples()
# --- Decoding loop ---
for i in range(0, encoded_length, frame_length):
lc3_frame_size = struct.unpack('=H', f_lc3.read(2))[0]
pcm = dec.decode(f_lc3.read(lc3_frame_size), bitdepth=bitdepth)
pcm = pcm[max(encoded_length - stream_length - i, 0) * pcm_size:
min(encoded_length - i, frame_length) * pcm_size]
wavfile.writeframesraw(pcm)
# --- Cleanup ---
wavfile.close()
for f in (f_lc3, f_wav):
if f is not sys.stdout.buffer:
f.close()