Compare commits

...
3 Commits
Author SHA1 Message Date
gryf 7a671a5a6d Make opus default encoder 2026-09-25 09:52:06 +02:00
gryf 5a45d56784 Added opus encoder and decoder 2026-09-25 09:49:37 +02:00
gryf 38dc4234e0 Use fstring intsead of string interpolation.
Also, removed python2 mentioning in readme.
2026-09-25 09:19:38 +02:00
2 changed files with 54 additions and 23 deletions

No files matched your search

+14 -8
View File
@@ -15,9 +15,10 @@ conversion between different type of audio formats.
Requirements Requirements
============ ============
- python in version 2.7 or 3 - python 3
- `mutagen`_ python library for tag read/write - `mutagen`_ python library for tag read/write
- `vorbis tools`_ for ``ogg`` files encode/decode - `vorbis tools`_ for ``ogg`` files encode/decode
- `opus tools`_ for ``opus`` files encode/decode
- `lame`_ for ``mp3`` files encode/decode - `lame`_ for ``mp3`` files encode/decode
- `flac`_ for ``flac`` files decode - `flac`_ for ``flac`` files decode
- `mac`_ for ``Monkey audio codecs``/``ape`` files decode - `mac`_ for ``Monkey audio codecs``/``ape`` files decode
@@ -37,16 +38,19 @@ Conversion can be performed from the following formats:
- WavePack - WavePack
- Ape - Ape
- Ogg Vorbis - Ogg Vorbis
- Ogg Opus
Currently supported encoders: Currently supported encoders:
- Ogg Vorbis - Ogg Vorbis
- Ogg Opus
- MP3 (lame) - MP3 (lame)
There is an option to set the quality for the encoders - for *Ogg* files there There is an option to set the quality for the encoders - for *Vorbis* files
would be used an ``-q`` option for ``oggenc`` command, and for the *mp3* there would be used an ``-q`` option for ``oggenc`` command, for the *mp3*
format, ``-V`` option would be used for ``lame`` command. Consult corresponding format ``-V`` option would be used for ``lame`` command and ``--bitrate`` for
man pages for details. ``opusenc`` for the *Opus* files. Consult corresponding encoder man pages for
details.
Usage Usage
===== =====
@@ -57,9 +61,10 @@ Given that there are couple of music files, simplest usage is as follows:
$ flac2ogg.py directory_of_music_files/* $ flac2ogg.py directory_of_music_files/*
All files from that directory will be encoded to *ogg* by defaults. If there All files from that directory will be encoded to *opus* by default. If there
are already some *ogg* files, new files would have ``_encoded_`` added into the are already some *opus* files, new files would have ``_encoded_`` added into
filename. Note, that output files will be placed next to the original files. the filename. Note, that output files will be placed next to the original
files.
License License
======= =======
@@ -69,6 +74,7 @@ This work is licensed on 3-clause BSD license. See LICENSE file for details.
.. _mutagen: https://mutagen.readthedocs.io/en/latest/ .. _mutagen: https://mutagen.readthedocs.io/en/latest/
.. _vorbis tools: http://www.vorbis.com/ .. _vorbis tools: http://www.vorbis.com/
.. _opus tools: https://opus-codec.org
.. _flac: http://www.vorbis.com/ .. _flac: http://www.vorbis.com/
.. _lame: http://lame.sourceforge.net/ .. _lame: http://lame.sourceforge.net/
.. _mac: http://www.deb-multimedia.org/dists/testing/main/binary-amd64/package/monkeys-audio.php .. _mac: http://www.deb-multimedia.org/dists/testing/main/binary-amd64/package/monkeys-audio.php
+40 -15
View File
@@ -14,7 +14,7 @@ from mutagen.mp3 import MP3
from mutagen.easyid3 import EasyID3, EasyID3KeyError from mutagen.easyid3 import EasyID3, EasyID3KeyError
VERSION = '1.2' VERSION = '1.3'
def match_file(path): def match_file(path):
@@ -129,8 +129,8 @@ class OggEncoder(Encoder):
self.quality = 8 self.quality = 8
def encode(self, input_fname, output_fname): def encode(self, input_fname, output_fname):
sp.check_call(["oggenc", "-q%s" % self.quality, input_fname, sp.check_call(["oggenc", f"-q{self.quality}", input_fname, '-o',
'-o', output_fname]) output_fname])
class Mp3Encoder(Encoder): class Mp3Encoder(Encoder):
@@ -144,7 +144,21 @@ class Mp3Encoder(Encoder):
self.quality = 6 self.quality = 6
def encode(self, input_fname, output_fname): def encode(self, input_fname, output_fname):
sp.check_call(["lame", "-V%s" % self.quality, input_fname, sp.check_call(["lame", f"-V{self.quality}", input_fname, output_fname])
class OpusEncoder(Encoder):
"""Opus encoder"""
EXT = ".opus"
def __init__(self, quality=None):
"""Init"""
super().__init__(quality)
if self.quality is None:
self.quality = 128
def encode(self, input_fname, output_fname):
sp.check_call(["opusenc", "--bitrate", self.quality, input_fname,
output_fname]) output_fname])
@@ -288,7 +302,7 @@ class M4aType(FileType):
if "," in wav: if "," in wav:
wav = wav.replace(",", "\\,") wav = wav.replace(",", "\\,")
sp.check_call(["mplayer", "-vo", "none", self.filename, "-ao", sp.check_call(["mplayer", "-vo", "none", self.filename, "-ao",
"pcm:file=%s" % wav]) f"pcm:file={wav}"])
class WavType(FileType): class WavType(FileType):
@@ -330,10 +344,18 @@ class OggType(FileType):
"""Ogg Vorbis filetype""" """Ogg Vorbis filetype"""
def extract_wav(self): def extract_wav(self):
"""Extract mp3 file to wav""" """Extract ogg vorbis file to wav"""
sp.check_call(["oggdec", self.filename]) sp.check_call(["oggdec", self.filename])
class OpusType(FileType):
"""Opus filetype"""
def extract_wav(self):
"""Extract opus file to wav"""
sp.check_call(["opusdec", self.filename])
class Converter: class Converter:
"""Main class for converting files""" """Main class for converting files"""
extract_map = {'.ape': ApeType, extract_map = {'.ape': ApeType,
@@ -342,6 +364,7 @@ class Converter:
'.mp3': Mp3Type, '.mp3': Mp3Type,
'.mpc': MusepackType, '.mpc': MusepackType,
'.ogg': OggType, '.ogg': OggType,
'.opus': OpusType,
'.wav': WavType, '.wav': WavType,
'.wv': WvType} '.wv': WvType}
@@ -381,11 +404,11 @@ class Converter:
base + ".wv.cue", base + ".ape.cue"): base + ".wv.cue", base + ".ape.cue"):
if os.path.exists(tmp): if os.path.exists(tmp):
cuefile = tmp cuefile = tmp
print("*** cuefile: %s" % cuefile) print(f"*** cuefile: {cuefile}")
break break
if cuefile is None: if cuefile is None:
print("*** No cuefile found for `%s'" % filename) print(f"*** No cuefile found for `{filename}'")
return return
cue = CueObjectParser(cuefile) cue = CueObjectParser(cuefile)
@@ -394,7 +417,7 @@ class Converter:
# list of wavs to encode # list of wavs to encode
klass = Converter.extract_map.get(ext.lower()) klass = Converter.extract_map.get(ext.lower())
if not klass: if not klass:
print("*** Cannot find right converter for `%s'" % ext) print(f"*** Cannot find right converter for `{ext}'")
return return
fobj = klass(filename, encoder) fobj = klass(filename, encoder)
@@ -425,7 +448,8 @@ class Converter:
ENCODERS = {'ogg': OggEncoder, ENCODERS = {'ogg': OggEncoder,
'mp3': Mp3Encoder} 'mp3': Mp3Encoder,
'opus': OpusEncoder}
def main(): def main():
@@ -436,12 +460,13 @@ def main():
help='Split output file with provided *.cue file') help='Split output file with provided *.cue file')
arg.add_argument('-r', '--recursive', action='store_true', arg.add_argument('-r', '--recursive', action='store_true',
help='Do the files searching recursive') help='Do the files searching recursive')
arg.add_argument('-e', '--encoder', default='ogg', type=str, arg.add_argument('-e', '--encoder', default='opus', type=str,
choices=('ogg', 'mp3'), help='Encoder to use. Defaults ' choices=('ogg', 'mp3', 'opus'),
'to "ogg"') help='Encoder to use. Defaults to "opus"')
arg.add_argument('-q', '--quality', help='Quality of the encoded file. ' arg.add_argument('-q', '--quality', help='Quality of the encoded file. '
'Consult "lame" and "oggenc" for details. Defaults are ' 'Consult "lame", "oggenc" and "opusenc" manuals for '
'6 for lame and 8 for oggenc.') 'details. Defaults are -V6 for lame, -q8 for oggenc and '
'--bitrate 128 for opusenc')
arg.add_argument('-v', '--version', action='version', arg.add_argument('-v', '--version', action='version',
version='%(prog)s v' + VERSION, version='%(prog)s v' + VERSION,
help='Display version and exit.') help='Display version and exit.')