SonicLab
SonicLab is a modular Python DSP / audio synthesis engine: vectorized oscillators, envelopes, filters, effects, sequencing, optional realtime audio I/O, and MIDI adapters.
Status: Beta. Public APIs may still evolve; see docs/stability.md and CHANGELOG.md.
Features
- Oscillators: sine, square, sawtooth, triangle, PolyBLEP bandlimited variants
- Modulation: ADSR / decay envelopes, modulated oscillators & frequency helpers
- Modifiers: volume, panning, clipping, frequency processors
- Composition:
Chain(serial),WaveAdder(parallel mix) - Noise: white, pink, brownian, blue, grey, velvet, sample-and-hold, Perlin
- Filters: Butterworth utilities, biquad resonant, acid/303-style filter
- Effects: distortion, delay, reverb, compressor
- Sequencing: step sequencers, arpeggiator, clock, accent/slide, TB-303 helpers
- Presets:
PresetBuilder/PresetLibrary - I/O (optional):
AudioOutputvia theaudio-ioextra - MIDI (optional): input/files, mono & poly synths (velocity, sustain, bend),
mono note-stack CV and multi-voice
PolyphonicMIDIToCVvia themidiextra
Install
From PyPI:
pip install soniclab
Optional extras:
pip install "soniclab[audio-io]" # sounddevice + numba speed path
pip install "soniclab[midi]" # mido + python-rtmidi
pip install "soniclab[speed]" # numba only
pip install "soniclab[examples]" # notebooks / plotting
pip install "soniclab[full]" # audio-io + midi + examples
From a checkout (recommended while developing):
uv sync
# or:
python -m pip install -e ".[dev]"
Notes:
- Base install is the core NumPy/SciPy engine only.
- Realtime device playback needs working system audio drivers plus
audio-io. - MIDI needs local MIDI ports/backends plus the
midiextra.
Minimal example
from soniclab import SineOscillator, __version__
print(__version__)
osc = SineOscillator(frequency=440, amplitude=0.3)
samples = osc.get_samples(44100) # 1 second @ 44.1 kHz, float32
print(samples.shape, samples.dtype)
Chain + stereo pan:
from soniclab import SineOscillator, Chain, Volume, Panner
chain = Chain(
SineOscillator(frequency=440, amplitude=0.4),
Volume(0.8),
Panner(0.25),
)
stereo = chain.get_samples(2048, mode="vectorized") # shape (2048, 2)
PolyBLEP oscillator:
from soniclab import PolyBLEPOscillator, WaveShape
osc = PolyBLEPOscillator(
frequency=110,
amplitude=0.5,
wave_shape=WaveShape.SAWTOOTH_UP,
)
samples = osc.get_samples(1024, mode="vectorized")
Optional audio output:
from soniclab.audio_io import AudioOutput
# See examples/ and soniclab/audio_io for callback-based playback.
Sample generation modes
Most generators support:
| Mode | Behavior |
|---|---|
"vectorized" |
NumPy block rendering (preferred for production) |
"iterator" |
Python sample loop (flexible, slower) |
"auto" |
oscillators: vectorized when n >= 512, else iterator; composers (Chain / WaveAdder) always use vectorized so small realtime buffers stay on the fast path |
For realtime or offline renderers, prefer "vectorized" (or "auto" with buffer sizes ≥ 512).
Documentation
- docs/ — getting started, API overview, recipes, stability policy
- Local preview:
uv run --with mkdocs mkdocs serve - CHANGELOG.md
- CONTRIBUTING.md
- SECURITY.md
Testing
uv run pytest tests -q
uv run ruff check soniclab tests
uv run mypy soniclab
Project layout
soniclab/ # installable package
tests/ # pytest suite (mirrors soniclab/ packages)
examples/ # demos & notebooks (not in sdist)
docs/ # user documentation (MkDocs)
scripts/ # benchmarks & local tooling
Public API
Import the stable surface from the top-level package:
from soniclab import (
SineOscillator,
SquareOscillator,
TriangleOscillator,
SawtoothOscillator,
PolyBLEPOscillator,
ADSREnvelope,
Chain,
WaveAdder,
Volume,
Panner,
Delay,
Reverb,
)
Optional subsystems stay in subpackages so the core install stays light:
from soniclab.audio_io import AudioOutput
from soniclab.midi_io import MIDIInput # requires midi extra
Polyphonic MIDI synth (velocity-sensitive voices):
from soniclab import ADSREnvelope, Chain, ModulatedVolume, SineOscillator
from soniclab.midi_io import PolyphonicSynth # requires midi extra
def voice_factory():
osc = SineOscillator(440, amplitude=0.25)
env = ADSREnvelope(attack_duration=0.01, release_duration=0.2)
return Chain(osc, ModulatedVolume(env))
synth = PolyphonicSynth(voice_factory, max_voices=8)
synth.note_on(60, 100)
synth.note_on(64, 80)
samples = synth.get_samples(2048)
See examples/midi/polyphony_usage.py and docs/recipes.md.
Contributing
- Prefer
uvfor environments (uv sync --group dev). - Keep changes covered by tests under
tests/. - Run
pytest,ruff, andmypybefore opening a PR. - Follow existing module patterns (component descriptor + registry registration).
- See CONTRIBUTING.md for details.
Publishing a release
Version is read from soniclab/_version.py (CalVer-style YYYY.MINOR.MICRO).
Publishing uses GitHub Actions (Trusted Publisher) on a GitHub Release.
-
Prep
- Bump
major/minor/microinsoniclab/_version.py. - Move the matching section in
CHANGELOG.mdfrom Unreleased to a dated heading (e.g.## [2026.1.3] - 2026-07-31). - Commit on
mainand push so CI is green (pytest,ruff,mypy, build).
- Bump
-
Local sanity (optional but recommended)
uv run pytest tests -q uv run ruff check soniclab tests uv run mypy soniclab uv build uv run --with twine twine check dist/*
-
Tag & release (creates the PyPI publish)
git tag 2026.1.3 git push origin main --tags # Then publish a GitHub Release for that tag (UI or gh): # gh release create 2026.1.3 --title "2026.1.3" --notes-file CHANGELOG.md
The
Publish to PyPIworkflow builds the sdist/wheel and uploads to PyPI when the release is published. For a dry run, use Actions → Publish to PyPI → Run workflow with targettestpypi. -
Verify — pypi.org/project/soniclab shows the new version;
pip install -U soniclabinstalls it.
Do not upload the same version twice to PyPI (versions are immutable).
Changelog
See CHANGELOG.md.
License
See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 soniclab-2026.1.3.tar.gz.
File metadata
- Download URL: soniclab-2026.1.3.tar.gz
- Upload date:
- Size: 283.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48f439daf286fb59a82fe2778e1986fa1d9db6b8df5dad614171e0ed9a22aa94
|
|
| MD5 |
73697ba8cd0f2a1253593cb274103b0e
|
|
| BLAKE2b-256 |
1a85840cd135a252e1fb61c4bb8c444e3dd945c9417043880bc291aa3512ac47
|
Provenance
The following attestation bundles were made for soniclab-2026.1.3.tar.gz:
Publisher:
publish.yml on rasigle/soniclab
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soniclab-2026.1.3.tar.gz -
Subject digest:
48f439daf286fb59a82fe2778e1986fa1d9db6b8df5dad614171e0ed9a22aa94 - Sigstore transparency entry: 2299099723
- Sigstore integration time:
-
Permalink:
rasigle/soniclab@7e0b1a9b853de8b1f1da23f1ba0ff2005544ab2b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/rasigle
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e0b1a9b853de8b1f1da23f1ba0ff2005544ab2b -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file soniclab-2026.1.3-py3-none-any.whl.
File metadata
- Download URL: soniclab-2026.1.3-py3-none-any.whl
- Upload date:
- Size: 234.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca98de1454fc019cd21c2dfd0a95de56224eba15ce5f09ec93b60bc402b4e3eb
|
|
| MD5 |
240219b2fb8b06cf9e5d78860cf64a76
|
|
| BLAKE2b-256 |
dd23141b9ec798f63fca206d7df1452112c80a3620129f2b968b16c8f90c158b
|
Provenance
The following attestation bundles were made for soniclab-2026.1.3-py3-none-any.whl:
Publisher:
publish.yml on rasigle/soniclab
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soniclab-2026.1.3-py3-none-any.whl -
Subject digest:
ca98de1454fc019cd21c2dfd0a95de56224eba15ce5f09ec93b60bc402b4e3eb - Sigstore transparency entry: 2299099748
- Sigstore integration time:
-
Permalink:
rasigle/soniclab@7e0b1a9b853de8b1f1da23f1ba0ff2005544ab2b -
Branch / Tag:
refs/heads/main - Owner: https://github.com/rasigle
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e0b1a9b853de8b1f1da23f1ba0ff2005544ab2b -
Trigger Event:
workflow_dispatch
-
Statement type: