Watching Themselves Play · Method appendix

Can we trust the machine's transcript?

Four of the strongest speech-recognition engines, on 26 musicians thinking aloud while they play — measured, compared, and read line by line. The answer is why this study transcribes by hand.

What this page is. A working appendix, not a finished paper — built so you can check the machine's work yourself. Every number traces to a file in asr_eval/; the reader at the bottom shows the actual transcript text each engine produced, on one shared clock, so you can watch them agree and disagree second by second. Nothing here is asserted to be a hallucination. The signals only describe the audio; verdicts are made explicitly, with reasons, and can be overturned by listening. Participants consented to share this material; names will be changed before any publication.

Why this is the hard, fair test

Think-aloud over live music is exactly the condition that breaks speech recognition: the speech is intermittent and buried under violin, piano, voice, or đàn tranh, and the model is tempted to fill the instrumental or quiet passages with invented text. We run each engine two ways — on the raw room recording and on an isolated voice stem (RoFormer removes the instrument) — and attach to every transcript segment the same audio reference: how much real voice is actually present at that moment (PANNs speech on the stem) and how much music (PANNs music on the room). Because the reference describes the audio, not the engine, it is a fair common ground for comparing machines.

Which machine hallucinates most

The engine people reach for first is not the one to trust. Whisper turbo (raw) transcribes over non-voice audio 49% of its time (≈ 702 minutes across the cohort); Deepgram Nova-3 (voice stem) is the cleanest at 29%. Whisper — the most widely used — loops and fabricates far more than the commercial engines, and its voice-stem run trades music-hallucination for a flood of subtitle-junk.

EngineAudioSessionsWordsRepetition loopsArtifact phrasesOver non-voice
Deepgram Nova-3stem26110 76459 (2.3/sess)92 (0.8/kw)29% (211 min)
Deepgram Nova-3raw26102 18295 (3.7/sess)88 (0.9/kw)32% (245 min)
AssemblyAI Universal-2stem26155 91912 (0.5/sess)101 (0.6/kw)33% (301 min)
Whisper large-v3stem26134 843285 (11.0/sess)1088 (8.1/kw)34% (261 min)
AssemblyAI Universal-2raw26150 0594 (0.2/sess)83 (0.6/kw)34% (317 min)
Whisper turbostem26152 179396 (15.2/sess)1110 (7.3/kw)35% (296 min)
Whisper large-v3raw1258 662147 (12.2/sess)427 (7.3/kw)42% (167 min)
Whisper turboraw26150 741509 (19.6/sess)765 (5.1/kw)49% (702 min)

Sorted cleanest → dirtiest by the share of transcribed time spent over non-voice audio. Rates are given per session (loops) and per 1 000 words (artifacts) so engines with different coverage compare fairly — Whisper large-v3 has a raw transcript for only 12 sessions, the rest have all 26. Reference: v=voice-stem PANNs speech · m=room PANNs music (shared across engines). "Over non-voice" is an indicator weighted continuously by (1 − voice-presence), not an exact hallucination clock.

Why AssemblyAI shows the fewest fabrications — and why that is not the same as "most accurate"

What the ranking actually measures. Every number in the table is a fabrication signal — looped lines, caption-junk phrases, and text emitted where the voice stem shows no voice. AssemblyAI Universal-2 and Deepgram Nova-3 score low on all three; the two Whisper models score high. That is a real, measured difference, but it is a statement about how much each engine invents, not about how correctly it transcribes the words that were truly spoken.

The likely mechanism (why the commercial engines invent less). Whisper is an encoder–decoder language model with no built-in voice-activity gate: handed an instrumental or silent passage, it still tries to decode words, and its autoregressive decoder can fall into repetition loops — the 500-plus loops and the © transcript Emily Beynon credit are textbook Whisper failure modes, and it learned the "Thank you / thanks for watching" phrases from caption-heavy training data. AssemblyAI and Deepgram are production systems built around strong voice-activity detection and endpointing: when they are not confident speech is present, they tend to emit nothing. Emitting nothing over the instrument is exactly what removes the fabrications we count.

Why "cleanest" is not "most correct." The same caution has a cost: an engine that stays silent when unsure can also drop real but quiet speech — a false-clean, not a true-accurate. We cannot crown any engine "correct," because we have no human ground-truth transcript to score against (no word-error-rate). So "AssemblyAI is cleanest" means precisely "it fabricates the least of what we can detect," and no more.

What we actually trust, then. Not any single engine, but agreement across independent engines over audio where a voice is present. When AssemblyAI, Deepgram, and Whisper — which never see each other's output — all print the same line while the voice-presence signal is high, that convergence is strong evidence the words are real. That is why the reading transcript below is built on cross-engine agreement, and why AssemblyAI is used only as a practical backbone (the fewest fabrications to wade through), never as an oracle.

How we decide — the coding scheme

To stay honest we separate what is measured (raw, automatic) from what is inferred (a verdict, with a reason, checkable against the audio). Four layers. Your three words map onto the verdict layer: nó thật → real, nó giả → fabricated, bị tịt tiếng nên fill vào → dead-audio.

ASR-evaluation coding scheme — layers, terms, definitions, examples

The point of this file is honesty and no early labelling. We separate what is measured (raw, automatic, no judgement) from what is inferred (a verdict, made by an LLM and/or a human, always with a rationale and always checkable against the audio). Four layers, from most raw to most interpretive.


Layer 1 — SIGNALS (raw, measured, no judgement)

Continuous or factual observations attached to every transcript segment. These assert nothing about truth; they only describe the audio and the text.

termdefinitionexample
v (voice-presence)PANNs speech probability on the voice stem (music removed), 0–1 — how much real voice is actually present at that momentv=0.01 → essentially no voice in the audio
m (music-presence)PANNs music probability on the raw room audio, 0–1m=0.90 → loud instrument playing
REPxNthis exact line occurs N times in a row (a plain fact about the text)"Thank you." REPx16
artifact-listthe text matches a published list of common ASR-artifact phrases (a heuristic pointer, not a verdict)"thanks for watching", "please subscribe"

Full transcripts with these signals inline are dumped to asr_eval/dumps/<name>_<raw|stem>.txt — every line shown, nothing hidden behind a count.

Layer 2 — CANDIDATE (heuristic routing, still not a verdict)

A segment becomes a candidate for review if any signal is unusual: low v, or REP>=3, or on the artifact-list. This only routes attention; it does not claim the segment is fake. Coherent real speech and a fabrication can both be candidates — that is exactly why a judging layer follows.

Layer 3 — ADJUDICATION CODES (the verdict — LLM and/or human, with rationale)

Each candidate is classified into exactly one code. The LLM is given the text, its neighbours, and the Layer-1 signals, and must give a one-line reason. A human can override; the audio is ground truth.

codedefinitiontypical evidenceexample
realgenuine speech, correctly transcribed — keepcoherent, context-consistent, v moderate/high"I'll focus on my facial expression."
fabricatedtext the model invented; not spoken — deletejunk/attribution/loop, v≈0, often m high (over music) or silent"© transcript Emily Beynon" x18, v≈0.01
dead-audioaudio was muted / lost (mic off) so no reliable transcript exists — researcher fills from another sourcea place where context implies speech but the channel is silent; ASR emits nothing or junka gap the participant clearly spoke in but the mic was off
misheardreal speech, wrong words (not invented from nothing) — correctplausible-but-wrong content over real voice (v moderate)a name or term transcribed incorrectly
uncertainevidence insufficient — needs the human/audioconflicting signals—

The three you named map directly: nó thật = real, nó giả = fabricated, bị tịt tiếng nên fill vào = dead-audio.

Layer 4 — THEMES (patterns across the cohort)

Recurring failure modes, named only after the codes exist (not assumed up front).

themedefinitionexample
music-fillfabrication over the instrument (model fills instrumental passages with words)~452 s on Jennifer raw
silence-junksubtitle-artifact phrases over silence (worse on the stem, whose gaps invite it)"Thank you." x16 on Jennifer stem
fabricated-attributioninvented names / credits entering the data as if spoken"© transcript Emily Beynon"
repetition-loopone line emitted many times10 loops / 256 s on Jennifer raw
dead-audio-gapmic-off stretches needing human fill (not an ASR fault, but a transcript gap)(to be tagged during adjudication)

Note on the study's broader coding vocabulary (kept distinct, per Anh-Thư)

This ASR-evaluation lane stops at Layer 4. real transcripts (human-verified) then flow to the separate coding/portraiture lane, where topics and content themes are built.

One session, adjudicated line by line — Jennifer

We routed the 45 most-flagged segments of Jennifer's session (violin + piano, 83 min) to an LLM, which classified each with a one-line reason. The load-bearing finding: fabrications and real speech often carry identical text — only the voice signal separates them.

Jennifer — ASR adjudication verdicts

Session: Jennifer - MultiCam Data - Violin and Piano - 2025-07-09 · camera 360-Camera-2 · 978 segments · 45 candidates reviewed (Whisper large-v3, raw room audio).

Counts by code

codecount
fabricated20
uncertain18
real7
misheard0
dead-audio0
total45

Confidence spread: high 17 · medium 12 · low 16.

Note on the two empty codes: nothing here is a clean dead-audio gap — the low-voice stretches are either full of loud instrument (music-fill fabrication) or near-silence with coherent text (routed to uncertain, not a muted-mic gap). And no case gave enough confirmed voice-with-wrong-words to justify misheard over the honest uncertain.

Instructive examples

Fabrication over the instrument (music-fill). idx 13, t=1022.6 — text "© transcript Emily Beynon" repeated ×18, v=0.05, m=0.90. No voice, loud violin/piano, an invented credit line looped 18 times. The textbook fabricated-attribution: a name that was never spoken entering the data as if it were.

Junk symbols filling loud passages. idx 4–10, t=250–458 — text "¶¶", v≈0.03–0.04, m≈0.85–0.94. Seven segments of pure junk over sustained instrument. The model emits something rather than nothing whenever the instrument is loud.

The artifact flag is only routing — high voice means keep. idx 30, t=3569.2 — "Thank you.", v=0.90, m=0.10, on the artifact-list. Despite matching a known junk phrase, the voice stem is nearly saturated and the neighbours are a real end-of-session conversation ("...practicing, because I was always focused on the sound..."). This is a real spoken thank-you. Contrast with idx 23, t=3022.3 — same words, v=0.05, m=0.89, looped ×3 → fabricated. Identical text, opposite verdict, decided by the voice signal.

Same word, two fates — the signal decides. idx 22, t=2909.2 — "Yeah.", v=0.93, answering "Is it good?" → real. idx 35–37, t=4408–4415 — "Yeah." ×9, v≈0.02–0.04, m=0.83 → fabricated repetition-loop. The transcript text alone cannot tell these apart.

Honestly ambiguous — near-silence with coherent text. idx 38–39, t=4430–4431 — "But then, it's so familiar." / "For piano, this is the familiar one.", v≈0.04, m≈0.05. Coherent and topic-apt, but no voice detected and no music to have masked it. This is genuinely undecidable from signals: could be real quiet speech the stem missed, or invented. Coded uncertain — a human must hear the audio. Same logic for idx 44 ("...my condition hasn't been so good recently."): specific and personal, which leans real, but v≈0 forbids a confident call.

High voice but loop-shaped — flagged, not resolved. idx 34, t=4017.1 — "Hey!" ×9, v=0.83, m=0.81. Real voice is clearly present, yet a 9× identical line is loop-like. Left uncertain rather than force-fitting real or fabricated.

What this says about trusting the raw transcript

Of 45 flagged segments, 20 are outright fabrications — invented credits, looped subtitle-phrases, and "¶¶" junk that the model manufactures to cover loud instrumental passages — and another 18 cannot be trusted without listening to the audio. Only 7 are confidently genuine, and several of those wear the exact same words ("Thank you.", "Yeah.") as neighbouring fabrications, so the text is worthless as its own evidence — only the per-moment voice-presence signal separates them. A raw Whisper transcript of a musician thinking aloud over their instrument therefore cannot be treated as verbatim: it silently mixes real utterances, invented attributions, and repetition loops that are indistinguishable on the page.

Read it like the studio timeline — original, filtered, coded

One shared time axis, drawn the way the study's own timeline is. Bottom-up it stacks ORIGINAL (each engine a lane of blocks at their exact start–end times) → FILTER (the machine's automatic flags, as bracketed spans) → CODE (the adjudicated verdict, where a human/LLM has judged) — granular at the bottom, grouped upward with brackets. The top lane is the person: their own voice/music track, from the session audio, independent of any engine — the anchor everything hangs on. Drag the overview to jump; use the zoom to go from whole-session shape to word-by-word reading.

lanes: loading…
Top lane = the person (■ voice · ■ music, from the session audio, never an engine). Each engine lane below shows its lines as blocks at their real duration, dimmed continuously by voice-presence — nothing hidden. REP×N looped line · artifact caption-junk match (pointers, not verdicts). Bracket tiers above a lane are the machine's filter flags and, where judged, the code (real / fabricated / uncertain) with its reason on hover. Overlap at low zoom is expected — that is the overview; zoom in to read. Zoom is a viewing control, not a threshold.

Verify every step yourself

Nothing here is a black box. Each stage is a small script you can open and re-run; the reader above is just the last stage made visible. This is the whole path from a raw audio file to a line on the screen:

  1. Raw transcripts. Each engine's per-clip output sits untouched on the data drive (transcripts_<engine>/, …_vocalstem/ for the stem). We never edit them.
  2. Load into segments. hallucination.py reads each format (Whisper JSON, Deepgram sentences, AssemblyAI words→sentences) into one shape {start, end, text} — every engine starts its first line "Weather is really bad for tuning." at ~13 s, so the parsing lines up.
  3. Place on the session clock. Each clip's offset comes from alignment.json, matched by its VID id (not by sort order), so a clip that started 11 min in lands 11 min in.
  4. Attach the human's voice track. audio_classification_vocals.json / audio_classification.json (PANNs) give voice- and music-presence for every second, computed once and shared by all engines — the anchor column.
  5. Measure, threshold-free. analyze() counts repetition loops (≥3 identical in a row) and artifact phrases (a published junk list), and weights transcription by (1−voice-presence) — no tuned cut-offs.
  6. Aggregate + align for reading. build_multiengine.py writes one JSON per session (multiengine/) with all engines on the shared clock plus the 1 s voice track; the cohort table above is results/COHORT_engines.json.
  7. Judge, out loud. adjudicate.py routes the flagged lines and an LLM assigns real / fabricated / dead-audio with a one-line reason (adjudication/) — always overturnable by listening. The full dumps in dumps/ show every line, verdict-free.

What this supports, honestly

The point is not that ASR is useless — most words in every engine are real speech, and the cleaner commercial engines are genuinely usable as a first draft. The point is that even the strongest engines fabricate content — invented credits, looped subtitle-phrases, foreign-language junk over the instrument — at rates that make an unreviewed transcript unsafe as a record of what a person actually said. A line like © transcript Emily Beynon entering the dataset as if a participant said it is the exact risk: a fabricated attribution silently coded as data. And because fabrication and real speech can carry identical words, the text cannot police itself. For verbatim human-subjects analysis, a human must transcribe — or verify every line against the audio — before the text is treated as evidence. That is the evidence behind the requirement.

PANNs also gives the whole-session trend of talking vs. music vs. both at once — but "talking" there is room talk (researcher + participant combined), never attributed to a person, until speaker diarization / voice-ID is added. Still to come: speaker-attribution error, and feeding the human-verified transcripts into the separate coding / portraiture lane.

Sources under asr_eval/: per-engine cohort results/COHORT_engines.json · per-session aligned segments multiengine/ (served here as data/) · full single-engine dumps dumps/ · coding scheme CODING_SCHEME.md · adjudication adjudication/ · dossier ASR_RELIABILITY_DOSSIER.md. Built by build_multiengine.py + build_asr_page.py, toward a separate ASR-reliability paper.