Native Shell
Native Shell:AI 生成的 UI,在你的应用中原生呈现,覆盖每个平台。iOS、Android、macOS、Windows 与 Linux 上的应用、GPUI 应用与网页在运行时加载已签名、沙箱隔离的 TSX 模块并绘制 th
AI 翻译
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Audio I/O for in-browser Python
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗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.
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).
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
| 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, . raises; use . |
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.
| 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=. |
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/.
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}
}
CallbackFlagsrecrecord