feat: add filename format

This commit is contained in:
Félix Voituret
2019-11-20 15:07:12 +01:00
parent bfb0225083
commit d771fbae34
4 changed files with 36 additions and 24 deletions

View File

@@ -28,6 +28,18 @@ OPT_OUTPUT = {
'help': 'Path of the output directory to write audio files in' 'help': 'Path of the output directory to write audio files in'
} }
# -f opt specification (separate).
OPT_FORMAT = {
'dest': 'filename_format',
'default': '{filename}/{instrument}.{codec}',
'help': (
'Template string that will be formatted to generated'
'output filename. Such template should be Python formattable'
'string, and could use {filename}, {instrument}, and {codec}'
'variables.'
)
}
# -p opt specification (train, evaluate and separate). # -p opt specification (train, evaluate and separate).
OPT_PARAMS = { OPT_PARAMS = {
'dest': 'configuration', 'dest': 'configuration',
@@ -37,23 +49,6 @@ OPT_PARAMS = {
'help': 'JSON filename that contains params' 'help': 'JSON filename that contains params'
} }
# -n opt specification (separate).
OPT_OUTPUT_NAMING = {
'dest': 'output_naming',
'default': 'filename',
'choices': ('directory', 'filename'),
'help': (
'Choice for naming the output base path: '
'"filename" (use the input filename, i.e '
'/path/to/audio/mix.wav will be separated to '
'<output_path>/mix/<instument1>.wav, '
'<output_path>/mix/<instument2>.wav...) or '
'"directory" (use the name of the input last level'
' directory, for instance /path/to/audio/mix.wav '
'will be separated to <output_path>/audio/<instument1>.wav'
', <output_path>/audio/<instument2>.wav)')
}
# -s opt specification (separate). # -s opt specification (separate).
OPT_OFFSET = { OPT_OFFSET = {
'dest': 'offset', 'dest': 'offset',
@@ -175,7 +170,7 @@ def _create_separate_parser(parser_factory):
_add_common_options(parser) _add_common_options(parser)
parser.add_argument('-i', '--inputs', **OPT_INPUT) parser.add_argument('-i', '--inputs', **OPT_INPUT)
parser.add_argument('-o', '--output_path', **OPT_OUTPUT) parser.add_argument('-o', '--output_path', **OPT_OUTPUT)
parser.add_argument('-n', '--output_naming', **OPT_OUTPUT_NAMING) parser.add_argument('-f', '--filename_format', **OPT_FORMAT)
parser.add_argument('-d', '--duration', **OPT_DURATION) parser.add_argument('-d', '--duration', **OPT_DURATION)
parser.add_argument('-s', '--offset', **OPT_OFFSET) parser.add_argument('-s', '--offset', **OPT_OFFSET)
parser.add_argument('-c', '--codec', **OPT_CODEC) parser.add_argument('-c', '--codec', **OPT_CODEC)

View File

@@ -44,7 +44,6 @@ __license__ = 'MIT License'
_SPLIT = 'test' _SPLIT = 'test'
_MIXTURE = 'mixture.wav' _MIXTURE = 'mixture.wav'
_NAMING = 'directory'
_AUDIO_DIRECTORY = 'audio' _AUDIO_DIRECTORY = 'audio'
_METRICS_DIRECTORY = 'metrics' _METRICS_DIRECTORY = 'metrics'
_INSTRUMENTS = ('vocals', 'drums', 'bass', 'other') _INSTRUMENTS = ('vocals', 'drums', 'bass', 'other')
@@ -71,7 +70,6 @@ def _separate_evaluation_dataset(arguments, musdb_root_directory, params):
audio_filenames=mixtures, audio_filenames=mixtures,
audio_codec='wav', audio_codec='wav',
output_path=join(audio_output_directory, _SPLIT), output_path=join(audio_output_directory, _SPLIT),
output_naming=_NAMING,
max_duration=600., max_duration=600.,
MWF=arguments.MWF, MWF=arguments.MWF,
verbose=arguments.verbose), verbose=arguments.verbose),

View File

@@ -27,7 +27,9 @@ def entrypoint(arguments, params):
""" """
# TODO: check with output naming. # TODO: check with output naming.
audio_adapter = get_audio_adapter(arguments.audio_adapter) audio_adapter = get_audio_adapter(arguments.audio_adapter)
separator = Separator(arguments.configuration, arguments.MWF) separator = Separator(
arguments.configuration,
arguments.MWF)
for filename in arguments.inputs: for filename in arguments.inputs:
separator.separate_to_file( separator.separate_to_file(
filename, filename,
@@ -37,6 +39,7 @@ def entrypoint(arguments, params):
duration=arguments.duration, duration=arguments.duration,
codec=arguments.codec, codec=arguments.codec,
bitrate=arguments.bitrate, bitrate=arguments.bitrate,
filename_format=arguments.filename_format,
synchronous=False synchronous=False
) )
separator.join() separator.join()

View File

@@ -18,8 +18,9 @@ import json
from functools import partial from functools import partial
from multiprocessing import Pool from multiprocessing import Pool
from pathlib import Path from pathlib import Path
from os.path import join from os.path import basename, join
from . import SpleeterError
from .audio.adapter import get_default_audio_adapter from .audio.adapter import get_default_audio_adapter
from .audio.convertor import to_stereo from .audio.convertor import to_stereo
from .model import model_fn from .model import model_fn
@@ -93,10 +94,13 @@ class Separator(object):
self, audio_descriptor, destination, self, audio_descriptor, destination,
audio_adapter=get_default_audio_adapter(), audio_adapter=get_default_audio_adapter(),
offset=0, duration=600., codec='wav', bitrate='128k', offset=0, duration=600., codec='wav', bitrate='128k',
synchronous=True): filename_format='{filename}/{instrument}.{codec}', synchronous=True):
""" Performs source separation and export result to file using """ Performs source separation and export result to file using
given audio adapter. given audio adapter.
Filename format should be a Python formattable string that could use
following parameters : {instrument}, {filename} and {codec}.
:param audio_descriptor: Describe song to separate, used by audio :param audio_descriptor: Describe song to separate, used by audio
adapter to retrieve and load audio data, adapter to retrieve and load audio data,
in case of file based audio adapter, such in case of file based audio adapter, such
@@ -107,6 +111,7 @@ class Separator(object):
:param duration: (Optional) Duration of loaded song. :param duration: (Optional) Duration of loaded song.
:param codec: (Optional) Export codec. :param codec: (Optional) Export codec.
:param bitrate: (Optional) Export bitrate. :param bitrate: (Optional) Export bitrate.
:param filename_format: (Optional) Filename format.
:param synchronous: (Optional) True is should by synchronous. :param synchronous: (Optional) True is should by synchronous.
""" """
waveform, _ = audio_adapter.load( waveform, _ = audio_adapter.load(
@@ -115,9 +120,20 @@ class Separator(object):
duration=duration, duration=duration,
sample_rate=self._sample_rate) sample_rate=self._sample_rate)
sources = self.separate(waveform) sources = self.separate(waveform)
filename = basename(audio_descriptor)
generated = []
for instrument, data in sources.items(): for instrument, data in sources.items():
path = join(destination, filename_format.format(
filename=filename,
instrument=instrument,
codec=codec))
if path in generated:
raise SpleeterError((
f'Separated source path conflict : {path},'
'please check your filename format'))
generated.append(path)
task = self._pool.apply_async(audio_adapter.save, ( task = self._pool.apply_async(audio_adapter.save, (
join(destination, f'{instrument}.{codec}'), path,
data, data,
self._sample_rate, self._sample_rate,
codec, codec,