@karaplay/file-coder
v1.4.4
Published
A comprehensive library for encoding/decoding karaoke files (.emk, .kar, MIDI) with Next.js support. Convert EMK to KAR, read/write karaoke files, full browser and server support.
Downloads
1,979
Maintainers
Readme
@karaplay/file-coder
A comprehensive library for encoding/decoding karaoke files (.emk, .kar, MIDI) with Next.js support.
✅ Thai Support: Thai lyrics are fully supported with proper TIS-620 encoding. All Thai characters are preserved and readable throughout the EMK→KAR conversion process.
Features
- 🎵 Convert NCN format (.mid + .lyr + .cur) to .kar (MIDI karaoke)
- 🔓 Decode .emk (Extreme Karaoke) files
- 📖 Read and validate .kar files
- ⚡ NEW: Complete EMK → KAR workflow (one-step conversion)
- 🌐 Full TypeScript support
- ⚛️ Next.js compatible (both client and server side)
- 🌐 NEW: Browser-compatible API for client-side processing
- 🇹🇭 Thai language support (TIS-620 encoding)
- ✅ FIXED v1.3.2: Client-side EMK decoder now works correctly!
- ✅ 131 tests - 100% pass rate (including integration tests with real files)
Installation
npm install @karaplay/file-coderQuick Start
Browser/Client-Side (Next.js) 🌐 NEW
For client-side processing in Next.js or browser environments:
'use client';
import { convertEmkFileToKar } from '@karaplay/file-coder/client';
function MyComponent() {
const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const result = await convertEmkFileToKar(file, { autoDownload: true });
console.log('Converted:', result.metadata.title);
};
return <input type="file" accept=".emk" onChange={handleFileUpload} />;
}📚 Full Browser API Documentation →
Server-Side (Node.js)
Usage
EMK to KAR Workflow (Complete Pipeline) ⭐ NEW
Convert EMK files directly to KAR in one step:
import { convertEmkToKar } from '@karaplay/file-coder';
const result = convertEmkToKar({
inputEmk: 'songs/song.emk',
outputKar: 'output/song.kar'
});
console.log(`Title: ${result.metadata.title}`);
console.log(`Artist: ${result.metadata.artist}`);
console.log(`Success: ${result.success}`);
// Thai text is readable! ✅Batch conversion:
import { convertEmkToKarBatch } from '@karaplay/file-coder';
const results = convertEmkToKarBatch(
['song1.emk', 'song2.emk', 'song3.emk'],
'output/kar'
);See EMK_TO_KAR_WORKFLOW.md for complete documentation.
NCN to KAR Conversion
import { convertNcnToKar } from 'file-coder';
const result = convertNcnToKar({
inputMidi: 'path/to/song.mid',
inputLyr: 'path/to/song.lyr',
inputCur: 'path/to/song.cur',
outputKar: 'path/to/output.kar',
appendTitles: true
});
console.log(`Converted: ${result.metadata.title} by ${result.metadata.artist}`);EMK Decoding (Server-side)
import { decodeEmkServer, parseSongInfoServer } from 'file-coder';
import * as fs from 'fs';
const fileBuffer = fs.readFileSync('path/to/song.emk');
const decoded = decodeEmkServer(fileBuffer);
// Access decoded parts
const midiData = decoded.midi;
const lyricData = decoded.lyric;
const cursorData = decoded.cursor;
// Parse song information
const songInfo = parseSongInfoServer(decoded.songInfo);
console.log(`Title: ${songInfo.TITLE}`);
console.log(`Artist: ${songInfo.ARTIST}`);EMK Decoding (Client-side/Next.js)
'use client';
import { decodeEmkClient, parseSongInfoClient } from 'file-coder';
function MyComponent() {
const handleFileUpload = async (file: File) => {
const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const decoded = decodeEmkClient(buffer);
const songInfo = parseSongInfoClient(decoded.songInfo);
console.log(`Title: ${songInfo.TITLE}`);
};
return <input type="file" onChange={(e) => handleFileUpload(e.target.files[0])} />;
}API Reference
NCN to KAR Functions
convertNcnToKar(options)- Main conversion functionparseLyricFile(filePath)- Parse .lyr file for metadatabuildKaraokeTrack(metadata, cursorBuffer, ticksPerBeat)- Build karaoke track with timingbuildMetadataTracks(metadata)- Build metadata tracksCursorReader- Class for reading cursor timing data
EMK to KAR Workflow Functions ⭐ NEW
convertEmkToKar(options)- Complete pipeline: EMK → KAR (one step!)convertEmkToKarBatch(emkFiles, outputDir, options?)- Batch convert multiple filesvalidateThaiLyricReadability(lyricBuffer)- Validate Thai text readability
KAR File Reader Functions
readKarFile(filePath)- Read and parse .kar filevalidateKarFile(filePath)- Validate .kar file structureextractLyricsFromKar(filePath)- Extract lyrics from .kar file
EMK Decoder Functions
Server-side
decodeEmkServer(fileBuffer)- Decode .emk file (Node.js)parseSongInfoServer(songInfoBuffer)- Parse song metadataxorDecryptServer(data)- XOR decryption utilitylooksLikeTextServer(buffer)- Text detection utility
Client-side
decodeEmkClient(fileBuffer)- Decode .emk file (Browser/Next.js)parseSongInfoClient(songInfoBuffer)- Parse song metadataxorDecryptClient(data)- XOR decryption utilitylooksLikeTextClient(buffer)- Text detection utility
Development
Install Dependencies
npm installBuild
npm run buildRun Tests
npm testTest Coverage
npm run test:coverageRequirements
- Node.js >= 16
- TypeScript >= 5.0
- Next.js >= 13.0 (optional, for client-side features)
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Changelog
v1.3.2 (Latest)
🔧 Critical Fix: Client-Side EMK Decoder
- Fixed: Client-side EMK decoder was failing with "Invalid EMK structure: expected at least 3 zlib blocks, found 0"
- Root Cause: Missing
ZLIB_SECOND_BYTESvalidation check in client-decoder (was only checking first byte 0x78) - Solution: Added proper zlib header validation (both bytes) and fallback to Node.js zlib when available
- Added: 12 comprehensive client-side decoder tests
- Result: Client-side EMK decoding now works in both Node.js (tests/SSR) and browser environments
Test results:
// All EMK files decode successfully on client-side ✅
// 131/131 tests passing (was 119 in v1.3.1) ✅
// Client and server decoders produce identical results ✅v1.3.1
🔧 Critical Fix: Marker Lines Preservation
- Fixed: Marker lines (e.g., "...... Intro ......", "....ดนตรี....") were being incorrectly filtered out
- Improved: Now includes ALL lines that have timing data in cursor file
- Smart Handling: Stops processing when cursor runs out of timing data
- Result: Complete preservation of songs with intro/solo/outro markers
What was fixed: v1.3.0 introduced marker filtering that removed lines like "...... Intro ......" even when the cursor file had timing data for them. This caused songs like "Move On แบบใด" to be missing marker lines. v1.3.1 removes the filtering and trusts the cursor file - if timing exists, the line is included.
Test results:
// Z2510001: ✅ Has "....ดนตรี...." + complete lyrics
// Z2510006: ✅ Has "...... Intro ......" + complete lyrics
// 119/119 tests passing ✅v1.3.0
🔧 Critical Fix: Beginning Lyrics Preservation
- Fixed: Beginning lyrics were being cut off during EMK to KAR and NCN to KAR conversion
- Improved: Smart detection and skipping of instrumental intro markers (e.g., "....ดนตรี....")
- Added: 6 comprehensive tests to verify beginning lyrics preservation
- Verified: All 119 tests passing, ensuring complete lyric integrity from EMK decode to KAR output
What was fixed: Previously, the conversion process was double-skipping the first 4 lines of lyrics, causing the actual beginning of songs to be missing from KAR files. This version correctly preserves all lyrics from the beginning while intelligently filtering out non-lyrical markers.
Comparison test:
// EMK decoded lyrics vs KAR output: 100% match
// First lyric: "ท่องเที่ยวมาแล้วแทบทั่วเมืองไทย" ✅
// Last lyric: "กับยุพิน ที่เมืองพระรถ..." ✅v1.2.0
- Added Thai encoding tests (6 new tests)
- Verified TIS-620 encoding preservation
- Updated README with encoding clarification
v1.1.1
- Documentation update for Thai encoding in KAR files
- No code changes
v1.0.0
- Initial release
- Full browser and server support
- EMK decoding and NCN to KAR conversion
- Thai language support (TIS-620)
