diff --git a/encode.py b/encode.py index 3910f59..31eea8b 100644 --- a/encode.py +++ b/encode.py @@ -1,4 +1,4 @@ -from libxheopus import DualOpusEncoder, CustomFileContainer +from libxheopus import DualOpusEncoder, XopusWriter import wave encoder = DualOpusEncoder("restricted_lowdelay", version="hev2") @@ -6,29 +6,21 @@ encoder.set_bitrates(12000) encoder.set_bitrate_mode("CVBR") desired_frame_size = encoder.set_frame_size(120) -wav_file = wave.open(r"C:\Users\sansw\Desktop\The Weeknd - Blinding Lights (HD+).wav", 'rb') - -metadata = {"Format": "xHE-Opus", "loudness": 0} # Replace with your metadata -container = CustomFileContainer(b'OpuS', 1, metadata) +wav_file = wave.open(r"test.wav", 'rb') file = r"test.xopus" -open(file, 'wb').write(b"") # clear -xopusfile = open(file, 'ab') -xopusfile.write(container.serialize() + b"\\xa") +xopus = XopusWriter(file, encoder) # Read and process the WAV file in chunks print("encoding...") while True: frames = wav_file.readframes(desired_frame_size) - encoded = encoder.encode(frames) - if not frames: break # Break the loop when all frames have been read - xopusfile.write(encoded + b"\\xa") - # Process the frames here, for example, print the number of bytes read - + xopus.write(frames) +xopus.close() print("encoded") \ No newline at end of file diff --git a/libxheopus.py b/libxheopus.py index e645e12..6bf577e 100644 --- a/libxheopus.py +++ b/libxheopus.py @@ -1,4 +1,5 @@ import importlib +import math import struct import pyogg @@ -142,9 +143,17 @@ class DualOpusEncoder: self.Rencoder.CTL(pyogg.opus.OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, int(phaseinvert)) self.Rencoder.CTL(pyogg.opus.OPUS_SET_DTX_REQUEST, int(DTX)) - def encode(self, pcmbytes): + def encode(self, pcmbytes, directpcm=False): """input: pcm bytes accept float32/int16 only""" - pcm = np.frombuffer(pcmbytes, dtype=np.int16) + if directpcm: + if pcmbytes.dtype == np.float32: + pcm = (pcmbytes * 32767).astype(np.int16) + elif pcmbytes.dtype == np.int16: + pcm = pcmbytes.astype(np.int16) + else: + raise TypeError("accept only int16/float32") + else: + pcm = np.frombuffer(pcmbytes, dtype=np.int16) left_channel = pcm[::2] right_channel = pcm[1::2] @@ -189,7 +198,7 @@ class DualOpusDecoder: return stereo_signal.astype(outputformat).tobytes() -class CustomFileContainer: +class HeaderContainer: def __init__(self, capture_pattern, version, metadata): self.capture_pattern = capture_pattern self.version = version @@ -226,4 +235,113 @@ class CustomFileContainer: value = struct.unpack(f'<{value_length}s', metadata_bytes[4:4+value_length])[0].decode('utf-8') metadata_bytes = metadata_bytes[4+value_length:] metadata[key] = value - return metadata \ No newline at end of file + return metadata + +class FooterContainer: + def __init__(self, loudness_avg, length): + self.loudness_avg = loudness_avg + self.length = length + + def serialize(self): + metadata_bytes = self.serialize_metadata() + return metadata_bytes + + def serialize_metadata(self): + metadata_bytes = b'' + metadata_bytes += struct.pack('