This commit is contained in:
dharm pimsen 2024-04-30 12:47:46 +07:00
parent a6ef8f580f
commit 2bd1a050ab
7 changed files with 146 additions and 25 deletions

View File

@ -1,19 +1,61 @@
from libxheopus import DualOpusEncoder, XopusWriter from libxheopus import DualOpusEncoder, XopusWriter
import wave import wave
import argparse
from tqdm import tqdm
encoder = DualOpusEncoder("restricted_lowdelay", version="hev2") parser = argparse.ArgumentParser(description='xHE-Opus Encoder')
encoder.set_bitrates(12000)
encoder.set_bitrate_mode("CVBR")
desired_frame_size = encoder.set_frame_size(120)
wav_file = wave.open(r"test.wav", 'rb') parser.add_argument("input", help='Input wav int16 file path')
parser.add_argument("output", help='Output xopus file path')
parser.add_argument('-sr', "--samprate", help='Set samples rates', default=48000, type=int)
parser.add_argument('-b', '--bitrate', help='Set Bitrate (bps)', default=64000, type=int)
parser.add_argument('-c', '--compress', help='Set compression: 0-10', default=10, type=int)
parser.add_argument('-l', '--loss', help='Set packet loss: 0-100%', default=0, type=int)
parser.add_argument('-fs', '--framesize', help='Set frame size: 120, 100, 80, 60, 40, 20, 10 or 5', default=120, type=int)
parser.add_argument('-bm', '--bitmode', help='Set Bitrate mode: CBR VBR CVBR', default="CVBR")
parser.add_argument('-bw', '--bandwidth', help='Set bandwidth: auto, fullband, superwideband, wideband, mediumband or narrowband', default="fullband")
parser.add_argument('-a', '--app', help='Set bandwidth: restricted_lowdelay, audio, voip', default="restricted_lowdelay")
parser.add_argument('-v', '--ver', help='Set opus version: hev2 (enable 120, 100, 80 framesize), he, exper, stable, old', default="hev2")
parser.add_argument('-pred', '--prediction', help='Enable prediction', action='store_true', default=False)
parser.add_argument('-ph', '--phaseinvert', help='Enable phase invert', action='store_true', default=False)
parser.add_argument('-dtx', help='Enable discontinuous transmission', action='store_true', default=False)
parser.add_argument('-sb', "--samebitrate", help='Enable same bitrate (bitrate x2)', action='store_true', default=False)
file = r"test.xopus" args = parser.parse_args()
progress = tqdm()
progress.desc = "creating encoder..."
encoder = DualOpusEncoder(args.app, args.samprate, args.ver)
encoder.set_bitrates(args.bitrate, args.samebitrate)
encoder.set_bitrate_mode(args.bitmode)
encoder.set_bandwidth(args.bandwidth)
encoder.set_compression(args.compress)
encoder.set_packet_loss(args.loss)
encoder.set_feature(args.prediction, args.phaseinvert, args.dtx)
desired_frame_size = encoder.set_frame_size(args.framesize)
xopus = XopusWriter(args.output, encoder)
allframe = 0
progress.desc = "reading wav file..."
wav_file = wave.open(args.input, 'rb')
while True:
frames = wav_file.readframes(desired_frame_size)
if not frames:
break # Break the loop when all frames have been read
allframe += len(frames)
progress.total = allframe
wav_file.rewind()
xopus = XopusWriter(file, encoder)
# Read and process the WAV file in chunks # Read and process the WAV file in chunks
print("encoding...") progress.desc = "encoding..."
while True: while True:
frames = wav_file.readframes(desired_frame_size) frames = wav_file.readframes(desired_frame_size)
@ -22,5 +64,7 @@ while True:
xopus.write(frames) xopus.write(frames)
progress.update(len(frames))
xopus.close() xopus.close()
print("encoded") progress.desc = "encoded"

View File

@ -1,7 +1,6 @@
import importlib import importlib
import math import math
import struct import struct
import pyogg import pyogg
import os import os
import numpy as np import numpy as np
@ -109,7 +108,6 @@ class DualOpusEncoder:
@return chunk size @return chunk size
""" """
if self.version != "hev2" and size > 60: if self.version != "hev2" and size > 60:
raise ValueError("non hev2 can't use framesize > 60") raise ValueError("non hev2 can't use framesize > 60")
@ -336,12 +334,18 @@ class XopusReader:
if data.startswith(b"\\xeof\\xeof"): if data.startswith(b"\\xeof\\xeof"):
break break
else: else:
try:
yield decoder.decode(data) yield decoder.decode(data)
except:
yield b""
else: else:
decodedlist = [] decodedlist = []
for data in self.xopusline[1:]: for data in self.xopusline[1:]:
if data.startswith(b"\\xeof\\xeof"): if data.startswith(b"\\xeof\\xeof"):
break break
else: else:
try:
decodedlist.append(decoder.decode(data)) decodedlist.append(decoder.decode(data))
except:
decodedlist.append(b"")
return decodedlist return decodedlist

View File

@ -1,21 +1,41 @@
import pyaudio import pyaudio
from libxheopus import DualOpusDecoder, XopusReader from libxheopus import DualOpusDecoder, XopusReader
import argparse
from tqdm import tqdm
import wave
parser = argparse.ArgumentParser(description='xHE-Opus Decoder/Player')
parser.add_argument("input", help='Input xopus file path')
parser.add_argument("-o", "--output", help='Output wav int16 file path')
args = parser.parse_args()
progress = tqdm()
# Initialize PyAudio # Initialize PyAudio
p = pyaudio.PyAudio() p = pyaudio.PyAudio()
decoder = DualOpusDecoder() decoder = DualOpusDecoder()
xopusdecoder = XopusReader(args.input)
metadata = xopusdecoder.readmetadata()
progress.total = metadata["footer"]["length"]
print("\nloudness:", metadata["footer"]["contentloudness"], "DBFS")
print(metadata["header"])
if not args.output:
progress.desc = "playing..."
streamoutput = p.open(format=pyaudio.paInt16, channels=2, rate=48000, output=True) streamoutput = p.open(format=pyaudio.paInt16, channels=2, rate=48000, output=True)
xopusdecoder = XopusReader(r"test.xopus")
print(xopusdecoder.readmetadata())
try: try:
for data in xopusdecoder.decode(decoder, True): for data in xopusdecoder.decode(decoder, True):
streamoutput.write(data) streamoutput.write(data)
progress.update(1)
except KeyboardInterrupt: except KeyboardInterrupt:
print("Interrupted by user") print("Interrupted by user")
finally: finally:
@ -23,3 +43,18 @@ finally:
streamoutput.stop_stream() streamoutput.stop_stream()
streamoutput.close() streamoutput.close()
p.terminate() p.terminate()
progress.desc = "played"
else:
progress.desc = "converting..."
outwav = wave.open("output.wav", "w")
# Set the parameters of the WAV file
outwav.setnchannels(2) # Mono
outwav.setsampwidth(2) # 2 bytes (16 bits) per sample
outwav.setframerate(48000)
for data in xopusdecoder.decode(decoder, True):
# Write the audio data to the file
outwav.writeframes(data)
progress.update(1)
progress.desc = "converted"

38
readme.md Normal file
View File

@ -0,0 +1,38 @@
# xHE-Opus
xHE-Opus is extended High Efficiency. It use Dual-Encoder to encode per channel and bitrate is divide 2 for per channel.
# Install
[PyOgg (damp11113 moded)](https://github.com/damp11113/PyOgg)
# Using
## Encoder
to encode you can use
```bash
$ python3 encode.py
```
```bash
usage: encode.py [-h] [-sr SAMPRATE] [-b BITRATE] [-c COMPRESS] [-l LOSS] [-fs FRAMESIZE] [-bm BITMODE]
[-bw BANDWIDTH] [-a APP] [-v VER] [-pred] [-ph] [-dtx] [-sb]
input output
encode.py: error: the following arguments are required: input, output
```
simple example
```bash
$ python3 encode.py input.wav output.xopus
```
This will convert to xhe-opus with bitrate 64Kbps (32Kbps per channel), bitrate mode is CVBR, compression is 10 and app is hev2
or if you want to set bitrate you can use `-b <bitrate>` input bit per sec (bps) like
```bash
$ python3 encode.py input.wav output.xopus -b 16000
```
## Decoder/Player
To player or decode this file you can use
```bash
$ python3 input.xopus
```
or if you want only convert to wav you can use
```bash
$ python3 input.xopus -o output.wav
```

BIN
test.wav

Binary file not shown.

Binary file not shown.

BIN
test2.xopus Normal file

Binary file not shown.