Lightweight full-featured audio playback in Python, built on Miniaudio
Project description
SoundObj
A modern Python wrapper for the miniaudio library, providing high-level audio playback and 3D spatialization capabilities.
Another audio library? Why?
It's a reasonable question.
The short version is that I couldn't find one that did what I wanted.
As of mid-2025, you either get a specialized set of features (playsound), a bloated installation that does way more than sound (pyglet/pygame/etc), licensing restrictions (bass/sound_lib), EOL/lack of support (Libaudioverse/Synthizer), data sciency stuff, or low-level interfaces (PyAudio/PyMiniaudio).
To be clear, I'm not knocking any of these libraries. I have used all of them once or twice, and have code in both pybass and sound_lib. At the time of writing, they are admitedly far more battle tested. In fact, I am likely to use them again and encourage you to do the same if they better serve your use case.
That said, I wanted something portable, permissive, and that just works with an API that is familiar or that someone could pick up and immediately start hacking on.
Features
- Truly simple audio playback
- Support for WAV, MP3, FLAC, OGG Vorbis, Opus, and everything else miniaudio is able to work with
- Adjust volume, pitch, pan, and spatial properties during playback
- Full support for positional audio, distance attenuation, and Doppler effects
- Stream audio directly from HTTP/FTP(s) URLs, including live streams
- Clean property-based Python interface
- Support for multiple 3D audio listeners
- Customizable engine settings for different use cases
- Easy to extend, assuming you know a little bit of C and feel comfortable adding FFI declarations
Installation
Prerequisites
- Python 3.13+
- cffi library
- vcpkg (included as submodule in vcpkg/ directory)
- miniaudio library (pulled in by vcpkg)
- curl (pulled in by vcpkg), used for URL streams
Build Instructions
- Clone the repository with submodules:
git clone --recursive https://github.com/cartertemm/soundobj.git
cd soundobj
Or if you already have a clone of the repository:
cd soundobj
git submodule update --init --recursive
- Install Python dependencies:
pip install cffi
- Build the FFI wrapper (will automatically handle VCPKG):
python build_ffi.py
Testing
After building the FFI wrapper, run the test suite with:
pytest tests/
Tests that require a real audio device are skipped automatically on headless machines. No additional dependencies beyond pytest are needed.
Roadmap
- Upload to PyPI
- Memory streams
- A more comprehensive environment for managing multiple sounds simultaniously
- More demos/examples
- Optional support for HRTF, now that Steam Audio has been made open-source and is licensed under Apache-2.0. This wouldn't be included by default but would be an optional dependency for those who need it.
How you can help
Test, test, test. If you get weird behavior, open an issue and tell me about it. If you are willing and able, hack on one of these features.
Quick Start
Most things should be pretty self explanatory, as this library is a high-level API over the already high-level ma_engine API. If not, the Miniaudio programming manual is a good starting point. It explains concepts like the coordinate system, positioning in 3D space, attenuation, etc.
One-line audio playback
Just want a quick sound or earcon to play and don't care about anything else?
import soundobj
soundobj.play_sound("path/to/audio.wav") # Sound is already playing! It will automatically close when complete and you do not have any control over the sound after this point.
Basic Audio Playback with controls
import soundobj
# Create a sound object and load an audio file
snd = soundobj.Sound(source="path/to/audio.wav")
snd.play() # Play the sound
snd.looping = True # Enable looping
snd.volume = 0.8
snd.pitch = 1.2
# Wait a bit
snd.stop()
Streaming audio from a URL
Pass any http:// or https:// URL as the source and it works the same as a local file. This includes both regular audio files and live streams (e.g. internet radio) where the duration isn't known in advance.
import soundobj
snd = soundobj.Sound(source="https://example.com/audio.mp3")
snd.play()
# Or an internet radio stream
radio = soundobj.Sound(source="https://stream.example.com/live")
radio.play()
radio.volume = 0.5
3D Spatial Audio
import soundobj
from soundobj import AttenuationModel, PositioningMode
# Create an engine with custom configuration
config = soundobj.EngineConfig(
channels=2,
sampleRate=44100,
listenerCount=1
)
engine = soundobj.Engine(config)
# Create a 3D positioned sound and enable spacialization
sound = soundobj.Sound(engine, "footsteps.wav")
sound.spatialization_enabled = True
# Position the sound in 3D space
sound.position = (5.0, 0.0, 10.0) # (x, y, z)
sound.direction = (0.0, 0.0, -1.0) # facing negative Z
# Configure distance attenuation
sound.attenuation_model = AttenuationModel.INVERSE
sound.min_distance = 1.0
sound.max_distance = 100.0
sound.rolloff = 2.0
# Set up velocity for Doppler effect
sound.velocity = (-2.0, 0.0, 0.0) # moving left
# Configure sound cone for directional audio
sound.cone = (0.5, 1.0, 0.3) # (inner_angle, outer_angle, outer_gain)
sound.play()
Engine and Listener Management
import soundobj
engine = soundobj.Engine()
# Get engine information
print(f"Channels: {engine.channels}")
print(f"Sample Rate: {engine.sample_rate}")
print(f"Listeners: {engine.listener_count}")
# Configure listener position and orientation
engine.set_listener_position(0, 0.0, 0.0, 0.0) # listener at origin
engine.set_listener_direction(0, 0.0, 0.0, 1.0) # facing positive Z
engine.set_listener_velocity(0, 1.0, 0.0, 0.0) # moving right
# Set world up vector (for 3D orientation)
engine.set_listener_world_up(0, 0.0, 1.0, 0.0) # Y is up
# Enable/disable listeners
engine.set_listener_enabled(0, True)
API Reference
Classes
Engine
The main audio engine that manages playback and 3D audio processing globally. A default global engine is created automatically at import, so most code can start with Sound directly and only instantiate Engine when custom configuration is needed.
Properties:
volume: Master volume (0.0 to 1.0+)channels: Number of output channels (read-only)sample_rate: Audio sample rate in Hz (read-only)time_in_milliseconds: Current engine time (read-only)listener_count: Number of 3D listeners (read-only)
Methods:
start(): Start the audio enginestop(): Stop the audio engineplay_sound(file_path, group=None): Play a sound file directlyfind_closest_listener(x, y, z): Find nearest listener to positionset_listener_position(index, x, y, z): Set listener positionget_listener_position(index): Get listener positionset_listener_direction(index, x, y, z): Set listener orientationget_listener_direction(index): Get listener orientation
Sound
Represents an individual audio sound with full control over playback and 3D properties.
Basic Properties:
volume: Sound volume (0.0 to 1.0+)pitch: Playback speed/pitch multiplier (1.0 = normal)pan: Stereo pan (-1.0 = left, 0.0 = center, 1.0 = right)looping: Enable/disable looping playbackis_playing: Check if currently playing (read-only)length_in_seconds: Audio duration (read-only)position_in_seconds: Current playback position (get/set)
3D Spatial Properties:
position: 3D position as (x, y, z) tupledirection: Direction vector as (x, y, z) tuplevelocity: Velocity vector for Doppler effectspatialization_enabled: Enable/disable 3D audio processingattenuation_model: Distance attenuation model (enum or string)positioning: Positioning mode (enum or string)
Distance and Attenuation:
rolloff: Distance attenuation rolloff factormin_distance: Minimum distance for attenuationmax_distance: Maximum distance for attenuationmin_gain: Minimum volume levelmax_gain: Maximum volume level
Advanced 3D Properties:
cone: Directional audio cone as (inner_angle, outer_angle, outer_gain)doppler_factor: Doppler effect intensity (1.0 = normal)directional_attenuation_factor: Directional volume reductiondirection_to_listener: Vector pointing to listener (read-only)pinned_listener_index: Pin sound to specific listenerlistener_index: Current listener index (read-only)
Methods:
load(source, stream=True): Load audio from a file path, URL, or bytes; auto-detects the source typeload_from_file(filename, stream=True): Load from fileload_from_url(url, stream=True): Load from an HTTP/HTTPS URL; works for both regular files and live streamsload_from_memory(data, stream=True): Load from memory (not implemented, raisesNotImplementedError)play(): Start playbackpause(): Pause playbackstop(): Stop playbackfade_in(duration_ms, start_volume=0.0, end_volume=1.0): Fade in effectfade_out(duration_ms, end_volume=0.0): Fade out effect
EngineConfig
Configuration options for engine initialization.
Attributes:
listenerCount: Number of 3D listeners (default: 0 = auto)channels: Output channels (default: 0 = auto)sampleRate: Sample rate in Hz (default: 0 = auto)periodSizeInFrames: Period size in frames (default: 0 = auto)periodSizeInMilliseconds: Period size in ms (default: 0 = auto)noAutoStart: Don't auto-start engine (default: False)noDevice: Initialize without audio device (default: False)
Global functions
play_sound
play_sound(path, group = None) -> bool
Plays what miniaudio calls an inline sound. They're meant for convenience as it takes only one line of code to get one playing and you don't have to manage keeping it alive. The sacrifice however is that you get 0 control over the sound once it starts playing. Returns True if the sound played successfully, False otherwise.
The group parameter will allow you to attach such a sound to a ma_sound_group thus giving you volume/positioning control, keep it set at None for now (WIP at this time).
Enums
AttenuationModel
Distance-based volume attenuation models:
NONE: No distance attenuationINVERSE: Realistic inverse distance attenuationLINEAR: Linear distance attenuationEXPONENTIAL: Exponential distance attenuation
PositioningMode
Sound positioning modes:
ABSOLUTE: Position in world coordinatesRELATIVE: Position relative to listener
Exceptions
MiniAudioError
Raised when miniaudio operations fail (engine initialization, file loading, etc.).
Licensing
This module is both released under the MIT and into the public domain. Choose which ever you prefer.
MIT
Copyright (c) 2025 Carter Temm
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Public Domain
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Acknowledgments
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file soundobj-0.3.0-cp314-cp314-win_amd64.whl.
File metadata
- Download URL: soundobj-0.3.0-cp314-cp314-win_amd64.whl
- Upload date:
- Size: 827.9 kB
- Tags: CPython 3.14, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fdb475c9da65ea2d60ad0830e23b2ee75dc81376876fb2ea5bbf8feb6524c873
|
|
| MD5 |
d5e6be5c4dab88fb144ef4374e8dd714
|
|
| BLAKE2b-256 |
156edc668946f8265c3bbc1d6d021ca67c210f0345267c48ddde4b180b1cfd43
|
Provenance
The following attestation bundles were made for soundobj-0.3.0-cp314-cp314-win_amd64.whl:
Publisher:
build.yml on cartertemm/soundobj
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soundobj-0.3.0-cp314-cp314-win_amd64.whl -
Subject digest:
fdb475c9da65ea2d60ad0830e23b2ee75dc81376876fb2ea5bbf8feb6524c873 - Sigstore transparency entry: 1794140084
- Sigstore integration time:
-
Permalink:
cartertemm/soundobj@a4d05c20f9b478f5f8f60f76e8be5ed7bbd12f35 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/cartertemm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build.yml@a4d05c20f9b478f5f8f60f76e8be5ed7bbd12f35 -
Trigger Event:
push
-
Statement type:
File details
Details for the file soundobj-0.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.
File metadata
- Download URL: soundobj-0.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- Upload date:
- Size: 5.0 MB
- Tags: CPython 3.14, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9aff0cc87f59be3d1878ce4863e0d9805cc82fb9971de91a52584755900100c
|
|
| MD5 |
2bcc4207128d79e3a3feffdff314eb34
|
|
| BLAKE2b-256 |
56927e2556c61f1f2ec63716930871834cc27be22a03c723f42d14bfe2fadf39
|
Provenance
The following attestation bundles were made for soundobj-0.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl:
Publisher:
build.yml on cartertemm/soundobj
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soundobj-0.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl -
Subject digest:
e9aff0cc87f59be3d1878ce4863e0d9805cc82fb9971de91a52584755900100c - Sigstore transparency entry: 1794138831
- Sigstore integration time:
-
Permalink:
cartertemm/soundobj@a4d05c20f9b478f5f8f60f76e8be5ed7bbd12f35 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/cartertemm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build.yml@a4d05c20f9b478f5f8f60f76e8be5ed7bbd12f35 -
Trigger Event:
push
-
Statement type:
File details
Details for the file soundobj-0.3.0-cp314-cp314-macosx_11_0_arm64.whl.
File metadata
- Download URL: soundobj-0.3.0-cp314-cp314-macosx_11_0_arm64.whl
- Upload date:
- Size: 3.9 MB
- Tags: CPython 3.14, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b5311ffd9929cd482b16cbba39b0355188f8dd69e9d9ad868d94a2b4d194864
|
|
| MD5 |
2e1b922e3cc9c267f50a980928718f10
|
|
| BLAKE2b-256 |
e98a34796a526fc4194e106245b2d7c3d60a76460d4ac8ede0f9b33e55023d97
|
Provenance
The following attestation bundles were made for soundobj-0.3.0-cp314-cp314-macosx_11_0_arm64.whl:
Publisher:
build.yml on cartertemm/soundobj
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soundobj-0.3.0-cp314-cp314-macosx_11_0_arm64.whl -
Subject digest:
3b5311ffd9929cd482b16cbba39b0355188f8dd69e9d9ad868d94a2b4d194864 - Sigstore transparency entry: 1794139919
- Sigstore integration time:
-
Permalink:
cartertemm/soundobj@a4d05c20f9b478f5f8f60f76e8be5ed7bbd12f35 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/cartertemm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build.yml@a4d05c20f9b478f5f8f60f76e8be5ed7bbd12f35 -
Trigger Event:
push
-
Statement type:
File details
Details for the file soundobj-0.3.0-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: soundobj-0.3.0-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 802.4 kB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
018d048a8fafd902fea2e15f9e20a9d11d664fe2e9a0c5999d2618c6de126968
|
|
| MD5 |
969bf55dd34f06e2585225e2c65d5e52
|
|
| BLAKE2b-256 |
4427dcedf6f84ef650ebf29811b2e567ea4003871eaaded3e0ba4802d88b72da
|
Provenance
The following attestation bundles were made for soundobj-0.3.0-cp313-cp313-win_amd64.whl:
Publisher:
build.yml on cartertemm/soundobj
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soundobj-0.3.0-cp313-cp313-win_amd64.whl -
Subject digest:
018d048a8fafd902fea2e15f9e20a9d11d664fe2e9a0c5999d2618c6de126968 - Sigstore transparency entry: 1791415198
- Sigstore integration time:
-
Permalink:
cartertemm/soundobj@f4e7e929ab7c1f0ff0ede213f58c1d222dd38a69 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/cartertemm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build.yml@f4e7e929ab7c1f0ff0ede213f58c1d222dd38a69 -
Trigger Event:
push
-
Statement type:
File details
Details for the file soundobj-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: soundobj-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 5.0 MB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8490a531ae61cac87e8c9fa054ccc2ff65c0c75cbc4d460812ed4e0c27ebf82c
|
|
| MD5 |
7b725d5dcfef845e1c9e1bfce00d379a
|
|
| BLAKE2b-256 |
d4805d4f0efcceacbc42c1c016401a4d3adef4c6495b575a160f14fb398ec757
|
Provenance
The following attestation bundles were made for soundobj-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
build.yml on cartertemm/soundobj
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soundobj-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
8490a531ae61cac87e8c9fa054ccc2ff65c0c75cbc4d460812ed4e0c27ebf82c - Sigstore transparency entry: 1791414639
- Sigstore integration time:
-
Permalink:
cartertemm/soundobj@f4e7e929ab7c1f0ff0ede213f58c1d222dd38a69 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/cartertemm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build.yml@f4e7e929ab7c1f0ff0ede213f58c1d222dd38a69 -
Trigger Event:
push
-
Statement type:
File details
Details for the file soundobj-0.3.0-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: soundobj-0.3.0-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 3.9 MB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b4ea8d380b3bfc99dbbd883bb792a6b96471f12ae1f0eec2be35c9f6c6538ee
|
|
| MD5 |
1c03f8eb77e5a1c64f5107ea6b332bef
|
|
| BLAKE2b-256 |
06304c308db3555ba1baaa789872e5cb3104e0f3355072f5a1203685759596e8
|
Provenance
The following attestation bundles were made for soundobj-0.3.0-cp313-cp313-macosx_11_0_arm64.whl:
Publisher:
build.yml on cartertemm/soundobj
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soundobj-0.3.0-cp313-cp313-macosx_11_0_arm64.whl -
Subject digest:
6b4ea8d380b3bfc99dbbd883bb792a6b96471f12ae1f0eec2be35c9f6c6538ee - Sigstore transparency entry: 1791415644
- Sigstore integration time:
-
Permalink:
cartertemm/soundobj@f4e7e929ab7c1f0ff0ede213f58c1d222dd38a69 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/cartertemm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build.yml@f4e7e929ab7c1f0ff0ede213f58c1d222dd38a69 -
Trigger Event:
push
-
Statement type: