xref: /btstack/3rd-party/lc3-google/python/tools/decoder.py (revision 6897da5c53aac5b1f90f41b5b15d0bd43d61dfff)
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