Cross-platform audio file decoding library that automatically selects from multiple available backends
npx @tessl/cli install tessl/pypi-audioread@3.0.0A cross-platform audio file decoding library that provides a unified interface for reading various audio formats. It automatically selects from multiple available backends (GStreamer, Core Audio, MAD, FFmpeg/Libav, standard library) to decode audio files, providing transparent cross-platform compatibility without requiring specific audio library dependencies.
pip install audioreadimport audioreadImport specific components:
from audioread import audio_open, available_backends, DecodeError, NoBackendError
from audioread import AudioFile # Base classAccess version information:
import audioread
print(audioread.__version__) # Package versionimport audioread
# Open and read an audio file
with audioread.audio_open('song.mp3') as f:
print(f"Channels: {f.channels}")
print(f"Sample rate: {f.samplerate} Hz")
print(f"Duration: {f.duration} seconds")
# Read raw PCM data
for buffer in f:
# Process 16-bit little-endian signed integer PCM data
process_audio_data(buffer)
# Check available backends on the system
backends = audioread.available_backends()
print(f"Available backends: {[b.__name__ for b in backends]}")
# Use specific backends
with audioread.audio_open('song.mp3', backends=backends) as f:
# Process with specified backends only
passaudioread uses a pluggable backend architecture that automatically selects the best available decoder:
Available backends include:
Open audio files with automatic backend selection and unified interface.
def audio_open(path, backends=None):
"""
Open an audio file using a library that is available on this system.
Parameters:
- path: str, path to the audio file
- backends: list, optional list of backend classes to try (default: all available)
Returns:
AudioFile instance with channels, samplerate, duration properties
Raises:
NoBackendError: if all backends fail to read the file
IOError: if file doesn't exist
"""Query available audio decoding backends on the current system.
def available_backends(flush_cache=False):
"""
Returns a list of backends that are available on this system.
Parameters:
- flush_cache: bool, if True, flush cache and reconstruct backend list
Returns:
List of backend classes that can be used for decoding
"""Base interface provided by all audio file objects returned from audio_open(). Note that specific backends may have variations in method signatures.
class AudioFile:
"""Base class for all audio file types."""
@property
def channels(self):
"""Number of audio channels (int)."""
@property
def samplerate(self):
"""Sample rate in Hz (int)."""
@property
def duration(self):
"""Length of the audio in seconds (float)."""
def close(self):
"""Close the underlying file."""
def __enter__(self):
"""Context manager entry."""
def __exit__(self, exc_type, exc_val, exc_tb):
"""Context manager exit."""
def __iter__(self):
"""Iterator support - yields blocks of PCM data."""Specific backend implementations (normally not used directly). Each backend has its own specific methods and parameters.
class RawAudioFile(AudioFile):
"""AIFF, WAV, or Au file reader using standard library."""
def __init__(self, filename: str):
"""Open file with standard library modules."""
def read_data(self, block_samples: int = 1024):
"""Read audio data in blocks."""
class FFmpegAudioFile(AudioFile):
"""Audio file decoder using FFmpeg command-line tool."""
def __init__(self, filename: str, block_size: int = 8192):
"""Open file with FFmpeg/avconv."""
def read_data(self, timeout: float = 10.0):
"""Read audio data with timeout."""
class GstAudioFile(AudioFile):
"""Audio file decoder using GStreamer."""
def __init__(self, filename: str):
"""Open file with GStreamer."""
class ExtAudioFile(AudioFile):
"""Audio file decoder using Core Audio on macOS."""
def __init__(self, filename: str):
"""Open file with CoreAudio."""
@property
def nframes(self):
"""Number of frames in source file."""
def setup(self, bitdepth: int = 16):
"""Set client format parameters."""
class MadAudioFile(AudioFile):
"""MPEG audio file decoder using MAD library."""
def __init__(self, filename: str):
"""Open file with MAD/pymad."""
def read_blocks(self, block_size: int = 4096):
"""Read audio data in blocks."""Exception types raised by audioread operations.
class DecodeError(Exception):
"""Base exception class for all decoding errors."""
class NoBackendError(DecodeError):
"""
The file could not be decoded by any backend.
Either no backends are available or each available backend failed.
"""Additional exceptions that may be raised by specific backends.
# Raw backend (rawread module)
class UnsupportedError(DecodeError):
"""File is not an AIFF, WAV, or Au file."""
class BitWidthError(DecodeError):
"""The file uses an unsupported bit width."""
# FFmpeg backend (ffdec module)
class FFmpegError(DecodeError):
"""Base FFmpeg error."""
class UnsupportedError(FFmpegError):
"""File could not be decoded by FFmpeg."""
class CommunicationError(FFmpegError):
"""Raised when the output of FFmpeg is not parseable."""
class NotInstalledError(FFmpegError):
"""Could not find the ffmpeg binary."""
class ReadTimeoutError(FFmpegError):
"""Reading from the ffmpeg command-line tool timed out."""
# GStreamer backend (gstdec module)
class GStreamerError(DecodeError):
"""Base GStreamer error."""
class IncompleteGStreamerError(GStreamerError):
"""Missing GStreamer base plugins."""
class UnknownTypeError(GStreamerError):
"""Raised when Gstreamer can't decode the given file type."""
class FileReadError(GStreamerError):
"""Raised when the file can't be read at all."""
class NoStreamError(GStreamerError):
"""Raised when no audio streams were found."""
class MetadataMissingError(GStreamerError):
"""Raised when GStreamer fails to report stream metadata."""
# MAD backend (maddec module)
class UnsupportedError(DecodeError):
"""File not readable by MAD library."""
# macOS Core Audio backend (macca module)
class MacError(DecodeError):
"""macOS-specific Core Audio error."""Access package version information and module-level variables.
__version__: str # Package version string (e.g., "3.0.1")
BACKENDS: list # Cached list of available backend classes
# From version module
version: str # Full version string (e.g., "3.0.1")
short_version: str # Short version string (e.g., "3.0")import audioread
def analyze_audio_file(filepath):
try:
with audioread.audio_open(filepath) as f:
print(f"File: {filepath}")
print(f"Format: {f.channels} channels, {f.samplerate} Hz, {f.duration:.2f}s")
# Calculate total samples
total_samples = int(f.samplerate * f.duration * f.channels)
print(f"Total samples: {total_samples}")
# Read in chunks and calculate RMS
rms_values = []
for chunk in f:
# Convert bytes to 16-bit integers
import struct
samples = struct.unpack(f'<{len(chunk)//2}h', chunk)
rms = (sum(s*s for s in samples) / len(samples)) ** 0.5
rms_values.append(rms)
avg_rms = sum(rms_values) / len(rms_values)
print(f"Average RMS: {avg_rms:.2f}")
except audioread.NoBackendError:
print(f"No backend could decode {filepath}")
except IOError:
print(f"File not found: {filepath}")import audioread
import wave
def convert_to_wav(input_path, output_path):
"""Convert any supported audio format to WAV."""
with audioread.audio_open(input_path) as f:
with wave.open(output_path, 'wb') as wav_file:
wav_file.setnchannels(f.channels)
wav_file.setsampwidth(2) # 16-bit samples
wav_file.setframerate(f.samplerate)
for data in f:
wav_file.writeframes(data)
print(f"Converted {input_path} to {output_path}")
# Example usage
convert_to_wav('song.mp3', 'song.wav')import audioread
def try_specific_backends(filepath):
"""Try backends in preferred order."""
# Get all available backends
all_backends = audioread.available_backends()
# Try FFmpeg first if available
ffmpeg_backends = [b for b in all_backends if 'FFmpeg' in b.__name__]
if ffmpeg_backends:
try:
with audioread.audio_open(filepath, backends=ffmpeg_backends) as f:
print(f"Opened with FFmpeg backend: {f.duration:.2f}s")
return
except audioread.DecodeError:
pass
# Fall back to any available backend
try:
with audioread.audio_open(filepath) as f:
print(f"Opened with backend: {type(f).__name__}")
except audioread.NoBackendError:
print("No backend could open the file")
# Check what backends are available
backends = audioread.available_backends()
print("Available backends:")
for backend in backends:
print(f" - {backend.__name__}")