An audio library based on libsndfile, CFFI and NumPy for reading and writing sound files
—
Object-oriented interface for advanced audio file handling with context manager support, seek operations, metadata access, and buffer-based I/O. The SoundFile class provides fine-grained control over audio file operations.
Create SoundFile objects for reading or writing audio files with extensive configuration options.
class SoundFile:
def __init__(self, file, mode='r', samplerate=None, channels=None,
subtype=None, endian=None, format=None, closefd=True,
compression_level=None, bitrate_mode=None):
"""
Create a SoundFile object for audio I/O operations.
Parameters:
- file: str or file-like, file path or file-like object
- mode: str, file mode ('r', 'w', 'x', 'r+', 'w+', 'x+')
- samplerate: int, sample rate for writing (required for write modes)
- channels: int, channel count for writing (required for write modes)
- subtype: str, audio subtype (e.g., 'PCM_16', 'FLOAT')
- endian: str, byte order ('FILE', 'LITTLE', 'BIG', 'CPU')
- format: str, file format (e.g., 'WAV', 'FLAC', 'OGG')
- closefd: bool, close file descriptor when SoundFile is closed
- compression_level: int, compression level for applicable formats
- bitrate_mode: str, bitrate mode ('CONSTANT', 'AVERAGE', 'VARIABLE')
"""Read audio data with flexible options for data types, array shapes, and output buffers.
def read(self, frames=-1, dtype='float64', always_2d=False,
fill_value=None, out=None):
"""
Read audio data from the file.
Parameters:
- frames: int, number of frames to read (-1 for all remaining)
- dtype: str or numpy.dtype, data type of output array
- always_2d: bool, return 2D array even for mono files
- fill_value: float, value to use for missing frames
- out: ndarray, pre-allocated output array
Returns:
- ndarray: audio data with shape (frames,) or (frames, channels)
"""
def buffer_read(self, frames=-1, dtype=None):
"""
Read raw audio data into a buffer.
Parameters:
- frames: int, number of frames to read (-1 for all remaining)
- dtype: str or numpy.dtype, data type for raw buffer
Returns:
- bytes: raw audio data buffer
"""
def buffer_read_into(self, buffer, dtype):
"""
Read audio data directly into an existing buffer.
Parameters:
- buffer: buffer-like, existing buffer to read into
- dtype: str or numpy.dtype, data type of buffer
Returns:
- int: number of frames actually read
"""Write audio data with support for NumPy arrays and raw buffers.
def write(self, data):
"""
Write audio data to the file.
Parameters:
- data: ndarray, audio data to write
Returns:
- None
"""
def buffer_write(self, data, dtype):
"""
Write raw audio data from a buffer.
Parameters:
- data: buffer-like, raw audio data buffer
- dtype: str or numpy.dtype, data type of buffer
Returns:
- None
"""Navigate within audio files and control file operations.
def seek(self, frames, whence=0):
"""
Seek to a position in the file.
Parameters:
- frames: int, frame position to seek to
- whence: int, reference point (SEEK_SET, SEEK_CUR, SEEK_END)
Returns:
- int: new absolute position in frames
"""
def tell(self):
"""
Return current position in frames.
Returns:
- int: current frame position
"""
def seekable(self):
"""
Check if the file supports seeking.
Returns:
- bool: True if file supports seek operations
"""
def truncate(self, frames=None):
"""
Truncate the file to a specific length.
Parameters:
- frames: int, length to truncate to (None for current position)
Returns:
- None
"""
def flush(self):
"""Flush write buffers to disk."""
def close(self):
"""Close the file."""Generate blocks of audio data for memory-efficient processing.
def blocks(self, blocksize=None, overlap=0, frames=-1, dtype='float64',
always_2d=False, fill_value=None, out=None):
"""
Return a generator for block-wise reading.
Parameters:
- blocksize: int, frames per block (default: 65536)
- overlap: int, overlapping frames between blocks
- frames: int, total frames to read (-1 for all remaining)
- dtype: str or numpy.dtype, data type of output arrays
- always_2d: bool, return 2D arrays even for mono files
- fill_value: float, value to use for missing frames
- out: ndarray, pre-allocated output array template
Yields:
- ndarray: audio data blocks
"""Handle file metadata copying between SoundFile objects.
def copy_metadata(self):
"""
Get all metadata present in this SoundFile.
Returns:
- dict: dictionary with all metadata. Possible keys are: 'title',
'copyright', 'software', 'artist', 'comment', 'date', 'album',
'license', 'tracknumber', 'genre'
"""name: str # File name or path
mode: str # File open mode
samplerate: int # Sample rate in Hz
frames: int # Total number of frames
channels: int # Number of audio channels
format: str # Major format (e.g., 'WAV', 'FLAC')
subtype: str # Audio subtype (e.g., 'PCM_16', 'FLOAT')
endian: str # Byte order ('LITTLE', 'BIG', 'FILE', 'CPU')
format_info: str # Human-readable format description
subtype_info: str # Human-readable subtype description
sections: int # Number of sections in file
closed: bool # Whether file is closed
extra_info: str # Additional information from libsndfile
compression_level: float # Compression level for writing (0.0-1.0)
bitrate_mode: str # Bitrate mode for writingReadable and writable metadata properties for audio files.
title: str # Song/track title
copyright: str # Copyright information
software: str # Software used to create the file
artist: str # Artist/performer name
comment: str # Comments or description
date: str # Creation or recording date
album: str # Album name
license: str # License information
tracknumber: str # Track number
genre: str # Musical genreimport soundfile as sf
import numpy as np
# Reading with context manager
with sf.SoundFile('input.wav', 'r') as file:
print(f'Sample rate: {file.samplerate}')
print(f'Channels: {file.channels}')
print(f'Frames: {file.frames}')
# Read all data
data = file.read()
# Read in blocks
for block in file.blocks(blocksize=1024):
# Process each block
processed = block * 0.8
# Writing with context manager
data = np.random.randn(44100, 2) # 1 second stereo
with sf.SoundFile('output.wav', 'w', samplerate=44100, channels=2) as file:
file.write(data)import soundfile as sf
with sf.SoundFile('audio.wav', 'r') as file:
# Jump to 1 second mark
file.seek(file.samplerate)
# Read 0.5 seconds of audio
data = file.read(file.samplerate // 2)
# Get current position
position = file.tell()
print(f'Current position: {position} frames')
# Seek relative to current position
file.seek(1000, sf.SEEK_CUR)
# Seek from end
file.seek(-1000, sf.SEEK_END)import soundfile as sf
# Read metadata
with sf.SoundFile('music.flac', 'r') as file:
print(f'Title: {file.title}')
print(f'Artist: {file.artist}')
print(f'Album: {file.album}')
print(f'Genre: {file.genre}')
# Write with metadata
data = np.random.randn(44100, 2)
with sf.SoundFile('output.flac', 'w', samplerate=44100, channels=2,
format='FLAC') as file:
file.title = 'My Song'
file.artist = 'My Band'
file.album = 'My Album'
file.genre = 'Electronic'
file.write(data)import soundfile as sf
import numpy as np
# Copy with processing and metadata
with sf.SoundFile('input.wav', 'r') as infile:
with sf.SoundFile('output.wav', 'w', samplerate=infile.samplerate,
channels=infile.channels, format=infile.format) as outfile:
# Copy metadata
metadata = infile.copy_metadata()
for key, value in metadata.items():
setattr(outfile, key, value)
# Process in blocks
for block in infile.blocks(blocksize=4096):
# Apply some processing
processed_block = np.tanh(block * 2.0) # Soft clipping
outfile.write(processed_block)
# Flush to ensure all data is written
outfile.flush()Install with Tessl CLI
npx tessl i tessl/pypi-soundfile