Spaces:
Running
Running
# This file is part of audioread. | |
# Copyright 2013, Adrian Sampson. | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining | |
# a copy of this software and associated documentation files (the | |
# "Software"), to deal in the Software without restriction, including | |
# without limitation the rights to use, copy, modify, merge, publish, | |
# distribute, sublicense, and/or sell copies of the Software, and to | |
# permit persons to whom the Software is furnished to do so, subject to | |
# the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be | |
# included in all copies or substantial portions of the Software. | |
"""Decode audio files.""" | |
from . import ffdec | |
from .exceptions import DecodeError, NoBackendError | |
from .version import version as __version__ # noqa | |
from .base import AudioFile # noqa | |
def _gst_available(): | |
"""Determine whether Gstreamer and the Python GObject bindings are | |
installed. | |
""" | |
try: | |
import gi | |
except ImportError: | |
return False | |
try: | |
gi.require_version('Gst', '1.0') | |
except (ValueError, AttributeError): | |
return False | |
try: | |
from gi.repository import Gst # noqa | |
except ImportError: | |
return False | |
return True | |
def _ca_available(): | |
"""Determines whether CoreAudio is available (i.e., we're running on | |
Mac OS X). | |
""" | |
import ctypes.util | |
lib = ctypes.util.find_library('AudioToolbox') | |
return lib is not None | |
def _mad_available(): | |
"""Determines whether the pymad bindings are available.""" | |
try: | |
import mad # noqa | |
except ImportError: | |
return False | |
else: | |
return True | |
# A cache for the available backends. | |
BACKENDS = [] | |
def available_backends(flush_cache=False): | |
"""Returns a list of backends that are available on this system. | |
The list of backends is cached after the first call. | |
If the parameter `flush_cache` is set to `True`, then the cache | |
will be flushed and the backend list will be reconstructed. | |
""" | |
if BACKENDS and not flush_cache: | |
return BACKENDS | |
# Standard-library WAV and AIFF readers. | |
from . import rawread | |
result = [rawread.RawAudioFile] | |
# Core Audio. | |
if _ca_available(): | |
from . import macca | |
result.append(macca.ExtAudioFile) | |
# GStreamer. | |
if _gst_available(): | |
from . import gstdec | |
result.append(gstdec.GstAudioFile) | |
# MAD. | |
if _mad_available(): | |
from . import maddec | |
result.append(maddec.MadAudioFile) | |
# FFmpeg. | |
if ffdec.available(): | |
result.append(ffdec.FFmpegAudioFile) | |
# Cache the backends we found | |
BACKENDS[:] = result | |
return BACKENDS | |
def audio_open(path, backends=None): | |
"""Open an audio file using a library that is available on this | |
system. | |
The optional `backends` parameter can be a list of audio file | |
classes to try opening the file with. If it is not provided, | |
`audio_open` tries all available backends. If you call this function | |
many times, you can avoid the cost of checking for available | |
backends every time by calling `available_backends` once and passing | |
the result to each `audio_open` call. | |
If all backends fail to read the file, a NoBackendError exception is | |
raised. | |
""" | |
if backends is None: | |
backends = available_backends() | |
for BackendClass in backends: | |
try: | |
return BackendClass(path) | |
except DecodeError: | |
pass | |
# All backends failed! | |
raise NoBackendError() | |