muvid.lyrics
Lyrics — transcription and markdown round-trip.
Two surfaces for the user:
transcribe(audio_path)— callsmixing.transcript.transcribe(ElevenLabs Scribe) and writes the raw word-timestamped JSON tolyrics/transcript.json. This is the seed; the user is expected to correct it.write_lyrics_md/parse_lyrics_md— the canonical, editable form. A simple markdown with[section]headers, one line per sung line, and an optional// <seconds>end-of-line anchor.
The alignment module consumes both: it reads lyrics.md for the
text the user committed to, and transcript.json for the timing
to splice in.
- class muvid.lyrics.LyricLine(*, text: str, line_index: int, section_label: str = '', start_s: float | None = None)[source]
One line of lyric text, optionally with a known start time.
- class muvid.lyrics.LyricSection(*, label: str, title: str = '', start_s: float | None = None, end_s: float | None = None, lines: tuple[LyricLine, ...] = ())[source]
A user-tagged section in the lyrics markdown.
Times are optional — if not present, alignment is computed from transcripts; if present, they override.
- class muvid.lyrics.LyricsDoc(*, sections: tuple[LyricSection, ...])[source]
Full parsed view of the user’s lyrics markdown.
- muvid.lyrics.lyrics_from_transcript(transcript: dict[str, Any]) LyricsDoc[source]
Build a default LyricsDoc from a transcription response.
Heuristic: split lines on punctuation (
. ? !) or on long pauses (>0.6 s gap between consecutive words). One[transcribed]section holds everything; the user is expected to re-tag with real sections.
- muvid.lyrics.parse_lyrics_md(md: str) LyricsDoc[source]
Parse the user-editable lyrics markdown.
Format:
[section_label] optional title line of lyric // 12.5 another line [next section] ...
Empty lines are separators between sections.
(instrumental)or any line starting with(and ending with)is treated as a non-lyric placeholder (no LyricLine emitted).
- muvid.lyrics.render_lyrics_md(doc: LyricsDoc) str[source]
Inverse of
parse_lyrics_md. Stable round-trip.
- muvid.lyrics.transcribe(audio_path: str | Path, *, api_key: str | None = None, out_path: str | Path | None = None, cache: bool | str | Path = True) dict[str, Any][source]
Run ElevenLabs Scribe on the audio and (optionally) write the JSON.
Returns the raw response dict (which contains
words: [...]with per-wordtext,start,end,confidence).The on-disk Scribe cache (in
mixing.transcript) is enabled by default, so re-running on the same audio is free. Passcache=Falseto force a fresh round-trip.
- muvid.lyrics.words_from_transcript(transcript: dict[str, Any]) list[dict[str, Any]][source]
Normalize Scribe’s word entries:
[{text, start, end, confidence}, ...].Filters out non-word events (Scribe surfaces
(laughs)etc. withtype≠word) and ones missing timing.confidenceis pass-through; absent →None.