#!/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 Encoder')

parser.add_argument(
    'wav_file', nargs='?',
    help='Input wave file, default is stdin',
    type=argparse.FileType('rb'), default=sys.stdin.buffer)

parser.add_argument(
    'lc3_file', nargs='?',
    help='Output bitstream file, default is stdout',
    type=argparse.FileType('wb'), default=sys.stdout.buffer)

parser.add_argument(
    '--bitrate', help='Bitrate in bps', type=int, required=True)

parser.add_argument(
    '--frame_duration', help='Frame duration in ms', type=float, default=10)

parser.add_argument(
    '--libpath', help='LC3 Library path')

args = parser.parse_args()

# --- WAV File input ---

f_wav = args.wav_file
wavfile = wave.open(f_wav, 'rb')

samplerate = wavfile.getframerate()
nchannels = wavfile.getnchannels()
bit_depth = wavfile.getsampwidth() * 8
stream_length = wavfile.getnframes()

# --- Setup encoder ---

enc = lc3.Encoder(
    int(args.frame_duration)*1000, samplerate, nchannels, libpath=args.libpath)
frame_size = enc.get_frame_bytes(args.bitrate)
frame_length = enc.get_frame_samples()
bitrate = enc.resolve_bitrate(frame_size)

# --- Setup output ---

f_lc3 = args.lc3_file
f_lc3.write(struct.pack(
    '=HHHHHHHI', 0xcc1c, 18,
    samplerate // 100, bitrate // 100, nchannels,
    int(args.frame_duration * 100), 0, stream_length))

# --- Encoding loop ---

for i in range(0, stream_length, frame_length):

    f_lc3.write(struct.pack('=H', frame_size))

    pcm = wavfile.readframes(frame_length)
    f_lc3.write(enc.encode(pcm, frame_size, bit_depth=bit_depth))

# --- Cleanup ---

wavfile.close()

for f in (f_wav, f_lc3):
    if f is not sys.stdout.buffer:
        f.close()
