@karaplay/file-coder 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BROWSER_API.md +318 -0
- package/README.md +216 -0
- package/REFACTORING_SUMMARY.txt +250 -0
- package/WORKFLOW_SUMMARY.txt +78 -0
- package/bin/ncntokar-cli.js +39 -0
- package/dist/client.d.ts +26 -0
- package/dist/client.js +74 -0
- package/dist/emk/client-decoder.d.ts +22 -0
- package/dist/emk/client-decoder.js +133 -0
- package/dist/emk/server-decode.d.ts +21 -0
- package/dist/emk/server-decode.js +123 -0
- package/dist/emk-to-kar.browser.d.ts +51 -0
- package/dist/emk-to-kar.browser.js +139 -0
- package/dist/emk-to-kar.d.ts +53 -0
- package/dist/emk-to-kar.js +210 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +64 -0
- package/dist/kar-reader.browser.d.ts +46 -0
- package/dist/kar-reader.browser.js +209 -0
- package/dist/kar-reader.d.ts +42 -0
- package/dist/kar-reader.js +197 -0
- package/dist/ncntokar.browser.d.ts +99 -0
- package/dist/ncntokar.browser.js +296 -0
- package/dist/ncntokar.d.ts +88 -0
- package/dist/ncntokar.js +340 -0
- package/examples/NextJSComponent.tsx +175 -0
- package/libs/emk/client-decoder.ts +142 -0
- package/libs/emk/server-decode.ts +133 -0
- package/libs/ncntokar.js +256 -0
- package/package.json +79 -0
- package/songs/.gitkeep +3 -0
- package/songs/cur/BPL3457.cur +0 -0
- package/songs/cur/Z2510006.cur +0 -0
- package/songs/cur/Z2510008.cur +0 -0
- package/songs/cur/Z2510136.cur +0 -0
- package/songs/cur/Z2510137.cur +0 -0
- package/songs/cur/Z2510138.cur +0 -0
- package/songs/cur/Z2510139.cur +0 -0
- package/songs/cur/Z2510140.cur +0 -0
- package/songs/cur/Z2510141.cur +0 -0
- package/songs/cur/song.cur +0 -0
- package/songs/emk/Z2510001.emk +0 -0
- package/songs/emk/Z2510002.emk +0 -0
- package/songs/emk/Z2510003.emk +0 -0
- package/songs/emk/Z2510004.emk +0 -0
- package/songs/emk/Z2510005.emk +0 -0
- package/songs/emk/Z2510006.emk +0 -0
- package/songs/kar/bpl3457.kar +0 -0
- package/songs/kar/z2510006.kar +0 -0
- package/songs/kar/z2510008.kar +0 -0
- package/songs/kar/z2510136.kar +0 -0
- package/songs/kar/z2510137.kar +0 -0
- package/songs/kar/z2510138.kar +0 -0
- package/songs/kar/z2510139.kar +0 -0
- package/songs/kar/z2510140.kar +0 -0
- package/songs/kar/z2510141.kar +0 -0
- package/songs/lyr/BPL3457.lyr +57 -0
- package/songs/lyr/Z2510006.lyr +53 -0
- package/songs/lyr/Z2510008.lyr +57 -0
- package/songs/lyr/Z2510136.lyr +54 -0
- package/songs/lyr/Z2510137.lyr +66 -0
- package/songs/lyr/Z2510138.lyr +62 -0
- package/songs/lyr/Z2510139.lyr +60 -0
- package/songs/lyr/Z2510140.lyr +41 -0
- package/songs/lyr/Z2510141.lyr +48 -0
- package/songs/lyr/song.lyr +37 -0
- package/songs/midi/BPL3457.MID +0 -0
- package/songs/midi/Z2510006.mid +0 -0
- package/songs/midi/Z2510008.mid +0 -0
- package/songs/midi/Z2510136.mid +0 -0
- package/songs/midi/Z2510137.mid +0 -0
- package/songs/midi/Z2510138.mid +0 -0
- package/songs/midi/Z2510139.mid +0 -0
- package/songs/midi/Z2510140.mid +0 -0
- package/songs/midi/Z2510141.mid +0 -0
package/BROWSER_API.md
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Browser API Documentation
|
|
2
|
+
|
|
3
|
+
This document describes how to use file-coder in browser and Next.js client-side environments.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install file-coder
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage in Next.js Client Components
|
|
12
|
+
|
|
13
|
+
### Basic Import
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
'use client';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
convertEmkFileToKar,
|
|
20
|
+
convertEmkToKarBrowser,
|
|
21
|
+
type BrowserEmkToKarResult
|
|
22
|
+
} from 'file-coder/client';
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Example 1: Single File Conversion with Auto-Download
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
'use client';
|
|
29
|
+
|
|
30
|
+
import { convertEmkFileToKar } from 'file-coder/client';
|
|
31
|
+
|
|
32
|
+
function MyComponent() {
|
|
33
|
+
const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
34
|
+
const file = e.target.files?.[0];
|
|
35
|
+
if (!file) return;
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// Convert and auto-download
|
|
39
|
+
const result = await convertEmkFileToKar(file, {
|
|
40
|
+
autoDownload: true
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
console.log('Converted:', result.metadata.title);
|
|
44
|
+
console.log('Artist:', result.metadata.artist);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('Conversion failed:', error);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return <input type="file" accept=".emk" onChange={handleFileUpload} />;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Example 2: Buffer-Based Conversion
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
'use client';
|
|
58
|
+
|
|
59
|
+
import { convertEmkToKarBrowser, fileToBuffer } from 'file-coder/client';
|
|
60
|
+
|
|
61
|
+
async function convertFromBuffer(emkFile: File) {
|
|
62
|
+
// Convert File to Buffer
|
|
63
|
+
const emkBuffer = await fileToBuffer(emkFile);
|
|
64
|
+
|
|
65
|
+
// Convert EMK to KAR
|
|
66
|
+
const result = convertEmkToKarBrowser({
|
|
67
|
+
emkBuffer,
|
|
68
|
+
outputFileName: 'output.kar',
|
|
69
|
+
autoDownload: false // We'll handle the buffer ourselves
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Access the KAR buffer
|
|
73
|
+
console.log('KAR buffer size:', result.karBuffer.length);
|
|
74
|
+
console.log('Title:', result.metadata.title);
|
|
75
|
+
|
|
76
|
+
// Manually download if needed
|
|
77
|
+
if (result.success) {
|
|
78
|
+
const { downloadBuffer } = await import('file-coder/client');
|
|
79
|
+
downloadBuffer(result.karBuffer, result.fileName);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Example 3: Batch Conversion
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
'use client';
|
|
90
|
+
|
|
91
|
+
import { convertEmkFilesBatch } from 'file-coder/client';
|
|
92
|
+
|
|
93
|
+
function BatchConverter() {
|
|
94
|
+
const handleBatchUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
95
|
+
const files = Array.from(e.target.files || []);
|
|
96
|
+
if (files.length === 0) return;
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
// Convert multiple files
|
|
100
|
+
const results = await convertEmkFilesBatch(files, {
|
|
101
|
+
autoDownload: true
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const successCount = results.filter(r => r.success).length;
|
|
105
|
+
console.log(`Converted ${successCount}/${files.length} files`);
|
|
106
|
+
|
|
107
|
+
// Check results
|
|
108
|
+
results.forEach(result => {
|
|
109
|
+
if (result.success) {
|
|
110
|
+
console.log(`✓ ${result.fileName}: ${result.metadata.title}`);
|
|
111
|
+
} else {
|
|
112
|
+
console.error(`✗ ${result.fileName}:`, result.warnings);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.error('Batch conversion failed:', error);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<input
|
|
122
|
+
type="file"
|
|
123
|
+
accept=".emk"
|
|
124
|
+
multiple
|
|
125
|
+
onChange={handleBatchUpload}
|
|
126
|
+
/>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## API Reference
|
|
132
|
+
|
|
133
|
+
### Main Functions
|
|
134
|
+
|
|
135
|
+
#### `convertEmkFileToKar(emkFile: File, options?: { autoDownload?: boolean })`
|
|
136
|
+
|
|
137
|
+
Converts a File object (from file input) to KAR format.
|
|
138
|
+
|
|
139
|
+
**Parameters:**
|
|
140
|
+
- `emkFile`: File object from file input
|
|
141
|
+
- `options.autoDownload`: If true, automatically downloads the KAR file (default: true)
|
|
142
|
+
|
|
143
|
+
**Returns:** `Promise<BrowserEmkToKarResult>`
|
|
144
|
+
|
|
145
|
+
#### `convertEmkToKarBrowser(options: BrowserEmkToKarOptions)`
|
|
146
|
+
|
|
147
|
+
Converts an EMK buffer to KAR buffer.
|
|
148
|
+
|
|
149
|
+
**Parameters:**
|
|
150
|
+
```typescript
|
|
151
|
+
interface BrowserEmkToKarOptions {
|
|
152
|
+
emkBuffer: Buffer;
|
|
153
|
+
outputFileName?: string;
|
|
154
|
+
autoDownload?: boolean;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Returns:** `BrowserEmkToKarResult`
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
interface BrowserEmkToKarResult {
|
|
162
|
+
success: boolean;
|
|
163
|
+
karBuffer: Buffer;
|
|
164
|
+
fileName: string;
|
|
165
|
+
intermediateBuffers?: {
|
|
166
|
+
midi: Buffer;
|
|
167
|
+
lyric: Buffer;
|
|
168
|
+
cursor: Buffer;
|
|
169
|
+
};
|
|
170
|
+
metadata: {
|
|
171
|
+
title: string;
|
|
172
|
+
artist: string;
|
|
173
|
+
code?: string;
|
|
174
|
+
};
|
|
175
|
+
warnings: string[];
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### `convertEmkFilesBatch(emkFiles: File[], options?: { autoDownload?: boolean })`
|
|
180
|
+
|
|
181
|
+
Converts multiple EMK files at once.
|
|
182
|
+
|
|
183
|
+
**Parameters:**
|
|
184
|
+
- `emkFiles`: Array of File objects
|
|
185
|
+
- `options.autoDownload`: If true, automatically downloads all KAR files (default: false)
|
|
186
|
+
|
|
187
|
+
**Returns:** `Promise<BrowserEmkToKarResult[]>`
|
|
188
|
+
|
|
189
|
+
### Helper Functions
|
|
190
|
+
|
|
191
|
+
#### `fileToBuffer(file: File): Promise<Buffer>`
|
|
192
|
+
|
|
193
|
+
Converts a File object to a Buffer for use with buffer-based APIs.
|
|
194
|
+
|
|
195
|
+
#### `downloadBuffer(buffer: Buffer, fileName: string, mimeType?: string): void`
|
|
196
|
+
|
|
197
|
+
Triggers a browser download of a buffer.
|
|
198
|
+
|
|
199
|
+
**Parameters:**
|
|
200
|
+
- `buffer`: The data to download
|
|
201
|
+
- `fileName`: Name for the downloaded file
|
|
202
|
+
- `mimeType`: MIME type (default: 'audio/midi')
|
|
203
|
+
|
|
204
|
+
### NCN to KAR (Browser)
|
|
205
|
+
|
|
206
|
+
#### `convertNcnToKarBrowser(options: BrowserConversionOptions)`
|
|
207
|
+
|
|
208
|
+
Converts MIDI, Lyric, and Cursor buffers to a KAR buffer.
|
|
209
|
+
|
|
210
|
+
**Parameters:**
|
|
211
|
+
```typescript
|
|
212
|
+
interface BrowserConversionOptions {
|
|
213
|
+
midiBuffer: Buffer;
|
|
214
|
+
lyricBuffer: Buffer;
|
|
215
|
+
cursorBuffer: Buffer;
|
|
216
|
+
outputFileName?: string;
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Returns:** `BrowserConversionResult`
|
|
221
|
+
|
|
222
|
+
### KAR Reader (Browser)
|
|
223
|
+
|
|
224
|
+
#### `readKarBuffer(buffer: Buffer): KarFileInfo`
|
|
225
|
+
|
|
226
|
+
Reads and parses a KAR file buffer.
|
|
227
|
+
|
|
228
|
+
#### `validateKarBuffer(buffer: Buffer)`
|
|
229
|
+
|
|
230
|
+
Validates a KAR buffer structure.
|
|
231
|
+
|
|
232
|
+
#### `extractLyricsFromKarBuffer(buffer: Buffer): string[]`
|
|
233
|
+
|
|
234
|
+
Extracts lyrics from a KAR buffer.
|
|
235
|
+
|
|
236
|
+
#### `readKarFile(file: File): Promise<KarFileInfo>`
|
|
237
|
+
|
|
238
|
+
Reads a File object as a KAR file.
|
|
239
|
+
|
|
240
|
+
## Complete Example Component
|
|
241
|
+
|
|
242
|
+
See [examples/NextJSComponent.tsx](./examples/NextJSComponent.tsx) for a full-featured Next.js component with:
|
|
243
|
+
- Single file upload and conversion
|
|
244
|
+
- Batch file processing
|
|
245
|
+
- Error handling
|
|
246
|
+
- Loading states
|
|
247
|
+
- Success/error messages
|
|
248
|
+
- Auto-download functionality
|
|
249
|
+
|
|
250
|
+
## Browser Compatibility
|
|
251
|
+
|
|
252
|
+
- ✅ Chrome/Edge (Chromium)
|
|
253
|
+
- ✅ Firefox
|
|
254
|
+
- ✅ Safari
|
|
255
|
+
- ✅ Next.js 13+ (App Router)
|
|
256
|
+
- ✅ React 18+
|
|
257
|
+
|
|
258
|
+
## Features
|
|
259
|
+
|
|
260
|
+
- 🎵 Client-side EMK decoding
|
|
261
|
+
- 🎤 Thai lyrics support (TIS-620 encoding)
|
|
262
|
+
- 📦 No server required - all processing in browser
|
|
263
|
+
- ⚡ Fast conversion
|
|
264
|
+
- 💾 Auto-download support
|
|
265
|
+
- 🔄 Batch processing
|
|
266
|
+
- 📊 Metadata extraction
|
|
267
|
+
- ✅ KAR file validation
|
|
268
|
+
|
|
269
|
+
## Notes
|
|
270
|
+
|
|
271
|
+
- All processing happens in the browser - no files are uploaded to servers
|
|
272
|
+
- Large files may take a few seconds to process
|
|
273
|
+
- The library uses Pako for decompression (browser-compatible alternative to zlib)
|
|
274
|
+
- Supports TIS-620 encoding for proper Thai character handling
|
|
275
|
+
|
|
276
|
+
## TypeScript Support
|
|
277
|
+
|
|
278
|
+
Full TypeScript support with type definitions included:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
import type {
|
|
282
|
+
BrowserEmkToKarOptions,
|
|
283
|
+
BrowserEmkToKarResult,
|
|
284
|
+
BrowserConversionOptions,
|
|
285
|
+
BrowserConversionResult,
|
|
286
|
+
KarFileInfo,
|
|
287
|
+
KarTrack
|
|
288
|
+
} from 'file-coder/client';
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Performance Tips
|
|
292
|
+
|
|
293
|
+
1. **Batch Processing**: Use `convertEmkFilesBatch` for multiple files instead of calling `convertEmkFileToKar` in a loop
|
|
294
|
+
2. **Auto-Download**: Set `autoDownload: false` if you want to process the buffer before downloading
|
|
295
|
+
3. **Web Workers**: For heavy processing, consider running conversions in a Web Worker (not included in library)
|
|
296
|
+
|
|
297
|
+
## Error Handling
|
|
298
|
+
|
|
299
|
+
```tsx
|
|
300
|
+
try {
|
|
301
|
+
const result = await convertEmkFileToKar(file);
|
|
302
|
+
|
|
303
|
+
if (result.success) {
|
|
304
|
+
console.log('Success:', result.metadata.title);
|
|
305
|
+
|
|
306
|
+
if (result.warnings.length > 0) {
|
|
307
|
+
console.warn('Warnings:', result.warnings);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
} catch (error) {
|
|
311
|
+
console.error('Conversion failed:', error.message);
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## License
|
|
316
|
+
|
|
317
|
+
MIT
|
|
318
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# @karaplay/file-coder
|
|
2
|
+
|
|
3
|
+
A comprehensive library for encoding/decoding karaoke files (.emk, .kar, MIDI) with Next.js support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎵 Convert NCN format (.mid + .lyr + .cur) to .kar (MIDI karaoke)
|
|
8
|
+
- 🔓 Decode .emk (Extreme Karaoke) files
|
|
9
|
+
- 📖 Read and validate .kar files
|
|
10
|
+
- ⚡ **NEW**: Complete EMK → KAR workflow (one-step conversion)
|
|
11
|
+
- 🌐 Full TypeScript support
|
|
12
|
+
- ⚛️ Next.js compatible (both client and server side)
|
|
13
|
+
- 🌐 **NEW**: Browser-compatible API for client-side processing
|
|
14
|
+
- 🇹🇭 Thai language support (TIS-620 encoding)
|
|
15
|
+
- ✅ 101+ tests - 100% pass rate (including integration tests with real files)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @karaplay/file-coder
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### Browser/Client-Side (Next.js) 🌐 NEW
|
|
26
|
+
|
|
27
|
+
For client-side processing in Next.js or browser environments:
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
'use client';
|
|
31
|
+
|
|
32
|
+
import { convertEmkFileToKar } from '@karaplay/file-coder/client';
|
|
33
|
+
|
|
34
|
+
function MyComponent() {
|
|
35
|
+
const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
36
|
+
const file = e.target.files?.[0];
|
|
37
|
+
if (!file) return;
|
|
38
|
+
|
|
39
|
+
const result = await convertEmkFileToKar(file, { autoDownload: true });
|
|
40
|
+
console.log('Converted:', result.metadata.title);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return <input type="file" accept=".emk" onChange={handleFileUpload} />;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**📚 [Full Browser API Documentation →](./BROWSER_API.md)**
|
|
48
|
+
|
|
49
|
+
### Server-Side (Node.js)
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
### EMK to KAR Workflow (Complete Pipeline) ⭐ NEW
|
|
54
|
+
|
|
55
|
+
Convert EMK files directly to KAR in one step:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { convertEmkToKar } from '@karaplay/file-coder';
|
|
59
|
+
|
|
60
|
+
const result = convertEmkToKar({
|
|
61
|
+
inputEmk: 'songs/song.emk',
|
|
62
|
+
outputKar: 'output/song.kar'
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
console.log(`Title: ${result.metadata.title}`);
|
|
66
|
+
console.log(`Artist: ${result.metadata.artist}`);
|
|
67
|
+
console.log(`Success: ${result.success}`);
|
|
68
|
+
// Thai text is readable! ✅
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Batch conversion**:
|
|
72
|
+
```typescript
|
|
73
|
+
import { convertEmkToKarBatch } from '@karaplay/file-coder';
|
|
74
|
+
|
|
75
|
+
const results = convertEmkToKarBatch(
|
|
76
|
+
['song1.emk', 'song2.emk', 'song3.emk'],
|
|
77
|
+
'output/kar'
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
See [EMK_TO_KAR_WORKFLOW.md](./EMK_TO_KAR_WORKFLOW.md) for complete documentation.
|
|
82
|
+
|
|
83
|
+
### NCN to KAR Conversion
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { convertNcnToKar } from 'file-coder';
|
|
87
|
+
|
|
88
|
+
const result = convertNcnToKar({
|
|
89
|
+
inputMidi: 'path/to/song.mid',
|
|
90
|
+
inputLyr: 'path/to/song.lyr',
|
|
91
|
+
inputCur: 'path/to/song.cur',
|
|
92
|
+
outputKar: 'path/to/output.kar',
|
|
93
|
+
appendTitles: true
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
console.log(`Converted: ${result.metadata.title} by ${result.metadata.artist}`);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### EMK Decoding (Server-side)
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { decodeEmkServer, parseSongInfoServer } from 'file-coder';
|
|
103
|
+
import * as fs from 'fs';
|
|
104
|
+
|
|
105
|
+
const fileBuffer = fs.readFileSync('path/to/song.emk');
|
|
106
|
+
const decoded = decodeEmkServer(fileBuffer);
|
|
107
|
+
|
|
108
|
+
// Access decoded parts
|
|
109
|
+
const midiData = decoded.midi;
|
|
110
|
+
const lyricData = decoded.lyric;
|
|
111
|
+
const cursorData = decoded.cursor;
|
|
112
|
+
|
|
113
|
+
// Parse song information
|
|
114
|
+
const songInfo = parseSongInfoServer(decoded.songInfo);
|
|
115
|
+
console.log(`Title: ${songInfo.TITLE}`);
|
|
116
|
+
console.log(`Artist: ${songInfo.ARTIST}`);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### EMK Decoding (Client-side/Next.js)
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
'use client';
|
|
123
|
+
|
|
124
|
+
import { decodeEmkClient, parseSongInfoClient } from 'file-coder';
|
|
125
|
+
|
|
126
|
+
function MyComponent() {
|
|
127
|
+
const handleFileUpload = async (file: File) => {
|
|
128
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
129
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
130
|
+
|
|
131
|
+
const decoded = decodeEmkClient(buffer);
|
|
132
|
+
const songInfo = parseSongInfoClient(decoded.songInfo);
|
|
133
|
+
|
|
134
|
+
console.log(`Title: ${songInfo.TITLE}`);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
return <input type="file" onChange={(e) => handleFileUpload(e.target.files[0])} />;
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## API Reference
|
|
142
|
+
|
|
143
|
+
### NCN to KAR Functions
|
|
144
|
+
|
|
145
|
+
- `convertNcnToKar(options)` - Main conversion function
|
|
146
|
+
- `parseLyricFile(filePath)` - Parse .lyr file for metadata
|
|
147
|
+
- `buildKaraokeTrack(metadata, cursorBuffer, ticksPerBeat)` - Build karaoke track with timing
|
|
148
|
+
- `buildMetadataTracks(metadata)` - Build metadata tracks
|
|
149
|
+
- `CursorReader` - Class for reading cursor timing data
|
|
150
|
+
|
|
151
|
+
### EMK to KAR Workflow Functions ⭐ NEW
|
|
152
|
+
|
|
153
|
+
- `convertEmkToKar(options)` - Complete pipeline: EMK → KAR (one step!)
|
|
154
|
+
- `convertEmkToKarBatch(emkFiles, outputDir, options?)` - Batch convert multiple files
|
|
155
|
+
- `validateThaiLyricReadability(lyricBuffer)` - Validate Thai text readability
|
|
156
|
+
|
|
157
|
+
### KAR File Reader Functions
|
|
158
|
+
|
|
159
|
+
- `readKarFile(filePath)` - Read and parse .kar file
|
|
160
|
+
- `validateKarFile(filePath)` - Validate .kar file structure
|
|
161
|
+
- `extractLyricsFromKar(filePath)` - Extract lyrics from .kar file
|
|
162
|
+
|
|
163
|
+
### EMK Decoder Functions
|
|
164
|
+
|
|
165
|
+
#### Server-side
|
|
166
|
+
- `decodeEmkServer(fileBuffer)` - Decode .emk file (Node.js)
|
|
167
|
+
- `parseSongInfoServer(songInfoBuffer)` - Parse song metadata
|
|
168
|
+
- `xorDecryptServer(data)` - XOR decryption utility
|
|
169
|
+
- `looksLikeTextServer(buffer)` - Text detection utility
|
|
170
|
+
|
|
171
|
+
#### Client-side
|
|
172
|
+
- `decodeEmkClient(fileBuffer)` - Decode .emk file (Browser/Next.js)
|
|
173
|
+
- `parseSongInfoClient(songInfoBuffer)` - Parse song metadata
|
|
174
|
+
- `xorDecryptClient(data)` - XOR decryption utility
|
|
175
|
+
- `looksLikeTextClient(buffer)` - Text detection utility
|
|
176
|
+
|
|
177
|
+
## Development
|
|
178
|
+
|
|
179
|
+
### Install Dependencies
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm install
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Build
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npm run build
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Run Tests
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
npm test
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Test Coverage
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
npm run test:coverage
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Requirements
|
|
204
|
+
|
|
205
|
+
- Node.js >= 16
|
|
206
|
+
- TypeScript >= 5.0
|
|
207
|
+
- Next.js >= 13.0 (optional, for client-side features)
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT
|
|
212
|
+
|
|
213
|
+
## Contributing
|
|
214
|
+
|
|
215
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
216
|
+
|