-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1f22144
commit 1fe4ccb
Showing
5 changed files
with
1,381 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
""" | ||
Stempeg is a Python package to read and write [STEM](https://www.native-instruments.com/en/specials/stems/) files. | ||
Technically, stems are audio containers that combine multiple audio streams and metadata in a single audio file. This makes it ideal to playback multitrack audio, where users can select the audio sub-stream during playback (e.g. supported by VLC). | ||
Under the hood, _stempeg_ uses [ffmpeg](https://www.ffmpeg.org/) for reading and writing multistream audio, optionally [MP4Box](https://github.com/gpac/gpac) is used to create STEM files that are compatible with Native Instruments hardware and software. | ||
- `stempeg.read`: reading audio tensors and metadata. | ||
- `stempeg.write`: writing audio tensors. | ||
![stempeg_scheme](https://user-images.githubusercontent.com/72940/102477776-16960a00-405d-11eb-9389-1ea9263cf99d.png) | ||
Please checkout [the Github repository](https://github.com/faroit/stempeg) for more information. | ||
""" | ||
|
||
from .read import read_stems | ||
from .read import Info | ||
from .read import StreamsReader, ChannelsReader | ||
from .write import write_stems | ||
from .write import write_audio | ||
from .write import FilesWriter, StreamsWriter, ChannelsWriter, NIStemsWriter | ||
from .cmds import check_available_aac_encoders | ||
|
||
import re | ||
import subprocess as sp | ||
import pkg_resources | ||
|
||
__version__ = "1.0.0" | ||
|
||
|
||
def default_metadata(): | ||
"""Get the path to included stems metadata. | ||
Returns | ||
------- | ||
filename : str | ||
Path to the json file | ||
""" | ||
return pkg_resources.resource_filename(__name__, "../metadata.json") | ||
|
||
|
||
def ffmpeg_version(): | ||
"""Returns the available ffmpeg version | ||
Returns | ||
---------- | ||
version : str | ||
version number as string | ||
""" | ||
|
||
cmd = ["ffmpeg", "-version"] | ||
|
||
output = sp.check_output(cmd) | ||
aac_codecs = [x for x in output.splitlines() if "ffmpeg version " in str(x)][0] | ||
hay = aac_codecs.decode("ascii") | ||
match = re.findall(r"ffmpeg version \w?(\d+\.)?(\d+\.)?(\*|\d+)", hay) | ||
if match: | ||
return "".join(match[0]) | ||
else: | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import re | ||
import subprocess as sp | ||
import logging | ||
|
||
FFMPEG_PATH = None | ||
FFPROBE_PATH = None | ||
MP4BOX_PATH = None | ||
|
||
|
||
def find_cmd(cmd): | ||
try: | ||
from shutil import which | ||
|
||
return which(cmd) | ||
except ImportError: | ||
import os | ||
|
||
for path in os.environ["PATH"].split(os.pathsep): | ||
if os.access(os.path.join(path, cmd), os.X_OK): | ||
return path | ||
|
||
return None | ||
|
||
|
||
def ffmpeg_and_ffprobe_exists(): | ||
global FFMPEG_PATH, FFPROBE_PATH | ||
if FFMPEG_PATH is None: | ||
FFMPEG_PATH = find_cmd("ffmpeg") | ||
|
||
if FFPROBE_PATH is None: | ||
FFPROBE_PATH = find_cmd("ffprobe") | ||
|
||
return FFMPEG_PATH is not None and FFPROBE_PATH is not None | ||
|
||
|
||
def mp4box_exists(): | ||
global MP4BOX_PATH | ||
if MP4BOX_PATH is None: | ||
MP4BOX_PATH = find_cmd("MP4Box") | ||
|
||
return MP4BOX_PATH is not None | ||
|
||
|
||
if not ffmpeg_and_ffprobe_exists(): | ||
raise RuntimeError( | ||
"ffmpeg or ffprobe could not be found! " | ||
"Please install them before using stempeg. " | ||
"See: https://github.com/faroit/stempeg" | ||
) | ||
|
||
|
||
def check_available_aac_encoders(): | ||
"""Returns the available AAC encoders | ||
Returns: | ||
list(str): List of available encoder codecs from ffmpeg | ||
""" | ||
cmd = [FFMPEG_PATH, "-v", "error", "-codecs"] | ||
|
||
output = sp.check_output(cmd) | ||
aac_codecs = [ | ||
x for x in output.splitlines() if "AAC (Advanced Audio Coding)" in str(x) | ||
][0] | ||
hay = aac_codecs.decode("ascii") | ||
match = re.findall(r"\(encoders: ([^\)]*) \)", hay) | ||
if match: | ||
return match[0].split(" ") | ||
else: | ||
return None | ||
|
||
|
||
def get_aac_codec(): | ||
"""Checks codec and warns if `libfdk_aac` codec | ||
is not available. | ||
Returns: | ||
str: ffmpeg aac codec name | ||
""" | ||
avail = check_available_aac_encoders() | ||
if avail is not None: | ||
if "libfdk_aac" in avail: | ||
codec = "libfdk_aac" | ||
else: | ||
logging.warning("For the better audio quality, install `libfdk_aac` codec.") | ||
codec = "aac" | ||
else: | ||
codec = "aac" | ||
|
||
return codec |
Oops, something went wrong.