Table of Contents

Playback

The extension methods in LrcDocumentExtensions look up lines by playback position, for example to show the current line of a song while it plays.

Offset

Line timestamps are kept as written. [offset:N] is stored in LrcMetadata.Offset, so writing the document gives back the same tag. The lookup methods apply it for you: a line's effective time is its timestamp minus Offset, so a positive offset shows lyrics sooner and a negative one later, as in other LRC players.

TimeSpan effective = doc.GetEffectiveTime(line.Timestamp);

GetEffectiveTime returns a TimeSpan because a positive offset can take it below zero, which an LrcTimestamp can't represent.

Current line

FindLineAt returns the last line whose effective time is at or before the position, so between two lines you get the earlier one. It returns null before the first line or when the document has no lines. It is a binary search, so calling it every frame is fine.

LrcLine? current = doc.FindLineAt(player.Position);
string text = current?.GetText() ?? "";

Current word

On an enhanced line, the current word is the last one whose effective time is at or before the position:

if (doc.FindLineAt(player.Position) is LrcEnhancedLine enhanced)
{
    LrcWord? currentWord = null;
    foreach (var word in enhanced.Words)
    {
        if (doc.GetEffectiveTime(word.Timestamp) > player.Position) break;
        currentWord = word;
    }
    // Highlight currentWord.
}

Upcoming lines

LinesInRange returns the lines whose effective time is in [start, end), in order:

foreach (var line in doc.LinesInRange(player.Position, player.Position + TimeSpan.FromSeconds(10)))
    Console.WriteLine(line.GetText());

Voice

Each line's EffectiveVoice is already resolved: a Walaoke M: , F: or D: marker applies to its line and every line after it until the next marker.

string color = doc.FindLineAt(player.Position)?.EffectiveVoice switch
{
    LrcVoice.Male => "blue",
    LrcVoice.Female => "pink",
    LrcVoice.Duet => "gold",
    _ => "white",
};