Skip to main content

browseraudio

PyPI Python License: MIT

Audio I/O for in-browser Python (Pyodide, JupyterLite, thebe): record, play, and synthesize in real time, to and from NumPy.

Browser kernels usually run in a Web Worker, which can't reach the Web Audio API. browseraudio does the audio on the page's main thread through small anywidget frontends and moves the samples over the widget comm.

Live demo →

Install

pip install browseraudio

In a browser kernel: import micropip; await micropip.install("browseraudio"). Needs a widget-capable kernel (JupyterLite, thebe, Jupyter, marimo) and, for the microphone, a secure context (https:// or localhost).

Quickstart

from browseraudio import record, play, keyboard, stream

rec = record(3.0)                 # click Record; read rec.samples in the NEXT cell
play(rec.samples, rec.sample_rate)

Recording finishes after the cell returns (a Web-Worker kernel can't receive the take mid-cell), so read rec.samples in a later cell.

Keyboard: design a sound, then play it on the computer keyboard (A W S E D …, Z/X for octaves). Notes are voiced in the page, polyphonic, with no kernel round trip:

import numpy as np
sr = 22050
t = np.arange(sr) / sr
kb = keyboard(lambda f: np.sin(2 * np.pi * f * t) * np.exp(-4 * t), sr)

Stream: real-time synthesis. The browser pulls blocks from your callback:

class Sine:
    def __init__(self):
        self.pitch, self.phase, self.on, self.amp = 60, 0.0, False, 0.0

    def callback(self, block):                     # (B, 1) with .sample_rate
        B = len(block)
        f = 440 * 2 ** ((self.pitch - 69) / 12)
        target = 0.3 if self.on else 0.0
        amp = np.linspace(self.amp, target, B, endpoint=False)  # glide: no clicks
        d = 2 * np.pi * f / block.sample_rate
        block[:, 0] = amp * np.sin(self.phase + d * np.arange(B))
        self.phase, self.amp = (self.phase + d * B) % (2 * np.pi), target

synth = Sine()
def on_note(midi, on):
    if on: synth.pitch, synth.on = midi, True
    elif midi == synth.pitch: synth.on = False

s = stream(synth.callback, sample_rate=44100, block_size=512, on_note=on_note)

The widget shows block size, queue, round trip, callback load, dropouts and key-to-sound latency. For chords, keep one voice per held key (see the demo).

Genie mode: pass input="genie" to keyboard or stream, or use the widget's Keys | Genie switch. Eight buttons (1–8 or A S D F J K L ;) become piano music via Piano Genie.

sounddevice code runs unchanged once the facade is registered:

import sys, browseraudio.sounddevice
sys.modules["sounddevice"] = browseraudio.sounddevice

API

Call What it does
record(duration=3.0) → Recorder Mic capture. .samples (float32 (n, 1)), .sample_rate, .error, on_result(cb), on_error(cb), await result() (main thread only), to_pyquist(). Stopping early keeps the take.
play(samples, sample_rate=None, *, autoplay=True) → Player Plays (n,) or (n, ch); sample_rate may come from samples.sample_rate. .play(), .stop(), .playing.
keyboard(render=None, sample_rate=None, *, wavetable=None, …) → Keyboard render(freq) -> ndarray per note, or a looped wavetable. Options: attack/decay/sustain/release, gain, one_shot, max_voices, keymap, input, genie_temperature, genie_checkpoint. .events, .render(), .on_note(cb), .clear().
stream(callback, sample_rate=44100, block_size=512, *, …) → Stream callback(block) per block. Options: channels, lookahead (seconds, default 0.04), on_note(midi, on), keymap, input, genie_range, genie_temperature, genie_checkpoint. .start(), .stop(), .playing, .error, .dropouts.
KeyMap(keys, table, start=0, labels=None) Key codes → MIDI through a state machine: table[state][i] = (midi or None, next_state). KeyMap.musical_typing(base=60).
browseraudio.sounddevice play, wait, OutputStream (callback mode), query_devices, default, CallbackStop/CallbackAbort, CallbackFlags. rec raises; use record.

How it works

Widgets render in a Shadow DOM. They follow the JupyterLab theme, or the host page's text colour and font elsewhere. Audio crosses the comm as base64 float32. For streams the browser is the clock: an AudioWorklet plays a short queue and asks the kernel for each next block. A kernel answers whenever no cell is running, even in a Web Worker, so a control change is heard after the queue plus one round trip (about 50–100 ms). Dropouts and Stop fade out rather than click.

Troubleshooting

Symptom Fix
No widget Use a widget-capable kernel (JupyterLite, thebe, Jupyter).
No mic prompt, or denied Needs https:// or localhost and a click; re-allow the mic in site settings.
rec.samples is None Read it in a later cell, after recording.
Stream crackles A cell is running, the callback is too slow (see "% of budget"), or lookahead is too short.
Stream started from code is silent Click Enable audio (browser autoplay policy).
Keys don't play Click the widget first.
Genie can't load storage.googleapis.com must be reachable; or self-host and pass genie_checkpoint=.

Development

pip install -e ".[test]" && pytest     # genie tests also need node
python -m build && python -m twine check dist/*

Python is in browseraudio/, frontends in browseraudio/static/ (ui.js is shared; genie.js and controls.js are added for keyboard widgets), and the demo site in demo/.

Credits

Genie mode is Piano Genie. It runs Magenta's published model (Apache-2.0) with inference ported from Magenta.js (Apache-2.0). Please cite:

@inproceedings{donahue2019pianogenie,
  title     = {Piano Genie},
  author    = {Donahue, Chris and Simon, Ian and Dieleman, Sander},
  booktitle = {Proceedings of the 24th International Conference on Intelligent User Interfaces},
  pages     = {160--164},
  year      = {2019},
  doi       = {10.1145/3301275.3302288}
}

License

MIT

Metadata

Release files for browseraudio 0.4.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 browseraudio 0.4.0
File Size Uploaded Provenance Actions
browseraudio-0.4.0.tar.gz 51.0 kB Without provenance Details for browseraudio-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for browseraudio 0.4.0
File Interpreter ABI Platform Actions
browseraudio-0.4.0-py3-none-any.whl Python 3 none any Details for browseraudio-0.4.0-py3-none-any.whl

Total release size: 94.6 kB

Release files / browseraudio-0.4.0.tar.gz

Download URL browseraudio-0.4.0.tar.gz
Size 51.0 kB
Tags Source
SHA-256 checksum
How to use checksums
cbd949cb6c5bb4eede0aac6903c1448fb3cdc282ecc268b69e32c46fcfae233a
BLAKE2b-256 checksum
How to use checksums
d8c57726daf8ca9decc36ac1c2ba2da574414e162c74fa03f903b3ff40c59388
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / browseraudio-0.4.0-py3-none-any.whl

Download URL browseraudio-0.4.0-py3-none-any.whl
Size 43.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0c9396f8dbade1ef75b2003658f3bf470d08e6518825512d80c2cb3d5bdca10f
BLAKE2b-256 checksum
How to use checksums
c6c34d339c434de321119accdffb863a88680dbd8a3d2698bd60c9bdeadfa5ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for browseraudio 0.4.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