CLI tool
beetbox/audioread avatar
beetbox/audioread

audioread: one Python API over five audio decoding backends

cross-library (GStreamer + Core Audio + MAD + FFmpeg) audio decoding for Python

539 stars113 forksPythonMIT

At a glance

What is it?
audioread is a small Python library that decodes audio files through whichever backend happens to be installed, covering GStreamer, Core Audio, MAD, FFmpeg or Libav, and the standard library modules for uncompressed formats. The trade is that every backend is forced to the same output, 16-bit little-endian signed integer PCM, and that choice is not configurable.
Who is it for?
audioread fits a Python project that has to open whatever audio file a user hands it, on whatever platform, and that does not want to write a backend selection layer of its own. It does not fit a project that needs a specific sample format, since the PCM parameters are fixed and the README says making them configurable could be added to most of the backends, and it does not fit a deployment where shelling out to ffmpeg is not permitted.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Backend selection is the whole point

audioread is a library to decode audio files using whichever backend is available, and the list of backends is the first thing the README gives.

There is GStreamer via PyGObject. There is Core Audio on Mac OS X via ctypes, with the note that PyObjC is not required. There is MAD via the pymad bindings. There is FFmpeg or Libav via its command-line interface. And there is the standard library wave, aifc and sunau modules for uncompressed audio formats.

The mechanism is that `audio_open` transparently selects a backend that can read the file, and each backend is implemented in a module inside the audioread package. So the caller does not pick a decoder, and the caller does not have to know that one file is an MP3 and another is a FLAC, and the library does not try to be clever about the format. It tries each backend until one opens the file.

There is an escape hatch, and it is the one to reach for in production. A second optional parameter to `audio_open` specifies which backends to try, instead of trying them all, which is the default, and the `available_backends` function returns the list of backends usable on the current system. That second function is the first thing to call on a new machine, because the set of backends is determined by what is installed, and two machines running the same code can have completely different sets.

The failure modes are separated on purpose. If no backends succeed in opening the file, a `DecodeError` exception is raised, and that exception is only used when the file type is unsupported by the backends. If the file does not exist, a standard `IOError` is raised instead. So a missing file and an unsupported format are different errors, which matters when you are mapping them onto HTTP status codes or user-facing messages.

One output format, whatever came in

The API surface is small, and it is the usage example in the README.

python
    with audioread.audio_open(filename) as f:
        print(f.channels, f.samplerate, f.duration)
        for buf in f:
            do_something(buf)

Buffers in the file are accessed by iterating over the object returned from `audio_open`, and each buffer is a bytes-like object, which the README lists as buffer, bytes or bytearray, containing raw 16-bit little-endian signed integer PCM data. The parenthetical note that follows is the important caveat: currently these PCM format parameters are not configurable, but this could be added to most of the backends.

So every backend is normalised to the same representation. A 44.1 kHz stereo MP3 and a 22.05 kHz mono AIFF both come out as 16-bit little-endian PCM, and the only place the differences survive is in the metadata fields on the file object itself. Those are `channels`, the number of audio channels as an integer, `samplerate` given in Hz as an integer, and `duration`, the length of the audio in seconds as a float.

That normalisation is what makes the library usable as a drop-in for anything that consumes PCM, and it is also its sharpest constraint. A caller that wants float samples, 24-bit depth, or a preserved native sample rate has to convert outside the library, and the README is candid that the parameters are not configurable in the current version. The file object being a context manager, used with `with`, means the underlying backend resources are released when the block ends, which matters for the backends that hold a subprocess or a file handle.

The FFmpeg backend and its long list of fixes

The version history in the README is dominated by the FFmpeg backend, and reading it explains what that backend actually is: it is a wrapper around the ffmpeg or avconv command-line tool, and the wrapper deals with a lot of process management.

The 2.1.7 release properly closes some file handles in the FFmpeg backend, and the maddec backend was changed to always produce bytes objects like the other backends. The same release resolved an audio data memory leak in the GStreamer backend. Version 2.1.8 fixed an unhandled `OSError` when FFmpeg is not installed, and 2.1.5 properly cleans up the file handle when a backend fails to decode a file.

The subprocess handling has its own set of fixes. Version 1.0.2 sends SIGKILL rather than SIGTERM to ffmpeg processes to avoid occasional hangs, and 2.1.4 fixes a bug where, after closing a file, the program's standard input stream would be broken and would not receive any input. Version 3.0.1 fixed a possible deadlock when FFmpeg's version output produces too much data, which is the kind of failure that appears as a hang rather than an error. Version 2.1.6 fixed a no such process crash in the FFmpeg backend on Windows Subsystem for Linux, and 1.2.2 disabled the crash dialog when running FFmpeg on Windows.

Two of those fixes have a feature dimension rather than only a bug fix. The 2.1.0 release says the FFmpeg backend can now also use Libav's avconv command, and 3.0.0 increased the default block size in FFmpegAudioFile to get slightly faster file reading, which is a tuning knob rather than a correctness fix. The 2.1.7 release also added the option to specify which specific backends `audio_open` should try, and 3.0.0 added caching of backends for faster lookup.

The GStreamer backend, and the raw backend's pending speedup

The GStreamer backend has its own history, and it is the one that changed shape most. Version 2.0.0 moved it to GStreamer 1.x via the new gobject-introspection API, and made it compatible with Python 3. The 1.0.0 release catches GStreamer's exception when necessary components such as uridecodebin are missing, and fixes a hang when the stream finishes before it begins, which happens when reading broken files. Version 1.0.1 raises an exception when GStreamer fails to report a duration, instead of silently setting the duration field to None, which is a behaviour change worth noting for anyone who was relying on a None duration.

Later releases are mostly correctness. Version 2.1.9 works correctly with GStreamer 1.18 and later, 2.1.6 avoids suppressing SIGINT on older versions of PyGObject, and 2.1.3 avoids warnings with modern versions of GLib, which is why the library now requires at least GLib 2.32. Version 2.1.2 fixed a file descriptor leak when opening and closing many files using GStreamer, which is the kind of bug that only shows up in a long-running service.

The raw backend, the one that handles uncompressed formats through the standard library, has a pending change listed under Upcoming in the version history. It optimises the raw backend PCM conversion path in audioread/rawread.py, skipping a Python loop, and the README says this can increase loading times by up to a factor of 150x. That figure is the project's own claim about a path that is not yet in a tagged release, and the repository has no GitHub releases at all, so the current state of the raw backend has to be read from the source rather than from a version number.

Installing, and the two dependencies that changed with Python 3.13

The packaging is Poetry based, with a poetry.lock file and a pyproject.toml at the root, and the build backend is poetry.core.masonry.api. The project metadata records the package as audioread at version 3.1.0, with the author as Adrian Sampson, the readme as README.rst and the licence as MIT. The Python floor is 3.9, and the classifiers list 3.9, 3.10 and 3.11.

The runtime dependency list is short, and there is a good reason for it. The only dependencies are standard-aifc for Python 3.13 and later, and standard-sunau for Python 3.13 and later. That is the whole list, and it exists because of the 3.1.0 release note: official support for Python 3.12 and 3.13, and the replacement of the deprecated aifc and sunau modules, as they have been removed from Python 3.13 onwards.

So the dependency is conditional on the interpreter version, and that conditionality is the kind of detail that breaks installs. On Python 3.13 and above you get the community replacements for the removed standard library modules, and on earlier versions those modules are still in the standard library and no extra package is needed. The optional dependency groups are where the real backends live. The mad group installs pymad with the mad extra, and the gi group installs pygobject, with version ranges of pymad above 0.11.3 and below 0.12.0, and pygobject above 3.54.2 and below 4.0.0. The test group installs pytest at 8.4.2 or later and pytest-cov at 7.0.0 or later.

The test tooling is configured through poethepoet tasks rather than a Makefile, with a test task that runs pytest and a test-with-coverage task that records coverage over the audioread package into a reports directory, with branch coverage enabled. The CI is driven from a .github/ directory, and there is a poetry.lock in the repository to pin the resolved set.

Troubleshooting, and the decode.py script

The troubleshooting section is short and points at one specific exception. A `NoBackendError` exception means that the library could not find one of the libraries or tools it needs to decode audio, and the README's example of the cause is a broken installation of FFmpeg. The check it recommends is to type ffmpeg -version in a shell, and if that gives an error, install FFmpeg with the operating system's package manager, or with Conda from conda-forge.

The distinction between `NoBackendError` and `DecodeError` is the one to internalise. NoBackendError means the machine has no working decoder installed, which is an environment problem you fix by installing software, while DecodeError means the backends were all present and none of them could read this particular file, which is a problem with the file or the format.

The repository also ships a script for the most common job. The included decode.py script demonstrates using this package to convert compressed audio files to WAV files, and it sits at the repository root next to the audioread package directory and the test directory. It is a small example rather than a full converter, and the README does not document its command-line options.

There is a user-visible detail in the version history that belongs in any migration plan. Version 3.0.0 dropped support for Python 2 and older versions of Python 3, requiring Python 3.6 and above, and made the audio file classes inherit from a common base AudioFile class. Version 2.0.0's GStreamer rewrite and version 1.0.0's Python 3 support are the two structural changes in the list, and everything else is an incremental fix.

Where audioread is the wrong choice

Three cases point elsewhere. The first is a project that needs a specific sample format or sample rate preserved. The PCM parameters are fixed at 16-bit little-endian signed integer, the README says this is not currently configurable, and the note that it could be added to most of the backends is a statement about the code, not a plan. A pipeline that wants float samples for a machine learning model, or 24-bit depth for a mastering task, has to convert, and a conversion at 44.1 kHz stereo is not free.

The second is a deployment where spawning subprocesses is not allowed. The FFmpeg and Libav backend is a command-line wrapper, and the version history shows exactly what that costs: signal handling, file handle cleanup, a deadlock when version output is too large, a Windows crash dialog to disable, a WSL process bug, and the SIGKILL choice to avoid hangs. The GStreamer and MAD backends avoid the subprocess but add a native library dependency of their own, and the raw backend covers only uncompressed formats.

The third is a project that wants a maintained, released package with a version history to plan against. The repository has no GitHub releases, the last push to the repository was on 2026-04-09, and the version history is a README section rather than a tagged changelog. The pyproject.toml records 3.1.0, and the upcoming raw backend optimisation is listed in the README without a release attached to it.

The alternative worth weighing is calling ffmpeg directly through subprocess yourself and parsing its output, or using a library such as soundfile or librosa, and the difference in approach is where the value sits. audioread is a thin, stable abstraction whose job is to find a working decoder and normalise the output, which is exactly what you want when the input format is unknown and the platform varies. A direct ffmpeg call gives you full control over sample format, filters and metadata, and costs you the backend selection logic and the exception handling. A dedicated audio library gives you a richer data model than a PCM iterator, and costs you the freedom to decode whatever the machine happens to have. For an unknown-format, unknown-platform decoder, audioread is the smaller surface.

Editorial conclusion

audioread fits a Python project that has to open whatever audio file a user hands it, on whatever platform, and that does not want to write a backend selection layer of its own. It does not fit a project that needs a specific sample format, since the PCM parameters are fixed and the README says making them configurable could be added to most of the backends, and it does not fit a deployment where shelling out to ffmpeg is not permitted. Before you adopt it, call available_backends on the target machine to see what is actually installed, and check the version history, because the 3.1.0 release replaced the aifc and sunau modules that Python 3.13 removed, with the standard-aifc and standard-sunau packages as dependencies.

Frequently asked questions

What is audioread?

It is a Python library that decodes audio files using whichever backend is available, supporting GStreamer via PyGObject, Core Audio on Mac OS X via ctypes without PyObjC, MAD via pymad, FFmpeg or Libav through their command-line interface, and the standard library wave, aifc and sunau modules for uncompressed formats. The author is Adrian Sampson and the licence is MIT.

Which audio backends does audioread support?

GStreamer through PyGObject, Core Audio on Mac OS X through ctypes, MAD through the pymad bindings, FFmpeg or Libav through the command-line interface, and the standard library wave, aifc and sunau modules for uncompressed formats. Each backend is implemented as a module inside the audioread package, and audio_open selects one transparently.

What format does audioread return?

Every backend is normalised to raw 16-bit little-endian signed integer PCM, delivered as bytes-like buffers. The README notes that these PCM format parameters are not currently configurable, although they could be added to most of the backends, and the channels, samplerate and duration values are exposed as fields on the file object.

How do I find out which backends are available?

Call the available_backends function to get a list of the backends usable on the current system, and pass the backends you want to the second optional parameter of audio_open, which by default tries them all. A NoBackendError means no usable decoder was found, while a DecodeError means the backends were present but none could read the file.

What Python versions does audioread support?

The library supports Python 3 with a floor of 3.9, and the 3.1.0 release added official support for Python 3.12 and 3.13. Because the aifc and sunau standard library modules were removed in Python 3.13, the package depends on standard-aifc and standard-sunau for Python 3.13 and above.

Official sources

  1. beetbox/audioread on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/beetbox-audioread.svg)](https://hysenlabs.com/projects/beetbox-audioread)

Was this useful?