@karaplay/karaoke-player
v1.0.14
Published
Karaoke player library with A/B swapping renderer for MIDI karaoke files
Downloads
1,474
Maintainers
Readme
@karaplay/karaoke-player
Karaoke player library with A/B swapping renderer for MIDI karaoke files.
🎯 More Accurate Timing Options
This library now supports multiple timing methods for maximum accuracy:
MIDI Note Events (⭐ Best) - Use note events from vocal track
- Most accurate - uses native MIDI tick timing
- Knows when to sing and when to rest (Note On/Off)
- Word/syllable level mapping
- See MIDI_NOTE_APPROACH.md for details
MIDI Lyric Events - Use lyric events from MIDI file
- Very accurate - absolute timing
- See MIDI_LYRIC_APPROACH.md for details
CUR File - Fallback method
- Relative timing, requires normalization
Why MIDI Lyric Events?
- ✅ Absolute Timing: No normalization needed - timing is absolute
- ✅ Native MIDI Integration: Timing matches MIDI playback 100%
- ✅ Tempo-Aware: Automatically handles tempo changes
- ✅ Standard Format: Uses MIDI standard (SMF format)
- ✅ Backward Compatible: Falls back to CUR file if MIDI doesn't have lyric events
Quick Start with MIDI Note Events (Recommended)
import {
parseMidiNotes,
notesToCharTimestamps,
findVocalTrack
} from '@karaplay/karaoke-player';
// Parse MIDI file for note events
const midiBuffer = await fetchArrayBuffer('/midi');
const result = parseMidiNotes(midiBuffer, {
minNote: 48, // C3 - vocal range
maxNote: 84 // C6 - vocal range
});
// Find vocal track automatically
const vocalTrack = findVocalTrack(result.tracks);
// Convert note events to timestamps
const words = fullLyricText.split(/\s+/);
const timestamps = notesToCharTimestamps(
vocalTrack.notes,
result.tempoMap,
result.division,
fullLyricText,
words
);Alternative: MIDI Lyric Events
import { parseMidiLyrics, lyricEventsToTimestamps } from '@karaplay/karaoke-player';
const { lyricEvents, tempoMap, division } = parseMidiLyrics(midiBuffer);
const timestamps = lyricEventsToTimestamps(
lyricEvents,
tempoMap,
division,
fullLyricText
);Installation
npm install @test-midi/karaoke-playerUsage
Basic Setup
import {
initMidiPlayer,
parseLyrics,
parseCurTimestamps,
normalizeTimestamps,
getCurrentCharByTime,
renderABSwap,
computeBaseMs,
safeGetStatus,
playMidi,
pauseMidi,
stopMidi,
seekMidi,
setSongDuration,
injectCalibrationUI,
getLyricSpeed,
getTimeOffsetMs
} from '@test-midi/karaoke-player';
// Initialize MIDI player
await initMidiPlayer();
// Set song duration
setSongDuration(180000); // 3 minutes
// Parse lyrics
const lyricText = await fetch('/lyrics.lyr').then(r => r.text());
const { fullText, lineTexts } = parseLyrics(lyricText);
// Parse CUR timestamps
const curBuffer = await fetch('/song.cur').then(r => r.arrayBuffer());
const rawTimestamps = parseCurTimestamps(curBuffer);
const timestamps = normalizeTimestamps(rawTimestamps, 180000);
// Render loop
function render() {
const status = safeGetStatus();
const baseMs = computeBaseMs(status);
const lyricSpeed = getLyricSpeed();
const timeOffsetMs = getTimeOffsetMs();
const lyricMs = (baseMs + timeOffsetMs) * lyricSpeed;
const currentCharPos = getCurrentCharByTime(timestamps, lyricMs);
renderABSwap(currentCharPos, lineTexts, lyricMs, timestamps);
requestAnimationFrame(render);
}
// Start rendering
render();HTML Structure
Your HTML should have two elements for the karaoke lines:
<div id="line1"></div>
<div id="line2"></div>Calibration UI
To add the calibration UI panel:
import { injectCalibrationUI } from '@test-midi/karaoke-player';
injectCalibrationUI();This will add a floating panel for adjusting lyric speed and time offset.
API Reference
Utilities
$(id)- Get DOM element by ID with cachingesc(s)- Escape HTML special charactersclamp(x, a, b)- Clamp value between min and maxformatTime(ms)- Format milliseconds to MM:SSfetchArrayBuffer(url)- Fetch array buffer from URL
Lyric Parser
decodeLyric(buffer)- Decode lyric buffer to text using multiple encodingsparseLyrics(text)- Parse lyrics text and extract singing linesparseCurTimestamps(buffer)- Parse CUR timestamps from buffernormalizeTimestamps(timestamps, songDurationMs)- Normalize timestamps to song durationgetCurrentCharByTime(timestamps, currentTimeMs)- Get current character position by time using binary searchfindLineByCharPos(lineTexts, charPos)- Find line by character position
MIDI Player
initMidiPlayer()- Initialize MIDI player (requires WebAudioTinySynth)setSongDuration(durationMs)- Set song durationsafeGetStatus()- Get player status safelycomputeBaseMs(status)- Compute base time in milliseconds from player statusplayMidi()- Play MIDIpauseMidi()- Pause MIDIstopMidi()- Stop MIDI and reset positionseekMidi(ms)- Seek MIDI to specific time
Calibration
injectCalibrationUI()- Inject calibration UI panelgetLyricSpeed()- Get current lyric speedgetTimeOffsetMs()- Get current time offset
Renderer
renderABSwap(currentCharPos, lineTexts, lyricMs, curTimestamps)- Render karaoke with A/B slot swapping
Requirements
- WebAudioTinySynth library (must be loaded separately)
- Modern browser with ES6 module support
License
MIT
