audio
Web Audio components for playing, analyzing, and recording sound.
Provides five components built on the browser's Web Audio API:
- :class:
Tone: play a single pitch (a note name like"C4"or a frequency in Hz) with a chosen waveform. - :class:
Melody: play a sequence of notes at a tempo; a melody is just a Python list, so students can compose music with list operations. - :class:
Sound: play an audio file through an optional chain of effects (echo, reverb, muffle, sharpen, distortion) with volume/pan/speed control. - :class:
Microphone: monitor live microphone input, firing events when the room gets loud or quiet and providing an :class:AudioLevelsnapshot on form submission. - :class:
AudioRecorder: record microphone audio and submit it as a :class:Recordingthat can be played back with :class:Sound.
The Python side only describes the components: each renders as a custom
element (<drafter-tone>, <drafter-melody>, <drafter-sound>,
<drafter-microphone>, <drafter-audio-recorder>) whose behavior is
implemented in js/src/components/. A single shared AudioContext lives in
js/src/components/audioBroker.ts; because browsers require a user gesture
before sound can play, components rendered before any interaction show a
small "Enable sound" prompt (the audio analog of the geolocation permission
prompt).
Like :class:~drafter.components.geolocation.CurrentLocation, the
:class:Microphone and :class:AudioRecorder components keep a hidden form
field (named after the component) updated with JSON-encoded data;
converters registered below turn those payloads into :class:AudioLevel
and :class:Recording values when a matching route parameter is annotated
with them. Failures become status values rather than exceptions, so
routes can inspect problems without try/except.
MicrophoneStatus = Literal['unavailable', 'prompt', 'pending', 'granted', 'denied', 'error']
module-attribute
The permission/availability states an AudioLevel's status field can
report, mirroring the microphone permission workflow.
NoteValue = str | tuple[str, int | float]
module-attribute
One item in a Melody's note list: a note name like "C4" (or
"rest"), played for one beat, or a (note, beats) pair like
("C4", 2).
REST = 'rest'
module-attribute
A note that plays silence for its beats in a Melody.
RecordingStatus = Literal['unavailable', 'prompt', 'recording', 'granted', 'denied', 'error']
module-attribute
The permission/recording states a Recording's status field can
report.
VISUALIZATIONS = ('meter', 'waveform', 'bars')
module-attribute
The live visualization styles a Microphone can draw; Sound supports
the "waveform" and "bars" subset.
WAVEFORMS = ('sine', 'square', 'triangle', 'sawtooth')
module-attribute
The oscillator waveform names accepted by Tone and Melody.
AudioEffect()
dataclass
Base class for audio effects that can be chained onto sound.
Effects are plain values, not components: pass a list of them as the
effects parameter of :class:Sound, :class:Tone, or
:class:Melody, and they are applied in order.
to_config()
Serialize this effect to the JSON configuration the JS side reads.
AudioLevel(status, message=None, volume=None, peak_volume=None, pitch=None)
dataclass
A snapshot of microphone input from a :class:Microphone component.
Attributes:
| Name | Type | Description |
|---|---|---|
status |
MicrophoneStatus
|
Current permission/availability state. |
message |
str | None
|
Optional descriptive message about the status. |
volume |
float | None
|
Loudness from 0.0 (silence) to 1.0 (as loud as the microphone can measure) at the moment the form was submitted, based on the peak signal level (None if unavailable). |
peak_volume |
float | None
|
The loudest volume heard since the page loaded (None if unavailable). |
pitch |
float | None
|
The dominant frequency in Hz of the sound being heard (None if unavailable or too quiet to estimate). |
AudioRecorder(name, max_duration=30000, show=True, on_record=None, on_denied=None, on_error=None, **extra_settings)
dataclass
Bases: Component
Records microphone audio and submits it with the form.
Shows a record button; after asking for microphone permission (shared
with :class:Microphone), it records until stopped or until
max_duration milliseconds pass. The completed recording is kept in
a hidden form field (named name) as a data URL, so a route
parameter with the same name annotated as :class:Recording receives
the converted value. Play a recording back by passing its data_url
to :class:Sound.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The form field name that will contain the Recording data. |
max_duration |
int
|
Maximum recording length in milliseconds. Defaults to 30000 (30 seconds). |
show |
bool
|
Whether to display the recorder UI. Defaults to True. |
on_record |
UrlOrFunction | None
|
Function or URL to call when a recording completes. |
on_denied |
UrlOrFunction | None
|
Function or URL to call when microphone permission is denied. |
on_error |
UrlOrFunction | None
|
Function or URL to call when recording fails. |
Initialize the AudioRecorder component.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The form field name for the Recording data. |
required |
max_duration
|
int
|
Maximum recording length in milliseconds. |
30000
|
show
|
bool
|
Whether to display the recorder UI. |
True
|
on_record
|
UrlOrFunction | None
|
Function or URL to call when a recording completes. |
None
|
on_denied
|
UrlOrFunction | None
|
Function or URL to call when permission is denied. |
None
|
on_error
|
UrlOrFunction | None
|
Function or URL to call when recording fails. |
None
|
**extra_settings
|
Additional HTML attributes. |
{}
|
Distortion(amount=0.3)
dataclass
Bases: AudioEffect
Overdrives the sound for a gritty, fuzzy character.
Attributes:
| Name | Type | Description |
|---|---|---|
amount |
float
|
How distorted the sound is, from 0.0 (clean) to 1.0 (heavily distorted). Defaults to 0.3. |
Echo(delay=0.3, strength=0.4)
dataclass
Bases: AudioEffect
Repeats the sound after a delay, quieter each time.
Attributes:
| Name | Type | Description |
|---|---|---|
delay |
float
|
Seconds between repeats. Defaults to 0.3. |
strength |
float
|
How loud each repeat is relative to the one before, from 0.0 (no echo) to 1.0 (repeats forever). Defaults to 0.4. |
Melody(notes, tempo=120, waveform='sine', volume=0.8, auto_play=False, controls=False, show=True, effects=None, on_note=None, on_finish=None, **extra_settings)
dataclass
Bases: Component
Plays a sequence of notes at a tempo using the Web Audio API.
A melody is just a list: each item is a note name like "C4" (played
for one beat), a (note, beats) pair like ("C4", 2), or
"rest" for silence. Notes are scheduled with sample-accurate Web
Audio timing, so melodies stay in rhythm.
Note
An on_note handler that returns a full :class:~drafter.Page
re-renders the whole page, which stops and resets this melody after
its very first note. To react to notes while the melody keeps
playing, return an Update (change state only) or a Fragment
targeting another element; save full pages for on_finish.
Attributes:
| Name | Type | Description |
|---|---|---|
notes |
list[NoteValue]
|
The notes to play, in order. |
tempo |
int | float
|
Speed in beats per minute. Defaults to 120. |
waveform |
str
|
The shape of the sound wave: "sine", "square", "triangle", or "sawtooth". Defaults to "sine". |
volume |
float
|
Loudness from 0.0 to 1.0. Defaults to 0.8. |
auto_play |
bool
|
Whether to play as soon as the page loads instead of showing a play button. Defaults to False. |
controls |
bool
|
Whether to show play/pause and restart buttons. Defaults to False. |
show |
bool
|
Whether to display the component. Defaults to True. A hidden auto-play component still shows its "Enable sound" prompt while the browser is blocking sound. |
effects |
list[AudioEffect] | None
|
Optional list of effects (like :class: |
on_note |
UrlOrFunction | None
|
Function or URL to call as each note starts. |
on_finish |
UrlOrFunction | None
|
Function or URL to call when the melody finishes. |
Initialize the Melody component.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
notes
|
list[NoteValue]
|
List of note names like 'C4', (note, beats) pairs, or 'rest'. |
required |
tempo
|
int | float
|
Speed in beats per minute. |
120
|
waveform
|
str
|
"sine", "square", "triangle", or "sawtooth". |
'sine'
|
volume
|
float
|
Loudness from 0.0 to 1.0. |
0.8
|
auto_play
|
bool
|
Whether to play on page load instead of showing a button. |
False
|
controls
|
bool
|
Whether to show play/pause and restart buttons. |
False
|
show
|
bool
|
Whether to display the component. |
True
|
effects
|
list[AudioEffect] | None
|
Optional list of effects applied in order. |
None
|
on_note
|
UrlOrFunction | None
|
Function or URL to call as each note starts. |
None
|
on_finish
|
UrlOrFunction | None
|
Function or URL to call when the melody finishes. |
None
|
**extra_settings
|
Additional HTML attributes. |
{}
|
get_attributes(context)
Extend the base attributes with normalized, JSON-encoded data.
The note list is normalized to [note, beats] pairs and the
effects list is serialized, since the <drafter-melody> custom
element parses both from JSON strings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
The render context passed through to the base class. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
The attribute dictionary with |
Microphone(name, threshold=0.5, cooldown=1000, rate=0, show=True, visualize='meter', on_loud=None, on_quiet=None, on_level=None, on_denied=None, on_error=None, **extra_settings)
dataclass
Bases: Component
Monitors live microphone input and reports how loud the room is.
This component follows the same permission workflow as
:class:~drafter.components.geolocation.CurrentLocation: it shows an
"Enable microphone" prompt, and once permission is granted it displays a
live level meter. It keeps a hidden form field (named name) updated
with the latest :class:AudioLevel snapshot, so a route parameter with
the same name annotated as :class:AudioLevel receives the converted
value on any form submission.
The on_loud event is the easiest way to react to sound: it fires
when the volume crosses threshold (a clap, a shout), and then not
again until cooldown milliseconds have passed. Volume is measured
as the peak signal level, so brief sounds like claps register at their
full loudness.
Note
An on_loud/on_quiet/on_level handler that returns a
full :class:~drafter.Page re-renders the whole page, briefly
resetting this component (it re-enables itself, but the meter and
peak_volume restart). For frequent events, prefer returning an
Update (change state only) or a Fragment targeting another
element.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The form field name that will contain the AudioLevel data. |
threshold |
float
|
The loudness (0.0 to 1.0) that counts as "loud". Defaults to 0.5. |
cooldown |
int
|
Minimum milliseconds between on_loud events. Defaults to 1000. |
rate |
int
|
Milliseconds between on_level events, or 0 to never fire them. Defaults to 0. |
show |
bool
|
Whether to display the permission UI and meter. Defaults to True. |
visualize |
str
|
The live display once granted: "meter", "waveform", or "bars". Defaults to "meter". |
on_loud |
UrlOrFunction | None
|
Function or URL to call when the volume rises past threshold. |
on_quiet |
UrlOrFunction | None
|
Function or URL to call when the volume falls back below threshold. |
on_level |
UrlOrFunction | None
|
Function or URL to call every |
on_denied |
UrlOrFunction | None
|
Function or URL to call when microphone permission is denied. |
on_error |
UrlOrFunction | None
|
Function or URL to call when the microphone fails. |
Initialize the Microphone component.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The form field name for the AudioLevel data. |
required |
threshold
|
float
|
The loudness (0.0 to 1.0) that counts as "loud". |
0.5
|
cooldown
|
int
|
Minimum milliseconds between on_loud events. |
1000
|
rate
|
int
|
Milliseconds between on_level events (0 disables them). |
0
|
show
|
bool
|
Whether to display the permission UI and meter. |
True
|
visualize
|
str
|
"meter", "waveform", or "bars". |
'meter'
|
on_loud
|
UrlOrFunction | None
|
Function or URL to call when volume rises past threshold. |
None
|
on_quiet
|
UrlOrFunction | None
|
Function or URL to call when volume falls below threshold. |
None
|
on_level
|
UrlOrFunction | None
|
Function or URL to call on each level report. |
None
|
on_denied
|
UrlOrFunction | None
|
Function or URL to call when permission is denied. |
None
|
on_error
|
UrlOrFunction | None
|
Function or URL to call when the microphone fails. |
None
|
**extra_settings
|
Additional HTML attributes. |
{}
|
Muffle(amount=0.5)
dataclass
Bases: AudioEffect
Removes high frequencies, like hearing sound through a wall.
Attributes:
| Name | Type | Description |
|---|---|---|
amount |
float
|
How muffled the sound is, from 0.0 (unchanged) to 1.0 (very muffled). Defaults to 0.5. |
Recording(status, message=None, data_url=None, duration=None, size=None)
dataclass
A completed audio recording from an :class:AudioRecorder component.
The data_url can be handed directly to :class:Sound (or
:class:~drafter.components.media.Audio) to play the recording back.
Attributes:
| Name | Type | Description |
|---|---|---|
status |
RecordingStatus
|
Current permission/recording state. |
message |
str | None
|
Optional descriptive message about the status. |
data_url |
str | None
|
The recorded audio as a data URL (None if nothing has been recorded). |
duration |
float | None
|
Length of the recording in seconds (None if unavailable). |
size |
int | None
|
Size of the recorded audio in bytes (None if unavailable). |
Reverb(amount=0.5)
dataclass
Bases: AudioEffect
Makes the sound ring out as if played in a large room.
Attributes:
| Name | Type | Description |
|---|---|---|
amount |
float
|
How much reverberation to add, from 0.0 (none) to 1.0 (cavernous). Defaults to 0.5. |
Sharpen(amount=0.5)
dataclass
Bases: AudioEffect
Removes low frequencies, like a tinny phone speaker.
Attributes:
| Name | Type | Description |
|---|---|---|
amount |
float
|
How thinned-out the sound is, from 0.0 (unchanged) to 1.0 (very tinny). Defaults to 0.5. |
Sound(src, volume=1.0, pan=0.0, speed=1.0, loop=False, effects=None, auto_play=False, controls=True, visualize=None, on_play=None, on_finish=None, on_error=None, **extra_settings)
dataclass
Bases: Component
Plays an audio file through the Web Audio API with optional effects.
Unlike the plain :class:~drafter.components.media.Audio component,
Sound routes the audio through a processing chain, so it can change
volume, stereo position, and playback speed, and apply effects like
:class:Echo or :class:Reverb. The data_url of a
:class:Recording can be played back this way, too.
Attributes:
| Name | Type | Description |
|---|---|---|
src |
str
|
URL (or data URL) of the audio to play. |
volume |
float
|
Loudness from 0.0 to 1.0. Defaults to 1.0. |
pan |
float
|
Stereo position from -1.0 (left) to 1.0 (right). Defaults to 0.0. |
speed |
float
|
Playback speed multiplier; below 1.0 is slower and deeper, above 1.0 is faster and higher. Defaults to 1.0. |
loop |
bool
|
Whether to repeat forever. Defaults to False. |
effects |
list[AudioEffect] | None
|
Optional list of effects (like :class: |
auto_play |
bool
|
Whether to start playing as soon as the page loads. Defaults to False. |
controls |
bool
|
Whether to show playback controls. Defaults to True. |
visualize |
str | None
|
Optional live visualization drawn while playing: "waveform" or "bars". Defaults to None. |
on_play |
UrlOrFunction | None
|
Function or URL to call when playback starts. |
on_finish |
UrlOrFunction | None
|
Function or URL to call when playback finishes. |
on_error |
UrlOrFunction | None
|
Function or URL to call if the audio cannot be played. |
Initialize the Sound component.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
src
|
str
|
URL (or data URL) of the audio to play. |
required |
volume
|
float
|
Loudness from 0.0 to 1.0. |
1.0
|
pan
|
float
|
Stereo position from -1.0 (left) to 1.0 (right). |
0.0
|
speed
|
float
|
Playback speed multiplier. |
1.0
|
loop
|
bool
|
Whether to repeat forever. |
False
|
effects
|
list[AudioEffect] | None
|
Optional list of effects applied in order. |
None
|
auto_play
|
bool
|
Whether to start playing on page load. |
False
|
controls
|
bool
|
Whether to show playback controls. |
True
|
visualize
|
str | None
|
Optional visualization: "waveform" or "bars". |
None
|
on_play
|
UrlOrFunction | None
|
Function or URL to call when playback starts. |
None
|
on_finish
|
UrlOrFunction | None
|
Function or URL to call when playback finishes. |
None
|
on_error
|
UrlOrFunction | None
|
Function or URL to call if the audio cannot play. |
None
|
**extra_settings
|
Additional HTML attributes. |
{}
|
get_attributes(context)
Extend the base attributes by JSON-encoding the effects list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
The render context passed through to the base class. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
The attribute dictionary, with |
Tone(pitch, duration=500, waveform='sine', volume=0.8, attack=10, release=50, auto_play=False, show=True, effects=None, on_start=None, on_finish=None, on_error=None, **extra_settings)
dataclass
Bases: Component
Plays a single pitch using the browser's Web Audio API.
The pitch can be a note name like "C4" or "F#3", or a raw
frequency in Hz like 440. By default the component renders a small
play button; with auto_play=True it plays as soon as the page loads
(browsers require at least one interaction with the page first, so a
tone on the very first page shows an "Enable sound" prompt instead).
Attributes:
| Name | Type | Description |
|---|---|---|
pitch |
str | int | float
|
Note name ( |
duration |
int
|
How long the tone plays, in milliseconds. Defaults to 500. |
waveform |
str
|
The shape of the sound wave: "sine" (smooth), "square" (buzzy), "triangle" (mellow), or "sawtooth" (bright). |
volume |
float
|
Loudness from 0.0 to 1.0. Defaults to 0.8. |
attack |
int
|
Milliseconds to fade in (prevents clicks). Defaults to 10. |
release |
int
|
Milliseconds to fade out. Defaults to 50. |
auto_play |
bool
|
Whether to play as soon as the page loads instead of showing a play button. Defaults to False. |
show |
bool
|
Whether to display the component. Defaults to True. A hidden auto-play component still shows its "Enable sound" prompt while the browser is blocking sound. |
effects |
list[AudioEffect] | None
|
Optional list of effects (like :class: |
on_start |
UrlOrFunction | None
|
Function or URL to call when the tone starts playing. |
on_finish |
UrlOrFunction | None
|
Function or URL to call when the tone finishes playing. |
on_error |
UrlOrFunction | None
|
Function or URL to call if the tone cannot be played. |
Initialize the Tone component.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pitch
|
str | int | float
|
Note name ("C4") or frequency in Hz (440). |
required |
duration
|
int
|
How long the tone plays, in milliseconds. |
500
|
waveform
|
str
|
"sine", "square", "triangle", or "sawtooth". |
'sine'
|
volume
|
float
|
Loudness from 0.0 to 1.0. |
0.8
|
attack
|
int
|
Milliseconds to fade in. |
10
|
release
|
int
|
Milliseconds to fade out. |
50
|
auto_play
|
bool
|
Whether to play on page load instead of showing a button. |
False
|
show
|
bool
|
Whether to display the component. |
True
|
effects
|
list[AudioEffect] | None
|
Optional list of effects applied in order. |
None
|
on_start
|
UrlOrFunction | None
|
Function or URL to call when the tone starts. |
None
|
on_finish
|
UrlOrFunction | None
|
Function or URL to call when the tone finishes. |
None
|
on_error
|
UrlOrFunction | None
|
Function or URL to call if the tone cannot play. |
None
|
**extra_settings
|
Additional HTML attributes. |
{}
|
get_attributes(context)
Extend the base attributes by JSON-encoding the effects list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
The render context passed through to the base class. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
The attribute dictionary, with |
convert_audio_level(ctx)
Convert a JSON string or dict payload into an :class:AudioLevel.
convert_recording(ctx)
Convert a JSON string or dict payload into a :class:Recording.
note_to_frequency(note)
Convert a note name like "C4", "F#3", or "Bb2" to Hz.
Uses equal temperament with A4 = 440 Hz. Note names are a letter A-G,
an optional # (sharp) or b (flat), and an octave digit 0-9.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
note
|
str
|
The note name to convert. |
required |
Returns:
| Type | Description |
|---|---|
float
|
The frequency in Hz. |
Raises:
| Type | Description |
|---|---|
StudentFacingError
|
If the note name is not recognized. |