Bare mic-capture + spectral scope for the piano-practice engine. Undecorated by rule — this page is instrumentation, not a product surface.
Safari needs a user gesture before it will open the mic or start an AudioContext. Nothing happens until you tap.
WebKit suspends audio the moment this page is hidden or the iPad locks. Capture does not silently restart itself: it goes to paused and waits for you to tap Resume, and any take running at that moment is closed and stamped interrupted. A recording that quietly lost its middle would be worse than no recording.
idle
WebKit suspends Web Audio when the page is hidden or the device locks (bug 237878). There is no workaround — this log is how we see it happen.
(no events yet)
Raw spectral peaks, not a transcriber. A piano note produces many partials, so harmonics show up here as their own "notes" (the 2nd partial of C3 reads as C4). Phase 1's score-informed verification is what turns this into note detection; this page exists to show what the microphone and room actually hand us.
| # | Hz | note | cents | rel dB |
|---|---|---|---|---|
| 1 | — | — | — | — |
| 2 | — | — | — | — |
| 3 | — | — | — | — |
Events are partitioned by take and carry two coordinates, because they
stop agreeing the moment anything is dropped. delivered sample is an offset into that
take's WAV file, end-exclusive: the hop occupies
[delivered − 1024, delivered) and index delivered itself belongs to the
next hop. That is the coordinate to use when locating an event in the audio. source seq is
the worklet's hop counter, which keeps advancing through dropped hops and is therefore
not a WAV index. Neither is a clock: AudioContext.currentTime restarts at
zero with every context, so it is recorded for reference only.
| take | delivered sample | source seq | t (ctx s) | kind | note | cents | Hz | level dB | peaks 2/3 |
|---|
Two independent paths. The WAV is written from the exact samples the ear sees (16-bit PCM, no codec in between) — that is the fixture format. MediaRecorder is whatever the browser will encode; the readout says which container it picked.
Hard cap 5 minutes per take, to stay clear of Safari's per-tab memory ceiling. Audio and its JSON share one basename, so a take is never separated from its events.
On stopping, the worklet is asked for a final snapshot and we wait for the reply before judging the take — counters carried on the audio itself cannot describe hops dropped after the last one that arrived, which is exactly when the end of a take goes missing. A take is valid only when it contains audio, clears a 0.25 s floor, and its arithmetic closes: source span − dropped = delivered. It is contiguous only if it is valid and nothing was dropped at all. audio verified means the browser confirmed echo cancellation, auto gain and noise suppression are genuinely off — requesting them off is not the same as getting it. Anything short of clean is written into the filename, so a bad take cannot be mistaken for a good one on disk.
| take | texture | dur (s) | samples | valid | contiguous | audio verified | interrupted | events |
|---|