Skip to content

About

Native audio I/O for MLX on macOS and Linux

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Repository files navigation

mlx-audio-io

The native audio data layer for Apple MLX: fast file decode and encode directly to and from mlx.core.array, with one unified API across macOS and Linux.

  • Zero-Copy MLX Pipeline: Direct decode and encode via DLPack capsules (mx.from_dlpack) and the Python buffer protocol.
  • Zero Torch, Zero NumPy: MLX is the sole required runtime dependency. No heavyweight PyTorch or NumPy runtime overhead.
  • Apple Silicon Optimized: Native macOS backend powered by Apple AudioToolbox loads a WAV 6.8x faster than librosa and saves one 1.5x faster than SoundFile on an M4 Max (measurements).
  • Decoupled Architecture: Upgrading mlx never requires rebuilding mlx-audio-io. One build works with any installed MLX (0.32.0+).
  • Concurrent Writer Engine: Staged buffer preparation (prepare_save / save_prepared) releases the Python GIL and avoids MLX contention across background export workers.

Installation

pip install mlx-audio-io

Prebuilt wheels are published for macOS 14 or later on Apple Silicon (Python 3.10 to 3.14), so nothing is compiled there. Other platforms build from source during install; see the Installation Guide for the compiler and Linux packages that needs.

MLX Compatibility

mlx-audio-io requires:

  • macOS: mlx>=0.32.0 (Apple Silicon)
  • Linux: mlx[cpu]>=0.32.0

Because decoded audio enters MLX via DLPack and save operations consume arrays through the buffer protocol, mlx-audio-io does not link against libmlx.dylib. Upgrading MLX versions in your environment does not require rebuilding mlx-audio-io.

For Linux build dependencies, source checkout, and troubleshooting, see the Installation Guide.


Quickstart

1. Load Audio

import mlx_audio_io as audio_io

# Decode native format directly into an mx.array: [frames, channels]
audio, sr = audio_io.load("speech.wav")

# Load with automatic high-quality resampling and mono fold-down
audio_16k, sr_16k = audio_io.load("speech.wav", sr=16000, mono=True)

2. Save Audio

# Save float32 or pcm16 WAV
audio_io.save("out.wav", audio, sr)
audio_io.save("out_pcm16.wav", audio, sr, encoding="pcm16")

# Save compressed formats (MP3, AAC/M4A, FLAC)
audio_io.save("out.mp3", audio, sr, bitrate="192k")
audio_io.save("out.m4a", audio, sr, bitrate="256k")
audio_io.save("out.flac", audio, sr)

3. Chunked Streaming

Stream long audio files in fixed-duration chunks without decoding the whole file into RAM:

for chunk, chunk_sr in audio_io.stream("long_recording.wav", chunk_duration=2.0):
    # chunk is an mx.array of shape [frames, channels]
    process(chunk)

4. Concurrent Background Export

For multi-stem export pipelines (e.g. Demucs, audio separators), stage the buffer once on the producer thread and delegate writing to background file workers:

from concurrent.futures import ThreadPoolExecutor
import mlx_audio_io as audio_io

# Producer: stage read-only view and evaluate lazy MLX graph
prepared = audio_io.prepare_save(stem, layout="channels_first")

# Worker threads: encode and write without holding the Python GIL
with ThreadPoolExecutor(max_workers=4) as workers:
    workers.submit(audio_io.save_prepared, "vocals.wav", prepared, 44100, encoding="pcm16")

5. Fast Metadata Inspection

Read container metadata in microseconds without reading or decoding sample frames:

meta = audio_io.info("speech.wav")
print(meta.duration, meta.sample_rate, meta.channels, meta.subtype)

API Overview

Function / Class Description Documentation
load Decode audio file to mx.array with optional resampling, slicing, and mono mix Details
save Write mx.array or buffer-compatible array to WAV, MP3, M4A, FLAC, AIFF Details
prepare_save Stage evaluated buffer view on producer for concurrent export threads Details
save_prepared File encoder for background worker threads (releases the GIL while encoding) Details
PreparedAudio Read-only audio buffer wrapper preserving strides and memory layout Details
stream Generator yielding fixed-frame or fixed-duration mx.array chunks Details
info Fast header inspection returning AudioInfo (frames, duration, channels) Details
batch_load Multi-threaded multi-file audio decoding into a list of mx.array Details
supports_soxr Check whether high-quality libsoxr resampling support is enabled Details

For complete signatures and parameter contracts, see the Full API Reference.


Platform Backends

Capability macOS Backend Linux Backend
Engine Apple AudioToolbox Native C++ WAV/MP3 + libav (FFmpeg)
Supported Formats WAV, MP3, M4A/AAC, FLAC, AIFF, CAF WAV, MP3, FLAC, M4A/AAC, AIFF, CAF
Encodings float32, pcm16, alac (lossless M4A) float32, pcm16, alac (lossless M4A)
Resampling AudioToolbox (best) / libsoxr (soxr_vhq) Native linear / libav / libsoxr
Streaming Full chunked streaming across all formats Full chunked streaming across all formats

Performance Highlights

Measured on Apple M4 Max (macOS 27.0) on a 194.8-second stereo 44.1 kHz PCM16 WAV track (median p50 latency):

Operation macOS M4 Max vs librosa / soundfile vs torchaudio
Full WAV Load 3.74 ms 6.8x faster than librosa 9.2x faster
WAV Partial Read (1s) 0.05 ms 3.4x faster than librosa 708x faster
MP3 Load (native SR) 37.88 ms 1.1x faster than librosa 1.9x faster
WAV Save (Float32) 14.07 ms 1.5x faster than SoundFile 1.5x faster
Save Prepared (save_prepared) 13.77 ms 1.5x faster than SoundFile 1.6x faster
Load + Resample (16 kHz, fastest) 10.76 ms 5.6x faster than librosa 5.0x faster
Load + Resample (16 kHz, best) 33.17 ms 1.8x faster than librosa 1.6x faster

For complete benchmarking methodology, Linux arm64/x86_64 numbers, and tail latency profiles, see Benchmarking & Performance.


Documentation


License

MIT

About

Native audio I/O for MLX on macOS and Linux

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages