mrkeyoor.com_
Sat 08 Aug 17:41 UTC
PyPIUtilsupdated 08 Aug 2026

soundfile

SoundFile is a Python interface to the libsndfile C library. It reads sampled-audio files into NumPy arrays, writes arrays back to formats such as WAV, FLAC, OGG, MAT, and supported MP3 variants, streams large files in blocks, and exposes seekable file handles for frame-level access. CFFI bridges Python to libsndfile, while platform wheels usually carry the native library. It does file format I/O only: there is no resampling, decoding through FFmpeg, playback, feature extraction, effects graph, or audio-device API.

Verdict

SoundFile is the clean default for NumPy audio I/O when libsndfile supports every required format. Choose an FFmpeg-based tool for broad codec coverage, and add a signal-processing library when reading and writing are only the first step.

API stability4/5The read, write, blocks, info, SoundFile, and virtual-I/O interfaces have been stable for years, and the README records old breaking changes rather than hiding them. The most important defaults, including mono dimensionality and write argument order, settled before the current line. Native libsndfile behavior can still change format support beneath the Python API, and deprecated buffer ctype arguments show that low-level details are not frozen forever.
Docs5/5The project documents installation across wheel and source scenarios, packaged-versus-system native-library precedence, read/write examples, block processing, frame semantics, RAW parameters, virtual files, in-memory conversion, compression controls, exception classes, and specific thread-safety boundaries. It also names the OGG and Buildroot known issues. That is the operational detail an audio I/O wrapper needs, not just a generated function reference.
Maintenance4/5PyPI lists 0.14.0, GitHub was pushed on 2026-07-14, and current metadata supports Python 3.10 and later including modern platforms. The repository has 849 stars and 135 open issues and pull requests, a meaningful queue for a thin wrapper whose bugs often originate in native libsndfile. Recent activity and updated wheel coverage are good signs, though the project depends on another upstream's codec and security maintenance.
Ecosystem5/5SoundFile recorded roughly seven million weekly downloads in the supplied package queue and sits naturally in the NumPy and scientific-Python stack. Libraries such as librosa commonly build higher-level workflows around the same array model. Common-platform wheels bundle libsndfile, greatly reducing installation friction. The boundary remains clear: codec breadth follows libsndfile, while playback, resampling, analysis, and device capture come from other packages.

Use it if

  • You need simple NumPy-based reading and writing for formats supported by libsndfile
  • You want block iteration or explicit frame seeking without loading an entire recording
  • You need audio I/O from BytesIO, an uploaded file object, or another virtual file
  • You want a thin file-format layer under signal-processing code you already own
Skip it if

Setup reality

SoundFile 0.14.0 requires Python 3.10 or newer and declares CFFI, NumPy, and typing-extensions as Python dependencies. The package itself has no compiled extension, but every operation depends on libsndfile. Wheels for common 64-bit and 32-bit Windows, Windows ARM64, Intel and ARM macOS, and 64-bit or AArch64 Linux include a current native library. On an unusual architecture, source build, minimal container, or distribution policy that forbids bundled native code, install libsndfile separately, such as libsndfile1 on Debian-family images. Since 0.12, packaged libsndfile is preferred over a system copy; install from source if using the system version is a deliberate requirement. Format support and bugs therefore depend on which native library actually loads, not only the Python package version. By default sf.read returns float64 and mono files are one-dimensional because always_2d defaults to False. Choose dtype and always_2d explicitly when downstream tensor shapes and memory matter. Integer reads do not normalize samples to floating point, and writing floats to an integer subtype quantizes them. RAW data has no header, so channels, sample rate, subtype, and sometimes endian must be supplied correctly. For long recordings use blocks or SoundFile.read with a frame count; a full-file read can allocate far more memory than the compressed file size suggests. Use a context manager so native handles close deterministically. File-like objects must be seekable for many formats, and in-memory output must be rewound before reading. Do not share a SoundFile handle between threads, and do not let multiple threads write the same file. Catch LibsndfileError for decoder failures and inspect code and error_string, while ordinary misuse may raise ValueError or TypeError. Pin and test the wheel/native combination for OGG writing and any codec that matters in production.

Patterns

Read samples and their stored rateread-audio

import soundfile as sf

audio, sample_rate = sf.read('voice.flac', dtype='float32', always_2d=True)
print(audio.shape, sample_rate)

always_2d keeps mono as shape (frames, 1). Without it, mono input returns a one-dimensional array.

Write a WAV with an explicit subtypewrite-audio

import soundfile as sf

sf.write('output.wav', audio, sample_rate, subtype='PCM_16')

Floating-point arrays are quantized when written to PCM_16. Choose a subtype deliberately instead of relying on the format default.

Convert a supported file to FLACcopy-to-flac

import soundfile as sf

data, rate = sf.read('input.wav', dtype='float32')
sf.write('output.flac', data, rate)

This changes the container and encoding but does not resample or normalize the signal.

Inspect metadata without reading samplesinspect-file

import soundfile as sf

meta = sf.info('recording.wav')
print(meta.frames, meta.samplerate, meta.channels, meta.format, meta.subtype)

Use info before allocating a full array so you can reject unexpected duration, channels, or sample rate.

Process a long file in overlapping blocksprocess-blocks

import numpy as np
import soundfile as sf

for block in sf.blocks('long.wav', blocksize=4096, overlap=1024, dtype='float32'):
    rms = np.sqrt(np.mean(block ** 2, axis=0))
    print(rms)

Overlapping blocks repeat samples between iterations. Account for overlap when aggregating durations or statistics.

Read selected frames through a managed handleseek-and-read

import soundfile as sf

with sf.SoundFile('interview.flac') as f:
    f.seek(10 * f.samplerate)
    ten_seconds = f.read(10 * f.samplerate, dtype='float32', always_2d=True)

Positions and counts are frames, not individual channel samples or bytes. The context manager closes the native handle.

Describe headerless RAW inputread-raw-audio

import soundfile as sf

data, rate = sf.read(
    'capture.raw',
    channels=1,
    samplerate=48000,
    subtype='PCM_16',
    endian='LITTLE',
)

RAW files cannot be auto-detected. Incorrect channels, subtype, rate, or endianness can yield plausible-looking but wrong samples.

Convert uploaded audio without a temporary fileconvert-in-memory

from io import BytesIO
import soundfile as sf

source = BytesIO(upload_bytes)
source.name = 'upload.ogg'
data, rate = sf.read(source)
out = BytesIO()
out.name = 'audio.wav'
sf.write(out, data, rate, format='WAV', subtype='PCM_16')
out.seek(0)
result_bytes = out.read()

Rewind the output before reading. Supplying format is safer than depending on a file-like object's synthetic name.

Control supported lossy compressionset-compression

import soundfile as sf

sf.write(
    'speech.mp3', audio, sample_rate,
    bitrate_mode='VARIABLE',
    compression_level=0.8,
)

compression_level ranges from 0 to 1 and support depends on format plus the loaded libsndfile version.

Report native decoder errorshandle-decode-errors

import soundfile as sf

try:
    audio, rate = sf.read(path)
except sf.LibsndfileError as exc:
    print('libsndfile code:', exc.code)
    print('decoder message:', exc.error_string)
    raise

API misuse may raise ValueError or TypeError instead. Do not assume every failure is a LibsndfileError.

Check available formats and subtypescheck-format-support

import soundfile as sf

formats = sf.available_formats()
if 'FLAC' not in formats:
    raise RuntimeError('This libsndfile build lacks FLAC support')
print(sf.available_subtypes('FLAC'))

Capabilities come from the libsndfile instance loaded at runtime and can differ between wheel and system-library deployments.

Alternatives

PackageRegistryPick it when
scipyPyPIYou only need WAV I/O and already depend on SciPy for signal processing
pydubPyPIYou want simple edits and broad format conversion and can install FFmpeg or another external backend
librosaPyPIYou need resampling, analysis, features, and higher-level music or speech workflows on top of file loading