From 7b5222a64a4fa43e15b5cbe3e18427bac05c82d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Voituret?= Date: Wed, 20 Nov 2019 14:33:18 +0100 Subject: [PATCH] feat: add detailed ffprobe logs --- spleeter/__init__.py | 6 ++++++ spleeter/__main__.py | 35 ++++++++++++++++++++------------- spleeter/audio/adapter.py | 12 +++++++---- spleeter/audio/ffmpeg.py | 13 +++++++++--- spleeter/commands/__init__.py | 3 +-- spleeter/commands/separate.py | 4 ++-- spleeter/separator.py | 2 +- spleeter/utils/configuration.py | 8 ++++---- tests/__init__.py | 6 +++++- tests/test_pypi_sdist.sh | 10 ---------- 10 files changed, 58 insertions(+), 41 deletions(-) delete mode 100644 tests/test_pypi_sdist.sh diff --git a/spleeter/__init__.py b/spleeter/__init__.py index e369371..0650c97 100644 --- a/spleeter/__init__.py +++ b/spleeter/__init__.py @@ -16,3 +16,9 @@ __email__ = 'research@deezer.com' __author__ = 'Deezer Research' __license__ = 'MIT License' + + +class SpleeterError(Exception): + """ Custom exception for Spleeter related error. """ + + pass diff --git a/spleeter/__main__.py b/spleeter/__main__.py index 5f72040..5c18b21 100644 --- a/spleeter/__main__.py +++ b/spleeter/__main__.py @@ -10,9 +10,13 @@ import sys import warnings +from . import SpleeterError from .commands import create_argument_parser from .utils.configuration import load_configuration -from .utils.logging import enable_logging, enable_tensorflow_logging +from .utils.logging import ( + enable_logging, + enable_tensorflow_logging, + get_logger) __email__ = 'research@deezer.com' __author__ = 'Deezer Research' @@ -26,19 +30,22 @@ def main(argv): :param argv: Provided command line arguments. """ - parser = create_argument_parser() - arguments = parser.parse_args(argv[1:]) - enable_logging() - if arguments.verbose: - enable_tensorflow_logging() - if arguments.command == 'separate': - from .commands.separate import entrypoint - elif arguments.command == 'train': - from .commands.train import entrypoint - elif arguments.command == 'evaluate': - from .commands.evaluate import entrypoint - params = load_configuration(arguments.params_filename) - entrypoint(arguments, params) + try: + parser = create_argument_parser() + arguments = parser.parse_args(argv[1:]) + enable_logging() + if arguments.verbose: + enable_tensorflow_logging() + if arguments.command == 'separate': + from .commands.separate import entrypoint + elif arguments.command == 'train': + from .commands.train import entrypoint + elif arguments.command == 'evaluate': + from .commands.evaluate import entrypoint + params = load_configuration(arguments.configuration) + entrypoint(arguments, params) + except SpleeterError as e: + get_logger().error(e) def entrypoint(): diff --git a/spleeter/audio/adapter.py b/spleeter/audio/adapter.py index 59bce42..bda1441 100644 --- a/spleeter/audio/adapter.py +++ b/spleeter/audio/adapter.py @@ -16,6 +16,7 @@ import tensorflow as tf from tensorflow.contrib.signal import stft, hann_window # pylint: enable=import-error +from .. import SpleeterError from ..utils.logging import get_logger __email__ = 'research@deezer.com' @@ -73,7 +74,8 @@ class AudioAdapter(ABC): # Defined safe loading function. def safe_load(path, offset, duration, sample_rate, dtype): - get_logger().info( + logger = get_logger() + logger.info( f'Loading audio {path} from {offset} to {offset + duration}') try: (data, _) = self.load( @@ -82,10 +84,12 @@ class AudioAdapter(ABC): duration.numpy(), sample_rate.numpy(), dtype=dtype.numpy()) - get_logger().info('Audio data loaded successfully') + logger.info('Audio data loaded successfully') return (data, False) except Exception as e: - get_logger().warning(e) + logger.exception( + 'An error occurs while loading audio', + exc_info=e) return (np.float32(-1.0), True) # Execute function and format results. @@ -140,6 +144,6 @@ def get_audio_adapter(descriptor): adapter_module = import_module(module_path) adapter_class = getattr(adapter_module, adapter_class_name) if not isinstance(adapter_class, AudioAdapter): - raise ValueError( + raise SpleeterError( f'{adapter_class_name} is not a valid AudioAdapter class') return adapter_class() diff --git a/spleeter/audio/ffmpeg.py b/spleeter/audio/ffmpeg.py index 8246a58..df837b3 100644 --- a/spleeter/audio/ffmpeg.py +++ b/spleeter/audio/ffmpeg.py @@ -16,6 +16,7 @@ import numpy as np # pylint: enable=import-error from .adapter import AudioAdapter +from .. import SpleeterError from ..utils.logging import get_logger __email__ = 'research@deezer.com' @@ -54,12 +55,18 @@ class FFMPEGProcessAudioAdapter(AudioAdapter): :param sample_rate: (Optional) Sample rate to load audio with. :param dtype: (Optional) Numpy data type to use, default to float32. :returns: Loaded data a (waveform, sample_rate) tuple. + :raise SpleeterError: If any error occurs while loading audio. """ if not isinstance(path, str): path = path.decode() - probe = ffmpeg.probe(path) + try: + probe = ffmpeg.probe(path) + except ffmpeg._run.Error as e: + raise SpleeterError( + 'An error occurs with ffprobe (see ffprobe output below)\n\n{}' + .format(e.stderr.decode())) if 'streams' not in probe or len(probe['streams']) == 0: - raise IOError('No stream was found with ffprobe') + raise SpleeterError('No stream was found with ffprobe') metadata = next( stream for stream in probe['streams'] @@ -117,5 +124,5 @@ class FFMPEGProcessAudioAdapter(AudioAdapter): process.stdin.close() process.wait() except IOError: - raise IOError(f'FFMPEG error: {process.stderr.read()}') + raise SpleeterError(f'FFMPEG error: {process.stderr.read()}') get_logger().info('File %s written', path) diff --git a/spleeter/commands/__init__.py b/spleeter/commands/__init__.py index 6428d6d..47e8f53 100644 --- a/spleeter/commands/__init__.py +++ b/spleeter/commands/__init__.py @@ -84,7 +84,6 @@ OPT_CODEC = { # -b opt specification (separate). OPT_BITRATE = { 'dest': 'bitrate', - 'type': int, 'default': '128k', 'help': 'Audio bitrate to be used for the separated output' } @@ -177,8 +176,8 @@ def _create_separate_parser(parser_factory): parser.add_argument('-i', '--inputs', **OPT_INPUT) parser.add_argument('-o', '--output_path', **OPT_OUTPUT) parser.add_argument('-n', '--output_naming', **OPT_OUTPUT_NAMING) - parser.add_ parser.add_argument('-d', '--duration', **OPT_DURATION) + parser.add_argument('-s', '--offset', **OPT_OFFSET) parser.add_argument('-c', '--codec', **OPT_CODEC) parser.add_argument('-b', '--birate', **OPT_BITRATE) parser.add_argument('-m', '--mwf', **OPT_MWF) diff --git a/spleeter/commands/separate.py b/spleeter/commands/separate.py index 2fbbfee..b501205 100644 --- a/spleeter/commands/separate.py +++ b/spleeter/commands/separate.py @@ -28,13 +28,13 @@ def entrypoint(arguments, params): # TODO: check with output naming. audio_adapter = get_audio_adapter(arguments.audio_adapter) separator = Separator(arguments.configuration, arguments.MWF) - for filename in arguments.audio_filenames: + for filename in arguments.inputs: separator.separate_to_file( filename, arguments.output_path, audio_adapter=audio_adapter, offset=arguments.offset, - duration=arguments.max_duration, + duration=arguments.duration, codec=arguments.codec, bitrate=arguments.bitrate, synchronous=False diff --git a/spleeter/separator.py b/spleeter/separator.py index a5f4efd..79478d9 100644 --- a/spleeter/separator.py +++ b/spleeter/separator.py @@ -57,7 +57,7 @@ class Separator(object): self._predictor = to_predictor(estimator) return self._predictor - def join(self, timeout=20): + def join(self, timeout=200): """ Wait for all pending tasks to be finished. :param timeout: (Optional) task waiting timeout. diff --git a/spleeter/utils/configuration.py b/spleeter/utils/configuration.py index 03db200..d1fb167 100644 --- a/spleeter/utils/configuration.py +++ b/spleeter/utils/configuration.py @@ -13,7 +13,7 @@ except ImportError: from os.path import exists -from .. import resources +from .. import resources, SpleeterError __email__ = 'research@deezer.com' @@ -31,17 +31,17 @@ def load_configuration(descriptor): :param descriptor: Configuration descriptor to use for lookup. :returns: Loaded description as dict. :raise ValueError: If required embedded configuration does not exists. - :raise IOError: If required configuration file does not exists. + :raise SpleeterError: If required configuration file does not exists. """ # Embedded configuration reading. if descriptor.startswith(_EMBEDDED_CONFIGURATION_PREFIX): name = descriptor[len(_EMBEDDED_CONFIGURATION_PREFIX):] if not loader.is_resource(resources, f'{name}.json'): - raise ValueError(f'No embedded configuration {name} found') + raise SpleeterError(f'No embedded configuration {name} found') with loader.open_text(resources, f'{name}.json') as stream: return json.load(stream) # Standard file reading. if not exists(descriptor): - raise IOError(f'Configuration file {descriptor} not found') + raise SpleeterError(f'Configuration file {descriptor} not found') with open(descriptor, 'r') as stream: return json.load(stream) diff --git a/tests/__init__.py b/tests/__init__.py index 3b800d9..f584f49 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,4 +1,8 @@ #!/usr/bin/env python # coding: utf8 -""" TO DOCUMENT """ \ No newline at end of file +""" Unit testing package. """ + +__email__ = 'research@deezer.com' +__author__ = 'Deezer Research' +__license__ = 'MIT License' diff --git a/tests/test_pypi_sdist.sh b/tests/test_pypi_sdist.sh deleted file mode 100644 index c514062..0000000 --- a/tests/test_pypi_sdist.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -###################################################################### -# Script that performs PyPi packaging test. -# -# @author Deezer Research -# @version 1.0.0 -###################################################################### - - twine upload --repository-url https://test.pypi.org/legacy/ dist/* \ No newline at end of file