Skip to content

syncalong.pipeline

High-level facade that runs the whole lyrics + audio → timestamped result pipeline. This is the entry point most callers want.

pipeline

High-level alignment pipeline: lyrics + audio → timestamped result.

AlignmentResult dataclass

AlignmentResult(timed_lines: list[tuple[LyricLine, float | None]], lrc: str, matched: int, total: int)

Result of aligning lyrics to an audio file.

Attributes:

Name Type Description
timed_lines list[tuple[LyricLine, float | None]]

One (LyricLine, timestamp_or_None) pair per lyric line, in order. The timestamp (seconds) is the line's start time, or None if it could not be aligned.

lrc str

The same alignment rendered as an LRC document.

matched int

Number of lines that received a timestamp.

total int

Total number of lines.

align

align(lyrics: LyricsInput, audio: AudioInput, *, transcriber: Transcriber | None = None, model_name: str = 'base', language: str | None = None, use_lyrics_prompt: bool = True, threshold: float = 55.0, separate_vocals: bool = False) -> AlignmentResult

Align lyrics to an audio file and return a structured result.

Parameters:

Name Type Description Default
lyrics LyricsInput

A :class:~pathlib.Path to a lyrics file, the raw lyrics as a str, or an already-parsed list[LyricLine].

required
audio AudioInput

Path to the audio file (str or :class:~pathlib.Path).

required
transcriber Transcriber | None

A reusable :class:~syncalong.transcribe.Transcriber. When None, a transient one is built from model_name.

None
model_name str

Whisper model to load when transcriber is None.

'base'
language str | None

BCP-47 language code, or None to auto-detect.

None
use_lyrics_prompt bool

Whether to bias Whisper with the lyrics text.

True
threshold float

Minimum fuzzy score (0–100) to accept a word match.

55.0
separate_vocals bool

When True, isolate vocals with Demucs first.

False

Returns:

Name Type Description
An AlignmentResult

class:AlignmentResult.

Raises:

Type Description
TypeError

If lyrics is not a Path, str, or list.

ModuleNotFoundError

If separate_vocals is True but demucs is not installed.

Source code in src/syncalong/pipeline.py
def align(
    lyrics: LyricsInput,
    audio: AudioInput,
    *,
    transcriber: Transcriber | None = None,
    model_name: str = "base",
    language: str | None = None,
    use_lyrics_prompt: bool = True,
    threshold: float = 55.0,
    separate_vocals: bool = False,
) -> AlignmentResult:
    """Align lyrics to an audio file and return a structured result.

    Args:
        lyrics: A :class:`~pathlib.Path` to a lyrics file, the raw lyrics as a
            ``str``, or an already-parsed ``list[LyricLine]``.
        audio: Path to the audio file (``str`` or :class:`~pathlib.Path`).
        transcriber: A reusable :class:`~syncalong.transcribe.Transcriber`.
            When ``None``, a transient one is built from ``model_name``.
        model_name: Whisper model to load when ``transcriber`` is ``None``.
        language: BCP-47 language code, or ``None`` to auto-detect.
        use_lyrics_prompt: Whether to bias Whisper with the lyrics text.
        threshold: Minimum fuzzy score (0–100) to accept a word match.
        separate_vocals: When ``True``, isolate vocals with Demucs first.

    Returns:
        An :class:`AlignmentResult`.

    Raises:
        TypeError: If ``lyrics`` is not a ``Path``, ``str``, or list.
        ModuleNotFoundError: If ``separate_vocals`` is ``True`` but ``demucs``
            is not installed.
    """
    lyric_lines = _coerce_lyrics(lyrics)
    audio_path = Path(str(audio))

    if separate_vocals:
        audio_path = _separate_vocals(audio_path)

    if transcriber is None:
        transcriber = Transcriber(model_name)

    prompt = lyrics_prompt(lyric_lines) if use_lyrics_prompt else None
    transcript = transcriber.transcribe(
        audio_path, language=language, initial_prompt=prompt
    )

    timed_lines = align_lyrics_to_transcript(
        lyric_lines, transcript, threshold=threshold
    )
    lrc = format_lrc(timed_lines)
    matched = sum(1 for _, ts in timed_lines if ts is not None)
    return AlignmentResult(
        timed_lines=timed_lines,
        lrc=lrc,
        matched=matched,
        total=len(timed_lines),
    )

align_to_lrc

align_to_lrc(lyrics: LyricsInput, audio: AudioInput, **kwargs: Any) -> str

Align lyrics to audio and return just the LRC document.

Convenience wrapper: equivalent to align(lyrics, audio, **kwargs).lrc.

Parameters:

Name Type Description Default
lyrics LyricsInput

See :func:align.

required
audio AudioInput

See :func:align.

required
**kwargs Any

Forwarded verbatim to :func:align.

{}

Returns:

Type Description
str

The LRC document as a string.

Source code in src/syncalong/pipeline.py
def align_to_lrc(lyrics: LyricsInput, audio: AudioInput, **kwargs: Any) -> str:
    """Align lyrics to audio and return just the LRC document.

    Convenience wrapper: equivalent to ``align(lyrics, audio, **kwargs).lrc``.

    Args:
        lyrics: See :func:`align`.
        audio: See :func:`align`.
        **kwargs: Forwarded verbatim to :func:`align`.

    Returns:
        The LRC document as a string.
    """
    return align(lyrics, audio, **kwargs).lrc