Skip to main content

🎵 sound_rs

PyPI Downloads Python Platforms Typed Docs License

sound_rs is a fast, Rust-powered audio library for Python that I built and maintain — decoding with symphonia (plus minimp3 for MP3), resampling with rubato, output through cpal.

Documentation: neksand.github.io/sound_rs — guides, API reference, the soundrs command and the benchmark methodology.


🚀 Features

  • Formats: WAV, MP3, FLAC, OGG/Vorbis, M4A, AAC — any bit depth, including 24-bit
  • Streaming playback: a two-hour file costs ~4 MB of RAM, not gigabytes, and the first sound arrives in ~9 ms instead of after the whole decode
  • Player: one output stream stays open — play, pause, resume, seek, stop, volume, position, duration
  • Decode to NumPy: load(path, sample_rate=, mono=, offset=, duration=) — resample to 16 kHz mono in one call, or decode only a window
  • Parallel decode: load_many(paths, sample_rate=, mono=) uses every core, GIL released
  • Recording: Recorder() captures from the microphone to a float32 array
  • Queues and live input: Player.enqueue(path) chains tracks; begin_feed/feed push samples from Python with backpressure
  • Gapless (MP3, OGG, AAC/MP4): encoder delay and padding are trimmed, so decoded audio lines up with the original
  • Fast metadata: get_audio_info reads the container header, ~1 ms regardless of file length
  • Resampling: rubato's FFT resampler with a proper anti-aliasing filter
  • Device-native output: the stream opens in whatever sample format the device wants (f32, f64, i16, i32, u8, u16)
  • Errors: everything raises sound_rs.SoundRsError with a stable .code (io, format, device, stalled, unsupported, usage)
  • Tested guarantees: no panics on corrupt input (mutation fuzzing), deterministic decode (PCM hashes in CI), underrun reporting. The full list is on the docs site.
  • No ffmpeg, no system libraries: MP3, FLAC, OGG, AAC and WAV are decoded inside the wheel; pip install sound_rs needs nothing else
  • Typed: ships sound_rs.pyi and py.typed, so editors autocomplete everything

🧠 Installation

pip install sound_rs

Wheels are built with the stable ABI (abi3-py310): one per platform — Linux x86_64 and aarch64, Windows amd64, macOS arm64 and Intel — each covering Python 3.10 and newer. Other platforms build from source.


⌨️ Command line

Installing the package also installs soundrs, so you can check the setup and read the docs without opening Python:

soundrs --help       # commands and the documentation link
soundrs devices      # output devices, default marked with *
soundrs info a.flac  # rate, channels, duration from the header
soundrs play a.flac --volume 0.5
soundrs docs         # prints https://neksand.github.io/sound_rs/

Exit codes: 0 success, 1 runtime failure, 2 bad usage.

💻 Usage

One-shot playback

import sound_rs

sound_rs.play_audio("sound.wav")          # blocks, GIL released
sound_rs.play_audio("sound.mp3", device="MacBook Pro Speakers")

The player

import sound_rs

with sound_rs.Player() as player:
    player.play_file("music.flac")   # returns immediately, streams from disk
    player.volume = 0.7
    player.seek(42.0)
    player.pause()
    player.resume()
    print(player.position, player.duration)
    player.wait()                    # block until it ends

sound_rs.list_devices()              # [(0, "MacBook Pro Speakers", True), ...]

Record

import sound_rs

with sound_rs.Recorder() as recorder:
    audio, rate = recorder.record(5.0)     # float32, (frames, channels)

Queue and live input

import numpy as np
import sound_rs

with sound_rs.Player() as player:
    player.play_file("a.flac")
    player.enqueue("b.mp3")                # plays next, own rate and layout
    player.wait()

player = sound_rs.Player()
player.begin_feed(48000)
player.feed(np.zeros(4800, dtype=np.float32))   # blocks when the buffer is full
player.end_feed()
player.wait()

Inspect and decode

sample_rate, channels, duration = sound_rs.get_audio_info("music.mp3")  # no decode
audio, rate = sound_rs.load("music.flac")                               # (frames, channels) float32
audio, rate = sound_rs.load("music.flac", sample_rate=16000, mono=True) # dataset shape

pairs = sound_rs.load_many(["a.flac", "b.flac", "c.flac"])              # parallel

From a NumPy array

import numpy as np

rate = 44100
t = np.linspace(0, 2.0, rate * 2, endpoint=False, dtype=np.float32)
sound_rs.play_array(np.sin(2 * np.pi * 440 * t), rate)   # mono, 1D
sound_rs.play_array(np.stack([left, right]), rate)       # 2D, channels first
sound_rs.play_sine_wave(440.0, 1.0, 44100)

🧩 Benchmark

Every measurement runs in its own process: peak RSS is process-wide, so timing and memory cannot share one. Median and p95 over repeated runs, competitors run side by side on the same files.

python bench/run.py                 # sound_rs only
python bench/run.py --compare       # + soundfile / sounddevice
python bench/run.py --reps 9

Hardware I measured on: Apple M5 Pro, macOS 26.6.2, Python 3.14.7, release build (lto = "fat", opt-level = 3). Competitors: libsndfile 1.2 (soundfile 0.14), PortAudio (sounddevice). Corpus: 3 s and 10 min stereo 44.1 kHz, generated by the harness.

Scoreboard — every axis in this section, side by side:

axis sound_rs best competitor ratio
import 1.1 ms 31.8 ms (soundfile) 29×
metadata (60 s file) 1.2 ms 31.7 ms (soundfile) 26×
decode WAV 130 ms 157 ms 1.2×
decode FLAC 265 ms 455 ms 1.7×
decode MP3 241 ms 268 ms 1.1×
decode AAC 349 ms not supported —
time to first sound (10 min) 11 ms 302 ms 27×
peak RAM (10 min file) 43 MB 255 MB 6×
playback overhead 30 ms 241 ms 8×
batch decode (2 files) 177 ms 299 ms 1.7×

Import time (cold process):

time peak RSS
sound_rs 1.1 ms 25 MB
soundfile 31.8 ms 34 MB
sounddevice 75.3 ms 32 MB

Metadata (60 s file): sound_rs 1.2 ms, soundfile 31.7 ms.

Decode 60 s stereo, median / p95:

format sound_rs libsndfile result PCM check
WAV 131 / 160 ms 155 ms 1.2× faster identical
FLAC 265 / 267 ms 465 ms 1.8× faster identical
MP3 247 / 249 ms 272 ms 1.1× faster 1.6e-05, 47-sample offset
M4A (AAC) 361 / 365 ms unsupported sound_rs only matches ffmpeg to 8e-08

Streaming a 10-minute FLAC — time to the first sound and peak memory:

first sound peak RSS
sound_rs Player 11.3 ms 43 MB
soundfile + sounddevice 302 ms 256 MB

Playback of a 3 s tone — overhead over the track duration:

overhead
sound_rs Player (stream kept open) +30 ms
sounddevice.play (opens a stream per call) +241 ms
sound_rs.play_array (one-shot, opens a stream) +182 ms

Batch decode two FLAC files: load_many 272 ms vs a soundfile loop 448 ms.

What the numbers do not hide:

  • MP3 output is offset by 47 samples (~1 ms) versus libsndfile and ffmpeg. Sample values agree to 1.6e-05 once aligned; the offset comes from how the decoder delay is trimmed, and the length matches exactly.
  • WAV decode is a memcpy race with libsndfile; the gap there is small by nature, the real wins are FLAC, metadata, memory and latency.
  • AAC decoding is slower than everything else — it is a newer, less tuned decoder — but libsndfile cannot read AAC at all.

🛠️ Roadmap

Step Feature Description
✅ 1 Playback + formats WAV, MP3, FLAC, OGG, M4A, 24-bit
✅ 2 NumPy integration 1D/2D arrays, load, load_many
✅ 3 Player Persistent stream: pause, seek, volume, position
✅ 4 Streaming decode Constant memory, ~9 ms to first sound
🔜 5 Device selection UI Input devices, hot-swap on disconnect
🔜 6 Recording Microphone to array or WAV
🔜 7 Effects Basic gain/fade/mix utilities

🧪 Development

cargo test                      # decode, gapless, seek, fuzzing, properties, player
cargo clippy --all-targets -- -D warnings
maturin develop --release       # build into your venv
python tests/smoke.py           # end-to-end decode + API checks
SOUND_RS_PLAY=1 python tests/smoke.py   # also plays (needs an audio device)
python tests/decode_regression.py  # PCM hashes; must not change
python docs/check_api.py        # every public name is documented
python bench/run.py --compare --report bench/REPORT.md
python3 docs/_build.py          # rebuild the documentation site

⚙️ Built With

  • 🦀 Rust — performance and safety
  • 🔗 PyO3 — Python bridge
  • 🧰 Maturin — building and publishing
  • 🔊 cpal, symphonia, minimp3, rubato — output, decoding, resampling

👨‍💻 Author

Nurassyl Mussainov Kazakhstan 🇰🇿 Python / Rust Developer

🔗 GitHub: Neksand 📦 PyPI: sound_rs


📜 License

Licensed under the MIT License — free for personal and commercial use.

Metadata

Release files for sound-rs 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sound-rs 0.3.0
File Size Uploaded Provenance Actions
sound_rs-0.3.0.tar.gz 222.2 kB Without provenance Details for sound_rs-0.3.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for sound-rs 0.3.0
File Actions
sound_rs-0.3.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details for sound_rs-0.3.0-cp310-abi3-win_amd64.whl
sound_rs-0.3.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details for sound_rs-0.3.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
sound_rs-0.3.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details for sound_rs-0.3.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
sound_rs-0.3.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details for sound_rs-0.3.0-cp310-abi3-macosx_11_0_arm64.whl
sound_rs-0.3.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details for sound_rs-0.3.0-cp310-abi3-macosx_10_12_x86_64.whl

Total release size: 7.7 MB

Release files / sound_rs-0.3.0.tar.gz

Download URL sound_rs-0.3.0.tar.gz
Size 222.2 kB
Tags Source
SHA-256 checksum
How to use checksums
5f9812fee787cf5238acd6bb5309f1db4915b1797be338da63ab3dd6201256a4
BLAKE2b-256 checksum
How to use checksums
6cd649c0885accfcc8934001e51b36329048783205dc354348860cf813788941
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / sound_rs-0.3.0-cp310-abi3-win_amd64.whl

Download URL sound_rs-0.3.0-cp310-abi3-win_amd64.whl
Size 1.4 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
079a4d03c34da7fc930e3ef83c68a1033c493ff8deb674de5aa2fa3f051b3dba
BLAKE2b-256 checksum
How to use checksums
231c3feb321f5d060806669008912066887dcd5d80322c485bb30af57796c449
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / sound_rs-0.3.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

Download URL sound_rs-0.3.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Size 1.9 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
adf488e04853c2a63d1964511df6aa308724c9ce65784dd999817b1c7538e556
BLAKE2b-256 checksum
How to use checksums
5ed6685ba0fe210824b62528a7fbe8d8178f58d4fbca9da82dd78481ea8a4849
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / sound_rs-0.3.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl

Download URL sound_rs-0.3.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
Size 1.6 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
263656e6aedf796a938217c7906736c9c9b0c04a2c406c995ac5720f733d3a06
BLAKE2b-256 checksum
How to use checksums
0fb9844e7581baf3348be3d04c842bcfec0cfda00cc0870cfc7e60d0bb533915
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / sound_rs-0.3.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL sound_rs-0.3.0-cp310-abi3-macosx_11_0_arm64.whl
Size 1.2 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
998c00a8d642cc2981aae72de8a68027be322e1f20c2c65eb4968e092c7f9a49
BLAKE2b-256 checksum
How to use checksums
769614b3278d221374c97f2849e014c24b572c658de8622caeb157871273fccf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / sound_rs-0.3.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL sound_rs-0.3.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 1.4 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
d8691e833033214a64bddb4fb37db6bc39c49b726bd8c682b3cb9c66b7b50288
BLAKE2b-256 checksum
How to use checksums
be943eed8fefbe4079b5cc96dc9df464ef4d98ce26c7226c0026181d1fef57af
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for sound-rs 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page