Skip to content

Commit

Permalink
fork stempeg + add stemsep.py
Browse files Browse the repository at this point in the history
  • Loading branch information
axeldelafosse committed Jul 30, 2023
1 parent 1f22144 commit 1fe4ccb
Show file tree
Hide file tree
Showing 5 changed files with 1,381 additions and 0 deletions.
59 changes: 59 additions & 0 deletions stempeg/__init__.py
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
90 changes: 90 additions & 0 deletions stempeg/cmds.py
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
Loading

0 comments on commit 1fe4ccb

Please sign in to comment.