@karaplay/file-coder 1.5.2 → 1.5.3
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/RELEASE_v1.5.3.md +274 -0
- package/SONG_LIST.txt +27 -13
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/ncntokar.d.ts +9 -0
- package/dist/ncntokar.js +69 -1
- package/package.json +1 -1
- package/temp/f0000001_ref.kar +0 -0
- package/temp/f0000001_test.cur +0 -0
- package/temp/f0000001_test.lyr +41 -0
- package/temp/f0000001_test.mid +0 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# Release v1.5.3 - Corrupted MIDI Repair
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-01-13
|
|
4
|
+
**Type:** Bug Fix + New Feature
|
|
5
|
+
|
|
6
|
+
## 🐛 Bug Fix: Corrupted MIDI Track Support
|
|
7
|
+
|
|
8
|
+
### Problem
|
|
9
|
+
|
|
10
|
+
The file `f0000001.emk` (อีกครั้ง - โลโซ/Loso) failed to convert with:
|
|
11
|
+
- **Error:** "Bad MIDI file. Expected 'MTrk', got: 'iF'" ❌
|
|
12
|
+
- **Cause:** MIDI file had garbage bytes (0x6984461d "iF") instead of valid "MTrk" header at track 3
|
|
13
|
+
- **Result:** Conversion failed with undefined error
|
|
14
|
+
|
|
15
|
+
**Root Cause:**
|
|
16
|
+
Some EMK files contain corrupted MIDI data with garbage bytes inserted before valid track headers, causing MIDI parsers to fail.
|
|
17
|
+
|
|
18
|
+
### Solution
|
|
19
|
+
|
|
20
|
+
Added automatic MIDI repair functionality:
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
// New function: repairCorruptedMidi()
|
|
24
|
+
export function repairCorruptedMidi(midiBuffer: Buffer): {
|
|
25
|
+
repaired: Buffer;
|
|
26
|
+
fixed: boolean;
|
|
27
|
+
corrections: number;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**How it works:**
|
|
32
|
+
1. Scans MIDI file for invalid track headers
|
|
33
|
+
2. Detects garbage bytes before "MTrk" chunks
|
|
34
|
+
3. Removes corrupted data
|
|
35
|
+
4. Rebuilds valid MIDI file automatically
|
|
36
|
+
|
|
37
|
+
### Results
|
|
38
|
+
|
|
39
|
+
**Before Fix (v1.5.2):**
|
|
40
|
+
```
|
|
41
|
+
f0000001.emk (อีกครั้ง - โลโซ):
|
|
42
|
+
❌ Error: Bad MIDI file. Expected 'MTrk', got: 'iF'
|
|
43
|
+
❌ Status: Cannot convert
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**After Fix (v1.5.3):**
|
|
47
|
+
```
|
|
48
|
+
f0000001.emk (อีกครั้ง - โลโซ):
|
|
49
|
+
✅ Conversion: SUCCESS!
|
|
50
|
+
✅ Duration: 0:58 (58.96s)
|
|
51
|
+
✅ Tempo: 344 BPM (4x ratio)
|
|
52
|
+
✅ Warning: Fixed 1 corrupted MIDI track(s)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 📊 Impact
|
|
58
|
+
|
|
59
|
+
### Conversion Success Rate Improvement
|
|
60
|
+
|
|
61
|
+
**Before v1.5.3:**
|
|
62
|
+
- Total Files: 11
|
|
63
|
+
- Success: 9 (82%)
|
|
64
|
+
- Failed: 2 (18%)
|
|
65
|
+
|
|
66
|
+
**After v1.5.3:**
|
|
67
|
+
- Total Files: 11
|
|
68
|
+
- Success: **10 (91%)** ✅ +9%
|
|
69
|
+
- Failed: 1 (9%)
|
|
70
|
+
|
|
71
|
+
### Files Status
|
|
72
|
+
|
|
73
|
+
**Fixed:**
|
|
74
|
+
- ✅ `f0000001.emk` (อีกครั้ง - โลโซ) - Now converts successfully!
|
|
75
|
+
|
|
76
|
+
**Still Failed:**
|
|
77
|
+
- ❌ `500006.emk` - Completely corrupted (no zlib blocks), cannot be recovered
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 🔧 Technical Details
|
|
82
|
+
|
|
83
|
+
### Corrupted MIDI Example
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
Offset Chunk ID Status
|
|
87
|
+
------ -------- ------
|
|
88
|
+
14 MTrk ✅ Valid
|
|
89
|
+
59 MTrk ✅ Valid
|
|
90
|
+
1431 iF ❌ CORRUPTED! (should be MTrk)
|
|
91
|
+
1440 MTrk ✅ Valid (found after skipping 9 bytes)
|
|
92
|
+
...
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Repair Process
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// Automatic repair in convertNcnToKar()
|
|
99
|
+
let midiBuffer: Buffer = fs.readFileSync(options.inputMidi);
|
|
100
|
+
const repairResult = repairCorruptedMidi(midiBuffer);
|
|
101
|
+
|
|
102
|
+
if (repairResult.fixed) {
|
|
103
|
+
midiBuffer = repairResult.repaired as Buffer;
|
|
104
|
+
warnings.push(`Fixed ${repairResult.corrections} corrupted MIDI track(s)`);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Detection:**
|
|
109
|
+
- Scans for "MTrk" signature (0x4D54726B)
|
|
110
|
+
- When invalid chunk found, searches next 100 bytes for valid "MTrk"
|
|
111
|
+
- Skips garbage bytes and continues
|
|
112
|
+
|
|
113
|
+
**Safety:**
|
|
114
|
+
- Never modifies header (MThd)
|
|
115
|
+
- Preserves all valid tracks
|
|
116
|
+
- Only removes garbage bytes between tracks
|
|
117
|
+
- Returns original if repair fails
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 📝 Changed Files
|
|
122
|
+
|
|
123
|
+
### Core Library
|
|
124
|
+
|
|
125
|
+
1. **src/ncntokar.ts**
|
|
126
|
+
- Added `repairCorruptedMidi()` function
|
|
127
|
+
- Integrated automatic repair in `convertNcnToKar()`
|
|
128
|
+
- Reports corrupted tracks in warnings
|
|
129
|
+
|
|
130
|
+
2. **src/index.ts**
|
|
131
|
+
- Exported `repairCorruptedMidi` for external use
|
|
132
|
+
|
|
133
|
+
### Documentation
|
|
134
|
+
|
|
135
|
+
3. **SONG_LIST.txt**
|
|
136
|
+
- Added เพลงที่ 10: อีกครั้ง (โลโซ)
|
|
137
|
+
- Updated success rate: 82% → 91%
|
|
138
|
+
- Updated failed files: 2 → 1
|
|
139
|
+
|
|
140
|
+
4. **RELEASE_v1.5.3.md**
|
|
141
|
+
- This file
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 🚀 Migration
|
|
146
|
+
|
|
147
|
+
### From v1.5.2 to v1.5.3
|
|
148
|
+
|
|
149
|
+
**No Breaking Changes!**
|
|
150
|
+
|
|
151
|
+
Simply update:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm install @karaplay/file-coder@1.5.3
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**All existing code continues to work.**
|
|
158
|
+
|
|
159
|
+
### What Changed
|
|
160
|
+
|
|
161
|
+
If you were trying to convert `f0000001.emk`:
|
|
162
|
+
|
|
163
|
+
**Before (v1.5.2):**
|
|
164
|
+
```typescript
|
|
165
|
+
convertEmkToKar({
|
|
166
|
+
inputEmk: 'f0000001.emk',
|
|
167
|
+
outputKar: 'output.kar'
|
|
168
|
+
});
|
|
169
|
+
// ❌ Error: Bad MIDI file
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**After (v1.5.3):**
|
|
173
|
+
```typescript
|
|
174
|
+
convertEmkToKar({
|
|
175
|
+
inputEmk: 'f0000001.emk',
|
|
176
|
+
outputKar: 'output.kar'
|
|
177
|
+
});
|
|
178
|
+
// ✅ Success! (with warning about fixed MIDI track)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🎯 Use Cases
|
|
184
|
+
|
|
185
|
+
### When This Fix Helps
|
|
186
|
+
|
|
187
|
+
✅ **Corrupted Track Headers:**
|
|
188
|
+
- Garbage bytes before MTrk chunks
|
|
189
|
+
- Invalid chunk IDs in MIDI file
|
|
190
|
+
- Malformed track structures
|
|
191
|
+
|
|
192
|
+
✅ **Automatic Recovery:**
|
|
193
|
+
- No manual intervention needed
|
|
194
|
+
- Transparent to the user
|
|
195
|
+
- Warning message in result
|
|
196
|
+
|
|
197
|
+
❌ **When It Doesn't Help:**
|
|
198
|
+
- Completely corrupted files (like 500006.emk)
|
|
199
|
+
- Files with no zlib blocks
|
|
200
|
+
- Files that can't be decoded at all
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 🧪 Testing
|
|
205
|
+
|
|
206
|
+
### Test: f0000001.emk
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { convertEmkToKar, validateKarTempo } from '@karaplay/file-coder';
|
|
210
|
+
|
|
211
|
+
const result = convertEmkToKar({
|
|
212
|
+
inputEmk: 'f0000001.emk',
|
|
213
|
+
outputKar: 'output.kar'
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
console.log('Success:', result.success); // true ✅
|
|
217
|
+
console.log('Title:', result.metadata.title); // "14 อีกครั้ง "
|
|
218
|
+
console.log('Artist:', result.metadata.artist); // "โลโซ (Loso)"
|
|
219
|
+
console.log('Warnings:', result.warnings);
|
|
220
|
+
// ["Fixed 1 corrupted MIDI track(s)", ...]
|
|
221
|
+
|
|
222
|
+
const validation = validateKarTempo(karBuffer);
|
|
223
|
+
console.log('Duration:', validation.durationMinutes); // "0:58"
|
|
224
|
+
console.log('Tempo:', validation.tempo); // 344 BPM
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Manual Repair Test
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { repairCorruptedMidi } from '@karaplay/file-coder';
|
|
231
|
+
|
|
232
|
+
const midiBuffer = fs.readFileSync('corrupted.mid');
|
|
233
|
+
const result = repairCorruptedMidi(midiBuffer);
|
|
234
|
+
|
|
235
|
+
if (result.fixed) {
|
|
236
|
+
console.log('Repaired!');
|
|
237
|
+
console.log('Corrections:', result.corrections);
|
|
238
|
+
fs.writeFileSync('repaired.mid', result.repaired);
|
|
239
|
+
} else {
|
|
240
|
+
console.log('No corruption detected or repair failed');
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 📚 Documentation
|
|
247
|
+
|
|
248
|
+
### Updated Documentation
|
|
249
|
+
|
|
250
|
+
- [SONG_LIST.txt](./SONG_LIST.txt) - Added f0000001.emk info
|
|
251
|
+
- [RELEASE_v1.5.3.md](./RELEASE_v1.5.3.md) - This file
|
|
252
|
+
|
|
253
|
+
### Related Documentation
|
|
254
|
+
|
|
255
|
+
- [EMK_TEST_SUITE_README.md](./EMK_TEST_SUITE_README.md) - Test suite guide
|
|
256
|
+
- [TEMPO_TRICKS_SUMMARY.md](./TEMPO_TRICKS_SUMMARY.md) - Tempo handling
|
|
257
|
+
- [RELEASE_v1.5.2.md](./RELEASE_v1.5.2.md) - High PPQ fix
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## ✨ Summary
|
|
262
|
+
|
|
263
|
+
**Fixed:** f0000001.emk now converts successfully! ✅
|
|
264
|
+
**Added:** Automatic corrupted MIDI repair
|
|
265
|
+
**Improved:** Success rate from 82% to 91%
|
|
266
|
+
**Breaking:** None - fully backward compatible
|
|
267
|
+
|
|
268
|
+
**Remaining Issue:** 500006.emk still cannot be converted (file completely corrupted)
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
**Recommended Action:** Update to v1.5.3 to get automatic MIDI repair for corrupted EMK files.
|
|
273
|
+
|
|
274
|
+
**npm:** https://www.npmjs.com/package/@karaplay/file-coder
|
package/SONG_LIST.txt
CHANGED
|
@@ -159,29 +159,43 @@ Notes: 6,313 notes
|
|
|
159
159
|
ชื่อว่า "failed" เพราะเคยแปลงไม่ได้ก่อน v1.4.7
|
|
160
160
|
ตอนนี้แปลงได้แล้วหลังเพิ่ม ZXIO "zxio" header support
|
|
161
161
|
|
|
162
|
+
--------------------------------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
เพลงที่ 10: อีกครั้ง (14)
|
|
165
|
+
--------------------------------------------------------------------------------
|
|
166
|
+
ศิลปิน: โลโซ (Loso)
|
|
167
|
+
ไฟล์: f0000001.emk
|
|
168
|
+
รูปแบบ: MThd
|
|
169
|
+
Tempo เดิม: 86.00 BPM
|
|
170
|
+
Tempo หลังแปลง: 344.00 BPM
|
|
171
|
+
อัตราเร่ง: 4.00x
|
|
172
|
+
ระยะเวลา: 0:58 นาที (58.96 วินาที)
|
|
173
|
+
Tracks: 10 tracks
|
|
174
|
+
Notes: 2,089 notes
|
|
175
|
+
สถานะ: ✅ แปลงสำเร็จ (เคยแปลงไม่ได้ แต่แก้ไขแล้วใน v1.5.3)
|
|
176
|
+
|
|
177
|
+
หมายเหตุ: ไฟล์นี้มี corrupted MIDI track (garbage bytes)
|
|
178
|
+
แก้ไขด้วย repairCorruptedMidi() function ใน v1.5.3
|
|
179
|
+
MIDI track ถูกซ่อมแซมอัตโนมัติก่อนแปลง
|
|
180
|
+
|
|
162
181
|
================================================================================
|
|
163
|
-
ไฟล์ที่แปลงไม่ได้ (
|
|
182
|
+
ไฟล์ที่แปลงไม่ได้ (1 ไฟล์)
|
|
164
183
|
================================================================================
|
|
165
184
|
|
|
166
185
|
1. 500006.emk
|
|
167
|
-
สถานะ:
|
|
168
|
-
ข้อผิดพลาด:
|
|
169
|
-
สาเหตุ:
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
ชื่อเพลง: อีกครั้ง
|
|
173
|
-
ศิลปิน: โลโซ (Loso)
|
|
174
|
-
สถานะ: ❌ แปลงไม่ได้
|
|
175
|
-
ข้อผิดพลาด: undefined
|
|
176
|
-
สาเหตุ: decode ได้บางส่วน (ชื่อเพลง/ศิลปิน) แต่สร้าง KAR ไม่ได้
|
|
186
|
+
สถานะ: ❌ แปลงไม่ได้
|
|
187
|
+
ข้อผิดพลาด: MIDI data block not found in EMK file
|
|
188
|
+
สาเหตุ: ไฟล์เสียหายอย่างสมบูรณ์ - ไม่มี zlib compressed blocks
|
|
189
|
+
การแก้ไข: ไม่สามารถกู้คืนได้ เนื่องจากไฟล์มีโครงสร้างผิดพลาด
|
|
190
|
+
หมายเหตุ: อาจต้องหาไฟล์ต้นฉบับใหม่
|
|
177
191
|
|
|
178
192
|
================================================================================
|
|
179
193
|
สถิติโดยรวม
|
|
180
194
|
================================================================================
|
|
181
195
|
|
|
182
196
|
จำนวนไฟล์ทั้งหมด: 11 ไฟล์
|
|
183
|
-
แปลงสำเร็จ:
|
|
184
|
-
แปลงไม่ได้:
|
|
197
|
+
แปลงสำเร็จ: 10 ไฟล์ (91%)
|
|
198
|
+
แปลงไม่ได้: 1 ไฟล์ (9%)
|
|
185
199
|
|
|
186
200
|
การกระจายตามรูปแบบ:
|
|
187
201
|
- ZXIO: 3 ไฟล์ (27%) - ratio 1.24x
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* file-coder - A comprehensive library for encoding/decoding karaoke files
|
|
3
3
|
* Supports .emk (Extreme Karaoke), .kar (MIDI karaoke), and NCN format conversions
|
|
4
4
|
*/
|
|
5
|
-
export { convertNcnToKar, convertWithDefaults, parseLyricFile, buildKaraokeTrack, buildMetadataTracks, readFileTextTIS620, splitLinesKeepEndings, trimLineEndings, metaEvent, endOfTrack, ensureReadableFile, ensureOutputDoesNotExist, CursorReader, type ConversionOptions, type SongMetadata } from './ncntokar';
|
|
5
|
+
export { convertNcnToKar, convertWithDefaults, parseLyricFile, buildKaraokeTrack, buildMetadataTracks, readFileTextTIS620, splitLinesKeepEndings, trimLineEndings, metaEvent, endOfTrack, ensureReadableFile, ensureOutputDoesNotExist, CursorReader, repairCorruptedMidi, type ConversionOptions, type SongMetadata } from './ncntokar';
|
|
6
6
|
export { readKarFile, validateKarFile, extractLyricsFromKar, type KarFileInfo, type KarTrack } from './kar-reader';
|
|
7
7
|
export { convertEmkToKar, convertEmkToKarBatch, validateThaiLyricReadability, type EmkToKarOptions, type EmkToKarResult } from './emk-to-kar';
|
|
8
8
|
export { decodeEmk as decodeEmkServer, parseSongInfo as parseSongInfoServer, xorDecrypt as xorDecryptServer, looksLikeText as looksLikeTextServer, type DecodedEmkParts as DecodedEmkPartsServer } from './emk/server-decode';
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Supports .emk (Extreme Karaoke), .kar (MIDI karaoke), and NCN format conversions
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.compareEmkKarTempo = exports.validateKarTempo = exports.readKarFileFromBrowser = exports.extractLyricsFromKarBuffer = exports.validateKarBuffer = exports.readKarBuffer = exports.validateThaiLyricReadabilityBrowser = exports.convertEmkFilesBatch = exports.convertEmkFileToKar = exports.convertEmkToKarBrowser = exports.downloadBuffer = exports.fileToBuffer = exports.buildMetadataTracksBrowser = exports.buildKaraokeTrackBrowser = exports.parseLyricBuffer = exports.convertNcnToKarBrowser = exports.looksLikeTextClient = exports.xorDecryptClient = exports.parseSongInfoClient = exports.decodeEmkClient = exports.looksLikeTextServer = exports.xorDecryptServer = exports.parseSongInfoServer = exports.decodeEmkServer = exports.validateThaiLyricReadability = exports.convertEmkToKarBatch = exports.convertEmkToKar = exports.extractLyricsFromKar = exports.validateKarFile = exports.readKarFile = exports.CursorReader = exports.ensureOutputDoesNotExist = exports.ensureReadableFile = exports.endOfTrack = exports.metaEvent = exports.trimLineEndings = exports.splitLinesKeepEndings = exports.readFileTextTIS620 = exports.buildMetadataTracks = exports.buildKaraokeTrack = exports.parseLyricFile = exports.convertWithDefaults = exports.convertNcnToKar = void 0;
|
|
7
|
+
exports.compareEmkKarTempo = exports.validateKarTempo = exports.readKarFileFromBrowser = exports.extractLyricsFromKarBuffer = exports.validateKarBuffer = exports.readKarBuffer = exports.validateThaiLyricReadabilityBrowser = exports.convertEmkFilesBatch = exports.convertEmkFileToKar = exports.convertEmkToKarBrowser = exports.downloadBuffer = exports.fileToBuffer = exports.buildMetadataTracksBrowser = exports.buildKaraokeTrackBrowser = exports.parseLyricBuffer = exports.convertNcnToKarBrowser = exports.looksLikeTextClient = exports.xorDecryptClient = exports.parseSongInfoClient = exports.decodeEmkClient = exports.looksLikeTextServer = exports.xorDecryptServer = exports.parseSongInfoServer = exports.decodeEmkServer = exports.validateThaiLyricReadability = exports.convertEmkToKarBatch = exports.convertEmkToKar = exports.extractLyricsFromKar = exports.validateKarFile = exports.readKarFile = exports.repairCorruptedMidi = exports.CursorReader = exports.ensureOutputDoesNotExist = exports.ensureReadableFile = exports.endOfTrack = exports.metaEvent = exports.trimLineEndings = exports.splitLinesKeepEndings = exports.readFileTextTIS620 = exports.buildMetadataTracks = exports.buildKaraokeTrack = exports.parseLyricFile = exports.convertWithDefaults = exports.convertNcnToKar = void 0;
|
|
8
8
|
// NCN to KAR converter exports
|
|
9
9
|
var ncntokar_1 = require("./ncntokar");
|
|
10
10
|
Object.defineProperty(exports, "convertNcnToKar", { enumerable: true, get: function () { return ncntokar_1.convertNcnToKar; } });
|
|
@@ -20,6 +20,7 @@ Object.defineProperty(exports, "endOfTrack", { enumerable: true, get: function (
|
|
|
20
20
|
Object.defineProperty(exports, "ensureReadableFile", { enumerable: true, get: function () { return ncntokar_1.ensureReadableFile; } });
|
|
21
21
|
Object.defineProperty(exports, "ensureOutputDoesNotExist", { enumerable: true, get: function () { return ncntokar_1.ensureOutputDoesNotExist; } });
|
|
22
22
|
Object.defineProperty(exports, "CursorReader", { enumerable: true, get: function () { return ncntokar_1.CursorReader; } });
|
|
23
|
+
Object.defineProperty(exports, "repairCorruptedMidi", { enumerable: true, get: function () { return ncntokar_1.repairCorruptedMidi; } });
|
|
23
24
|
// KAR file reader exports
|
|
24
25
|
var kar_reader_1 = require("./kar-reader");
|
|
25
26
|
Object.defineProperty(exports, "readKarFile", { enumerable: true, get: function () { return kar_reader_1.readKarFile; } });
|
package/dist/ncntokar.d.ts
CHANGED
|
@@ -61,6 +61,15 @@ export declare function ensureOutputDoesNotExist(filePath: string, createDir?: b
|
|
|
61
61
|
* Parses lyric file and extracts metadata (title, artist, lyrics)
|
|
62
62
|
*/
|
|
63
63
|
export declare function parseLyricFile(lyricFilePath: string): SongMetadata;
|
|
64
|
+
/**
|
|
65
|
+
* Repairs corrupted MIDI files by removing garbage bytes before MTrk chunks
|
|
66
|
+
* Some EMK files have corrupted MIDI with invalid bytes before track headers
|
|
67
|
+
*/
|
|
68
|
+
export declare function repairCorruptedMidi(midiBuffer: Buffer): {
|
|
69
|
+
repaired: Buffer;
|
|
70
|
+
fixed: boolean;
|
|
71
|
+
corrections: number;
|
|
72
|
+
};
|
|
64
73
|
/**
|
|
65
74
|
* Builds karaoke track with timing information
|
|
66
75
|
*/
|
package/dist/ncntokar.js
CHANGED
|
@@ -50,6 +50,7 @@ exports.endOfTrack = endOfTrack;
|
|
|
50
50
|
exports.ensureReadableFile = ensureReadableFile;
|
|
51
51
|
exports.ensureOutputDoesNotExist = ensureOutputDoesNotExist;
|
|
52
52
|
exports.parseLyricFile = parseLyricFile;
|
|
53
|
+
exports.repairCorruptedMidi = repairCorruptedMidi;
|
|
53
54
|
exports.buildKaraokeTrack = buildKaraokeTrack;
|
|
54
55
|
exports.buildMetadataTracks = buildMetadataTracks;
|
|
55
56
|
exports.fixEmkMidiTempo = fixEmkMidiTempo;
|
|
@@ -197,6 +198,66 @@ function parseLyricFile(lyricFilePath) {
|
|
|
197
198
|
lines: lyricLines
|
|
198
199
|
};
|
|
199
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* Repairs corrupted MIDI files by removing garbage bytes before MTrk chunks
|
|
203
|
+
* Some EMK files have corrupted MIDI with invalid bytes before track headers
|
|
204
|
+
*/
|
|
205
|
+
function repairCorruptedMidi(midiBuffer) {
|
|
206
|
+
try {
|
|
207
|
+
// Check if file starts with MThd
|
|
208
|
+
if (midiBuffer.slice(0, 4).toString('ascii') !== 'MThd') {
|
|
209
|
+
return { repaired: midiBuffer, fixed: false, corrections: 0 };
|
|
210
|
+
}
|
|
211
|
+
let corrections = 0;
|
|
212
|
+
const chunks = [];
|
|
213
|
+
// Add header (first 14 bytes: MThd + length(4) + data(6))
|
|
214
|
+
const headerLength = midiBuffer.readUInt32BE(4);
|
|
215
|
+
chunks.push(midiBuffer.slice(0, 14 + headerLength - 6));
|
|
216
|
+
let offset = 14;
|
|
217
|
+
// Scan and repair tracks
|
|
218
|
+
while (offset < midiBuffer.length - 8) {
|
|
219
|
+
const chunkId = midiBuffer.slice(offset, offset + 4).toString('ascii');
|
|
220
|
+
if (chunkId === 'MTrk') {
|
|
221
|
+
// Valid track, copy it
|
|
222
|
+
const chunkLength = midiBuffer.readUInt32BE(offset + 4);
|
|
223
|
+
const trackEnd = offset + 8 + chunkLength;
|
|
224
|
+
if (trackEnd <= midiBuffer.length) {
|
|
225
|
+
chunks.push(midiBuffer.slice(offset, trackEnd));
|
|
226
|
+
offset = trackEnd;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// Track length exceeds file, stop here
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// Invalid chunk, try to find next MTrk
|
|
235
|
+
let found = false;
|
|
236
|
+
for (let i = offset + 1; i < Math.min(offset + 100, midiBuffer.length - 4); i++) {
|
|
237
|
+
if (midiBuffer.slice(i, i + 4).toString('ascii') === 'MTrk') {
|
|
238
|
+
corrections++;
|
|
239
|
+
offset = i;
|
|
240
|
+
found = true;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (!found) {
|
|
245
|
+
// No more valid tracks found
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (corrections > 0) {
|
|
251
|
+
const repaired = Buffer.concat(chunks);
|
|
252
|
+
return { repaired, fixed: true, corrections };
|
|
253
|
+
}
|
|
254
|
+
return { repaired: midiBuffer, fixed: false, corrections: 0 };
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
// If repair fails, return original
|
|
258
|
+
return { repaired: midiBuffer, fixed: false, corrections: 0 };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
200
261
|
/**
|
|
201
262
|
* Builds karaoke track with timing information
|
|
202
263
|
*/
|
|
@@ -378,8 +439,15 @@ function convertNcnToKar(options) {
|
|
|
378
439
|
ensureReadableFile(options.inputLyr);
|
|
379
440
|
ensureReadableFile(options.inputCur);
|
|
380
441
|
ensureOutputDoesNotExist(options.outputKar);
|
|
442
|
+
// Read and repair MIDI if needed
|
|
443
|
+
let midiBuffer = fs.readFileSync(options.inputMidi);
|
|
444
|
+
const repairResult = repairCorruptedMidi(midiBuffer);
|
|
445
|
+
if (repairResult.fixed) {
|
|
446
|
+
midiBuffer = repairResult.repaired;
|
|
447
|
+
warnings.push(`Fixed ${repairResult.corrections} corrupted MIDI track(s)`);
|
|
448
|
+
}
|
|
381
449
|
// Parse MIDI
|
|
382
|
-
const midi = (0, midi_file_1.parseMidi)(
|
|
450
|
+
const midi = (0, midi_file_1.parseMidi)(midiBuffer);
|
|
383
451
|
const ticksPerBeat = midi.header && midi.header.ticksPerBeat;
|
|
384
452
|
if (!ticksPerBeat) {
|
|
385
453
|
throw new Error("Only ticks-per-beat MIDI timing is supported (SMPTE timing not supported).");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karaplay/file-coder",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.3",
|
|
4
4
|
"description": "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.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
14 �ա����
|
|
2
|
+
��� (Loso)
|
|
3
|
+
A
|
|
4
|
+
|
|
5
|
+
ʹ������ŧ���� �Դ���
|
|
6
|
+
04-0595192
|
|
7
|
+
����� ..
|
|
8
|
+
�����á����������Сѹ�ѹ���
|
|
9
|
+
���������ѹ���ѹ�����
|
|
10
|
+
����ͩѹ�ͧ�� �ͻ���ҹ��µҵ�͵�
|
|
11
|
+
�ҡ���������������� �ҡ���ҷ��������ѹ
|
|
12
|
+
�Ѻ���������ҧ㨩ѹ��ҷ�
|
|
13
|
+
�ͷ����ѹ����֡����� 14
|
|
14
|
+
����ѹ��Ό���á
|
|
15
|
+
�֡� ��ҧ��ѹ�����ѹ����š�
|
|
16
|
+
���������ѹ���� 14 �ա����
|
|
17
|
+
������Ẻ����ѹ�����ѡ�ѡ
|
|
18
|
+
���դ��ѡ��ⴹ���ѡ͡
|
|
19
|
+
�纻Ǵ᷺��·���ҧ��ѧ��ӿ�������
|
|
20
|
+
�ҡ���������������� �ҡ���ҷ��������ѹ
|
|
21
|
+
�Ѻ���������ҧ㨩ѹ��ҷ�
|
|
22
|
+
�ͷ����ѹ����֡����� 14
|
|
23
|
+
����ѹ��Ό���á
|
|
24
|
+
�֡� ��ҧ��ѹ�����ѹ����š�
|
|
25
|
+
���������ѹ���� 14 �ա����
|
|
26
|
+
�����..
|
|
27
|
+
�ҡ���������������� �ҡ���ҷ��������ѹ
|
|
28
|
+
�Ѻ���������ҧ㨩ѹ��ҷ�
|
|
29
|
+
�ͷ����ѹ����֡����� 14
|
|
30
|
+
����ѹ��Ό���á
|
|
31
|
+
�֡� ��ҧ��ѹ�����ѹ����š�
|
|
32
|
+
���������ѹ���� 14 �ա����
|
|
33
|
+
�ͷ����ѹ����֡����� 14
|
|
34
|
+
����ѹ��Ό���á
|
|
35
|
+
�֡� ��ҧ��ѹ�����ѹ����š�
|
|
36
|
+
���������ѹ���� 14 �ա����
|
|
37
|
+
���������ѹ���� 14 �ա����
|
|
38
|
+
���������ѹ���� 14 �ա����
|
|
39
|
+
..��¹�Ӵ����..
|
|
40
|
+
0
|
|
41
|
+
|
|
Binary file
|