Browser-based audio editor & jam-session recorder for Streamlit — full effects rack, mic input, real-time recording
Project description
streamlit-audio-editor
A browser-based audio editor & jam-session recorder for Streamlit
streamlit-audio-editor is a fully interactive audio editor that runs inside any Streamlit application. Load any audio file, trim with precision handles, apply a full rack of real-time effects, route your microphone through the effects chain, and record jam sessions — all entirely client-side via the Web Audio API with zero server-side dependencies (no ffmpeg, no pydub).
Features
Waveform Display
- PCM waveform rendering — decoded via Web Audio API
decodeAudioDataand drawn on an HTML5 canvas - Click-to-seek — click anywhere on the waveform to jump to that position
- Animated playhead — a live cursor tracks the current playback position
- Zoom — scroll wheel or ± buttons to zoom in on waveform detail; horizontal scrollbar for navigation
- Loop mode — toggle looping with correct
loopStart/loopEndon the AudioBufferSourceNode
Trim & Export
- Draggable IN / OUT trim handles — set precise start and end points directly on the waveform
- PCM slicing — exports only the selected region as raw PCM
- 16-bit WAV encoding — encodes the trim in the browser, no server round-trip
- Inline preview — listen to the trimmed result before exporting
- Download button — one-click WAV download of the trimmed audio
Effects Rack
All effects are real-time — no playback restart required:
| Effect | Controls |
|---|---|
| 3-Band EQ | Low shelf · Mid peak · High shelf |
| Filter | Lowpass / Highpass / Bandpass / Notch with frequency + resonance |
| Compressor | Threshold, ratio, attack, release |
| Delay | Delay time with feedback loop |
| Chorus | LFO-modulated delay — rate, depth, mix |
| Distortion | Waveshaper overdrive curve |
| Tremolo | LFO amplitude modulation — rate, depth |
| Reverb | Convolution with synthetic impulse response |
| Stereo Pan | Left / right panning |
| Speed / Pitch | Tape-style playback rate adjustment |
| Gain | Master output level (0.0 – 2.0) |
Microphone Input
- Route live mic through the entire effects chain in real time
- Uses
getUserMedia— works in any modern browser with microphone permission
Jam Session Recording
- MediaRecorder capture — records the effected output (file playback + mic) as WebM/Opus
- Preview & download — listen to the recording inline, then download or send to Python
- Duration tracking — recording length in seconds returned with the result
Format Support
- Supports MP3, WAV, OGG, M4A, FLAC — anything the browser can decode
- Load from URL or base64 data URI
Dark Theme
- Consistent dark UI designed to match Streamlit's dark mode
- Glass-morphism panels with subtle borders and hover effects
Installation
pip install streamlit-audio-editor
Quick Start
import base64
import streamlit as st
from streamlit_audio_editor import st_audio_editor
st.title("Audio Editor")
result = st_audio_editor(key="editor")
if result and result.get("type") == "export":
st.success(
f"Trimmed {result['trimStart']:.2f}s → {result['trimEnd']:.2f}s "
f"({result['trimEnd'] - result['trimStart']:.2f}s)"
)
wav_bytes = base64.b64decode(result["wavBase64"])
st.audio(wav_bytes, format="audio/wav")
st.download_button("Download trimmed WAV", wav_bytes, "trimmed.wav", "audio/wav")
if result and result.get("type") == "recording":
audio_bytes = base64.b64decode(result["recordingBase64"])
st.audio(audio_bytes, format=result["mimeType"])
st.download_button("Download recording", audio_bytes, "jam.webm", result["mimeType"])
API Reference
st_audio_editor
st_audio_editor(
audio_url: str | None = None,
key: str | None = None,
) -> dict | None
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
audio_url |
str or None |
None |
URL or data-URI of an audio file to pre-load. Supports any browser-decodable format. |
key |
str or None |
None |
An optional key that uniquely identifies this component. Required when placing multiple editors on one page. |
Return Value
Returns a dict when the user exports a trim or sends a recording, or None before any interaction.
Export trim (type="export"):
{
"type": "export",
"trimStart": float, # trim in-point (seconds)
"trimEnd": float, # trim out-point (seconds)
"duration": float, # total file duration (seconds)
"gain": float, # gain multiplier (0.0 – 2.0)
"wavBase64": str, # base64-encoded 16-bit PCM WAV of the trimmed region
# … plus all current effect parameters:
# eqLow, eqMid, eqHigh, filterFreq, filterQ, filterType,
# compThreshold, compRatio, compAttack, compRelease,
# delayTime, delayFeedback, chorusRate, chorusDepth, chorusMix,
# distortion, tremoloRate, tremoloDepth, reverbMix, pan, speed
}
Jam session recording (type="recording"):
{
"type": "recording",
"mimeType": str, # e.g. "audio/webm;codecs=opus"
"recordingBase64": str, # base64-encoded audio blob
"durationSec": float, # recording length in seconds
}
Usage Examples
Pre-loading Audio from a URL
result = st_audio_editor(
audio_url="https://example.com/sample.mp3",
key="editor",
)
Pre-loading a Local File via Data URI
import base64
with open("sample.wav", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
result = st_audio_editor(
audio_url=f"data:audio/wav;base64,{b64}",
key="editor",
)
Processing Exported Audio
import base64
import streamlit as st
from streamlit_audio_editor import st_audio_editor
result = st_audio_editor(key="editor")
if result and result["type"] == "export":
wav_bytes = base64.b64decode(result["wavBase64"])
col1, col2, col3 = st.columns(3)
col1.metric("Trim Start", f"{result['trimStart']:.2f}s")
col2.metric("Trim End", f"{result['trimEnd']:.2f}s")
col3.metric("Duration", f"{result['trimEnd'] - result['trimStart']:.2f}s")
st.audio(wav_bytes, format="audio/wav")
st.download_button("Download WAV", wav_bytes, "trimmed.wav", "audio/wav")
# Show active effects
if result.get("gain", 1.0) != 1.0:
st.info(f"Gain: {result['gain']:.2f}x")
if result.get("reverbMix", 0) > 0:
st.info(f"Reverb mix: {result['reverbMix']:.0%}")
Handling Jam Session Recordings
import base64
import streamlit as st
from streamlit_audio_editor import st_audio_editor
result = st_audio_editor(key="editor")
if result and result["type"] == "recording":
audio_bytes = base64.b64decode(result["recordingBase64"])
st.success(f"Recorded {result['durationSec']:.1f}s of audio")
st.audio(audio_bytes, format=result["mimeType"])
st.download_button(
"Download Recording",
audio_bytes,
"jam-session.webm",
result["mimeType"],
)
Architecture
The component is built with React 18 communicating with Streamlit via the bidirectional component API (streamlit-component-lib). All audio processing runs entirely in the browser via the Web Audio API.
┌──────────────────────────────────────────────────────────┐
│ Python (Streamlit) │
│ st_audio_editor(audio_url, key) │
│ ↓ args ↑ componentValue │
├──────────────────────────────────────────────────────────┤
│ React Frontend (iframe) │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Toolbar: Load · Play/Pause · Loop · Zoom · Export │ │
│ ├────────────────────────────────────────────────────┤ │
│ │ Waveform Canvas │ │
│ │ ┌─ IN ──────── ▶ playhead ──────── OUT ─┐ │ │
│ │ │ ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲ │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ ├────────────────────────────────────────────────────┤ │
│ │ Effects Rack │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │ EQ │ │Filter│ │Comp │ │Delay │ │Chorus│ ... │ │
│ │ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │ │
│ ├────────────────────────────────────────────────────┤ │
│ │ Jam Session: Mic Input → Effects → MediaRecorder │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ Web Audio API Graph: │
│ Source → EQ → Filter → Comp → Delay → Chorus → │
│ Distortion → Tremolo → Reverb → Pan → Gain → Dest │
└──────────────────────────────────────────────────────────┘
- Audio decoding —
AudioContext.decodeAudioData()decodes any browser-supported format to PCM - Effects chain — each effect is a Web Audio node wired in series; parameters update in real time
- Mic routing —
getUserMediastream is connected to the same effects chain - Recording —
MediaRecordercaptures the final output node as WebM/Opus - Export — raw PCM is sliced and encoded to 16-bit WAV entirely in JavaScript
Browser Compatibility
| Browser | Status |
|---|---|
| Chrome / Edge 90+ | ✅ Full support |
| Firefox 90+ | ✅ Full support |
| Safari 15+ | ✅ Full support (mic requires HTTPS) |
| Mobile browsers | ⚠️ Mic input may require user gesture |
Requirements
- Python 3.8+
- Streamlit ≥ 1.28.0
License
MIT — see LICENSE for details.
Links
Project details
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 streamlit_audio_editor-0.4.1.tar.gz.
File metadata
- Download URL: streamlit_audio_editor-0.4.1.tar.gz
- Upload date:
- Size: 434.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f60cde0afe97c53f19a476d41f566db2a9c428f5c7bf4a2318579955376d932
|
|
| MD5 |
7c9e00c488e8985c967d132635490740
|
|
| BLAKE2b-256 |
5f4e07639da819592d9e847bd379d4e0e4ff969c090061791718d6dc9b67fc57
|
File details
Details for the file streamlit_audio_editor-0.4.1-py3-none-any.whl.
File metadata
- Download URL: streamlit_audio_editor-0.4.1-py3-none-any.whl
- Upload date:
- Size: 435.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13ba343bb2244c7d8e24b5fb3cc761d3972ac36aba0ffff70d23fa1cd52877b3
|
|
| MD5 |
918c5e6fe8c8ffd29da9bb3c373606b5
|
|
| BLAKE2b-256 |
1cdb678a1c803367237df7fe261afc7527c4848ca74481616573662a1ac61e25
|