lacing.tracks.subtitle#

Subtitle / lyric / caption tracks — the (sections, lines, words) trio.

SubtitleBuilder lets callers add sections, lines, and words to a store with float seconds and a single asset_id, instead of hand-rolling Annotation / MediaRef / Provenance / TimeInterval. SubtitleTrack provides matching read-side convenience: lines_in(window), words_in(window), sections_covering(t).

Body schemas are conventional URIs:

  • annot://schema/song-section/v1 — {label, title?, energy?, mood?}

  • annot://schema/lyric-line/v1 — {text, line_index?, section?}

  • annot://schema/word/v1 — {text, line_index?, confidence?}

    (matches the built-in lacing.bodies.word schema)

These are not enforced unless the caller has registered Pydantic validators for them; register_subtitle_schemas will register simple permissive validators if you want body validation. Otherwise the body is just a dict.

Quick start:

from lacing import MemoryStore
from lacing.tracks.subtitle import SubtitleBuilder, SubtitleTrack

store = MemoryStore()
with SubtitleBuilder(store, asset_id="song/audio.mp3") as b:
    b.section("intro", 0.0, 12.5)
    b.line("I came down to the river", 12.5, 16.2,
           section="verse_1", words=[
               ("I",     12.5, 12.7),
               ("came",  12.7, 13.0),
               ("down",  13.0, 13.3),
           ])

track = SubtitleTrack(store, asset_id="song/audio.mp3")
chorus_lines = track.lines_in(35.0, 55.0)
section_at_42 = track.sections_covering(42.0)

Module Attributes

BUILT_IN_BODY_SCHEMAS

Mapping of body URI → minimal example body.

Functions

register_subtitle_schemas()

Register permissive body validators for the subtitle URIs.

Classes

SubtitleBuilder(store, *, asset_id[, rate, ...])

Builder for (sections, lines, words) tiers over one asset.

SubtitleTrack(store, *, asset_id[, rate])

Read-side facade for (sections, lines, words) over an asset.

lacing.tracks.subtitle.BUILT_IN_BODY_SCHEMAS: dict[str, dict[str, Any]] = {'annot://schema/lyric-line/v1': {'line_index': 0, 'section': 'verse_1', 'text': 'I came down to the river'}, 'annot://schema/song-section/v1': {'energy': 'medium', 'label': 'verse_1', 'mood': 'wistful', 'title': 'verse 1'}, 'annot://schema/word/v1': {'confidence': 0.94, 'line_index': 0, 'text': 'river'}}#

Mapping of body URI → minimal example body. Used by register_subtitle_schemas() and as inline reference for callers building outside the builder.

class lacing.tracks.subtitle.SubtitleBuilder(store, *, asset_id, rate=1000, was_generated_by='lacing.tracks.subtitle', was_attributed_to='lacing', ensure_tiers=True)[source]#

Bases: object

Builder for (sections, lines, words) tiers over one asset.

The builder is a context manager only as a convenience; it has no transactional semantics. Calling .section() / .line() / .word() writes immediately, in the order given.

Parameters:
  • store (IntervalAnnotationStore) – Any IntervalAnnotationStore (memory, sqlite, postgres).

  • asset_id (str) – The MediaRef.asset_id to attach every annotation to. Typically a path or content-hash of the audio file.

  • rate (int) – Tick rate for time intervals. Defaults to 1000 (ms).

  • was_generated_by (str) – Provenance.was_generated_by. Defaults to "lacing.tracks.subtitle".

  • was_attributed_to (str) – Provenance.was_attributed_to.

  • ensure_tiers (bool) – When True (default), creates the three tiers if they don’t exist. Pass False if your store uses different tier names and you’ve created them yourself.

add(*, tier, body_schema_uri, body, start_s, end_s)[source]#

Add an annotation to tier with explicit schema/body.

Return type:

_BuiltAnnotation

line(text, start_s, end_s, *, line_index=None, section='', words=(), extra=None)[source]#

Add a lyric line. words is an optional list of (text, start, end) or (text, start, end, confidence) tuples that will be inserted on the words tier.

Return type:

_BuiltAnnotation

section(label, start_s, end_s, *, title='', energy='', mood='', extra=None)[source]#

Add a song section.

Return type:

_BuiltAnnotation

word(text, start_s, end_s, *, line_index=None, confidence=None, extra=None)[source]#

Add one word.

Return type:

_BuiltAnnotation

class lacing.tracks.subtitle.SubtitleTrack(store, *, asset_id, rate=1000)[source]#

Bases: object

Read-side facade for (sections, lines, words) over an asset.

Methods take float seconds; conversions to RationalTime are handled internally. Returned annotations are sorted by start time.

Parameters:
  • store (IntervalAnnotationStore) – Any IntervalAnnotationStore.

  • asset_id (str | None) – When set, query results are filtered to annotations whose MediaRef.asset_id equals this value. Pass None to ignore asset filtering (rarely what you want).

  • rate (int) – Tick rate used to build query intervals.

lines_in(start_s, end_s)[source]#

Lines that overlap [start_s, end_s].

Return type:

list[Annotation]

sections_covering(t)[source]#

Sections whose interval contains t (typically one).

Return type:

list[Annotation]

words_in(start_s, end_s)[source]#

Words that overlap [start_s, end_s].

Return type:

list[Annotation]

lacing.tracks.subtitle.register_subtitle_schemas()[source]#

Register permissive body validators for the subtitle URIs.

Calling this is optional; the builder works fine without registered schemas. Use it when you want body-shape errors to surface at write time rather than later.

Return type:

None