Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/6xingyv/accompanist-lyrics-core/llms.txt

Use this file to discover all available pages before exploring further.

Accompanist Lyrics Core is designed so that the most common use case — reading a lyrics string from a file or network response and getting structured, timed lines back — requires almost no configuration. The following walkthrough takes you from zero to a fully navigable SyncedLyrics object, then shows how to look up the active line by playback time and export the result to LRC.
1

Add the dependency

Add the artifact to your build.gradle.kts. If you are working in a Kotlin Multiplatform project, place it in commonMain.
dependencies {
    implementation("com.mocharealm.accompanist:lyrics-core:0.4.5")
}
See the Installation guide for version catalogs, KMP target details, and repository setup.
2

Parse lyrics with AutoParser

AutoParser accepts a raw lyrics string and automatically detects the format by running each registered parser’s canParse() check in sequence. The first parser that claims the content handles the parse.
import com.mocharealm.accompanist.lyrics.core.parser.AutoParser

// Obtain your lyrics string — from disk, a network call, or a content provider
val lyricsContent: String = fetchLyrics()

// Create a default AutoParser instance
val autoParser = AutoParser()

// Parse — returns a SyncedLyrics regardless of the source format
val lyrics = autoParser.parse(lyricsContent)

// Top-level metadata
println(lyrics.title)
println(lyrics.artists?.joinToString(", ") { it.name })
The default AutoParser checks parsers in this order: TTMLParserLyricifySyllableParserEnhancedLrcParserKugouKrcParser. Standard LRC files are handled by EnhancedLrcParser, which also produces syllable-level output when Enhanced LRC word-timing tags are present. If no parser recognises the content, AutoParser returns an empty SyncedLyrics.
If you already know the format of the file, use the specific parser directly to skip the detection loop and avoid any ambiguity:
import com.mocharealm.accompanist.lyrics.core.parser.EnhancedLrcParser
import com.mocharealm.accompanist.lyrics.core.parser.TTMLParser
import com.mocharealm.accompanist.lyrics.core.parser.LyricifySyllableParser
import com.mocharealm.accompanist.lyrics.core.parser.KugouKrcParser

val lyrics = EnhancedLrcParser.parse(lrcContent)     // LRC or Enhanced LRC
val lyrics = TTMLParser().parse(ttmlContent)          // TTML / Apple Music
val lyrics = LyricifySyllableParser.parse(lsfContent) // Lyricify Syllable
val lyrics = KugouKrcParser.parse(krcContent)         // Kugou KRC
3

Access lines and timing data

Every entry in lyrics.lines implements ISyncedLine, which guarantees start, end, and duration in milliseconds. Use a when expression to branch on the concrete type and access format-specific data.
import com.mocharealm.accompanist.lyrics.core.model.synced.SyncedLine
import com.mocharealm.accompanist.lyrics.core.model.karaoke.KaraokeLine

for (line in lyrics.lines) {
    when (line) {
        is SyncedLine -> {
            // Plain or translated line — no syllable data
            println("${line.start}ms – ${line.end}ms: ${line.content}")
            line.translation?.let { println("  ↳ Translation: $it") }
        }
        is KaraokeLine.MainKaraokeLine -> {
            // Syllable-timed main vocal line
            val fullText = line.syllables.joinToString("") { it.content }
            println("${line.start}ms – ${line.end}ms: $fullText")

            // Individual syllable timestamps
            for (syllable in line.syllables) {
                print("${syllable.content}[${syllable.start}${syllable.end}ms] ")
            }
            println()

            // Optional translation and phonetic annotation
            line.translation?.let { println("  ↳ Translation: $it") }
            line.phonetic?.let { println("  ↳ Phonetic: $it") }

            // Background / accompaniment vocals embedded in the same line
            line.accompanimentLines?.forEach { accompaniment ->
                val bgText = accompaniment.syllables.joinToString("") { it.content }
                println("  ↳ Background: $bgText")
            }
        }
        is KaraokeLine.AccompanimentKaraokeLine -> {
            // Stand-alone accompaniment/background vocal line
            val bgText = line.syllables.joinToString("") { it.content }
            println("${line.start}ms – ${line.end}ms (background): $bgText")
            line.translation?.let { println("  ↳ Translation: $it") }
        }
    }
}
4

Get the current line by playback time

SyncedLyrics provides a binary-search helper that returns the index of the line that should be highlighted at a given playback position. Pass the current position in milliseconds and use the returned index to scroll or highlight your UI.
// timeMs is your player's current position in milliseconds (e.g. from ExoPlayer or AVPlayer)
val timeMs: Int = player.currentPositionMs.toInt()

// Returns the index of the first line active at timeMs
val currentIndex: Int = lyrics.getCurrentFirstHighlightLineIndexByTime(timeMs)

if (currentIndex < lyrics.lines.size) {
    println("Now playing line $currentIndex: ${lyrics.lines[currentIndex]}")
}
For duet or overlapping-vocal scenarios where multiple lines can be active simultaneously, use the companion function:
val activeIndices: List<Int> = lyrics.getCurrentAllHighlightLineIndicesByTime(timeMs)
activeIndices.forEach { index ->
    println("Active line $index: ${lyrics.lines[index]}")
}
Both timing functions perform a binary search on the lines list and are safe to call on every UI frame or playback tick — they do not iterate the full list.
5

Export to LRC

Use LrcExporter to serialise a SyncedLyrics object back into a standard LRC string. Karaoke lines are automatically flattened to plain text, and translation lines are written as duplicate timestamps. Title and artist metadata are written as [ti:] and [ar:] ID3 tags.
import com.mocharealm.accompanist.lyrics.core.exporter.LrcExporter

val lrcString: String = LrcExporter.export(lyrics)

// Write to file, send over network, copy to clipboard, etc.
println(lrcString)
Example output for a two-line parsed file:
[ti:Song Title]
[ar:Artist Name]
[00:39.96]I lean in and you move away
[00:39.96]我靠在里面,你就离开
[00:44.12]Every time I reach out

Next steps

Now that you can parse, navigate, and export lyrics, explore the rest of the documentation:
  • Parsers Overview — learn about the individual parsers, their detection heuristics, and which features each format supports.
  • Exporters Overview — details on LrcExporter and the ILyricsExporter interface for building custom exporters.
  • Custom Parser Guide — implement ILyricsParser and register it with AutoParser to handle any proprietary format.

Build docs developers (and LLMs) love