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 |
|---|
Matching against an idealised harmonic series does not work on a real piano: the
strings are stiff, so partials sit progressively sharp of n·f0 by an amount that
differs per note. Calibration measures each note's actual partial positions, fits its
inharmonicity coefficient B, and records the amplitude profile this instrument produces
through this microphone. No shipped product does this, which makes it both the differentiator and
the risk.
no calibration loaded
Five seconds of silence. A fan or an air conditioner is narrowband and stationary, so a single broadband threshold either deafens us in that band or fires constantly; the floor is measured per frequency bin instead.
Play the note shown, firmly and alone. It is captured only once the fit is good and the pitch is within 100 cents of the target — a wrong or fumbled note is refused rather than stored, because a bad template poisons every judgement made against it afterwards.
| note | f0 measured | cents off | B | partials | residual (cents) | SNR dB |
|---|
The five exercises, judged score-informed: each note is verified against the stored templates of the expected notes plus their semitone neighbours — a bounded hypothesis test, never an open 88-key search. Each exercise records its own take, so the audio, the events and the verdicts share one basename. These numbers are what decide the microphone question.
A missed or wrong note stops the scoring rather than advancing by one and carrying on. After a loss of alignment every later note would attach to the wrong position and the resulting hit rate would be fiction; recovering automatically is score following, which this chunk does not have. Get back to the note shown and tap Resync here.
idle
| exercise | texture | steps | hits | misses | wrong | unscorable | hit rate | median latency |
|---|
(no session yet)