@karaplay/file-coder 1.5.0 → 1.5.2

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/README.md CHANGED
@@ -14,6 +14,8 @@ A comprehensive library for encoding/decoding karaoke files (.emk, .kar, MIDI) w
14
14
  - ⚛️ Next.js compatible (both client and server side)
15
15
  - 🌐 **NEW**: Browser-compatible API for client-side processing
16
16
  - 🇹🇭 Thai language support (TIS-620 encoding)
17
+ - 🎯 **v1.5.0**: Accurate tempo handling for ZXIO format (1.24x ratio)
18
+ - ⏱️ **NEW**: Tempo validation and duration accuracy
17
19
  - ✅ **FIXED v1.3.2**: Client-side EMK decoder now works correctly!
18
20
  - ✅ 131 tests - 100% pass rate (including integration tests with real files)
19
21
 
@@ -83,6 +85,94 @@ const results = convertEmkToKarBatch(
83
85
 
84
86
  See [EMK_TO_KAR_WORKFLOW.md](./EMK_TO_KAR_WORKFLOW.md) for complete documentation.
85
87
 
88
+ ---
89
+
90
+ ## ⏱️ Tempo Handling & Duration Accuracy
91
+
92
+ ### Understanding EMK Tempo Conversion
93
+
94
+ EMK files use non-standard MIDI timing that requires tempo adjustment during conversion. This library **automatically** handles tempo correction based on the EMK format:
95
+
96
+ #### ZXIO Format (v1.5.0+)
97
+ ```
98
+ Original EMK: 64 BPM → Converted KAR: 79 BPM
99
+ Tempo Ratio: 1.24x (ticksPerBeat / 77.42)
100
+ Duration: 4:43 ✅ Accurate!
101
+ ```
102
+
103
+ #### MThd Format
104
+ ```
105
+ Tempo Ratio: 4x, 8x, or 20x (auto-detected)
106
+ ```
107
+
108
+ ### Validating Conversion Accuracy
109
+
110
+ Use `@tonejs/midi` to verify tempo and duration:
111
+
112
+ ```typescript
113
+ import { Midi } from '@tonejs/midi';
114
+ import { convertEmkToKar } from '@karaplay/file-coder';
115
+ import * as fs from 'fs';
116
+
117
+ // Convert EMK to KAR
118
+ const result = convertEmkToKar({
119
+ inputEmk: 'song.emk',
120
+ outputKar: 'song.kar'
121
+ });
122
+
123
+ // Validate with Tone.js
124
+ const karBuffer = fs.readFileSync('song.kar');
125
+ const midi = new Midi(karBuffer);
126
+
127
+ console.log('✅ Validation Results:');
128
+ console.log(` Tempo: ${midi.header.tempos[0].bpm.toFixed(2)} BPM`);
129
+ console.log(` Duration: ${(midi.duration / 60).toFixed(2)} minutes`);
130
+ console.log(` PPQ: ${midi.header.ppq}`);
131
+ console.log(` Tracks: ${midi.tracks.length}`);
132
+ ```
133
+
134
+ ### 🔧 Troubleshooting Tempo Issues
135
+
136
+ **Problem:** Converted KAR plays too fast or too slow
137
+ **Solution:** The library automatically applies correct tempo ratios:
138
+
139
+ | Format | Original BPM | Ratio | Converted BPM | Status |
140
+ |--------|--------------|-------|---------------|--------|
141
+ | ZXIO | 64 BPM | 1.24x | 79 BPM | ✅ v1.5.0+ |
142
+ | MThd | 160 BPM | 4x | 640 BPM | ✅ Auto |
143
+ | MThd | 142 BPM | 8x | 1136 BPM | ✅ Auto |
144
+
145
+ **Important Notes:**
146
+ 1. ✅ **Tempo is automatically corrected** - no manual adjustment needed
147
+ 2. ✅ **Use @tonejs/midi for accurate duration** - it handles tempo events correctly
148
+ 3. ⚠️ **Don't use karaoke-player's getTickResolution()** - it can give incorrect timing
149
+ 4. ✅ **Duration decrease is normal** - faster tempo = shorter playback time
150
+
151
+ ### Best Practices for MIDI Playback
152
+
153
+ When implementing a player for converted KAR files:
154
+
155
+ ```typescript
156
+ import { Midi } from '@tonejs/midi';
157
+
158
+ // ✅ CORRECT: Use Tone.js for timing
159
+ const midi = new Midi(karBuffer);
160
+ const duration = midi.duration; // Accurate!
161
+
162
+ midi.tracks.forEach(track => {
163
+ track.notes.forEach(note => {
164
+ const time = note.time; // ✅ Correct time in seconds
165
+ const noteNum = note.midi; // MIDI note number
166
+ const velocity = note.velocity;
167
+ });
168
+ });
169
+
170
+ // ❌ INCORRECT: Don't manually calculate from ticks
171
+ // const time = ticks * tickResolution; // May be wrong!
172
+ ```
173
+
174
+ ---
175
+
86
176
  ### NCN to KAR Conversion
87
177
 
88
178
  ```typescript
@@ -0,0 +1,190 @@
1
+ # Release v1.5.1 - Tempo Validation & Documentation
2
+
3
+ **Date:** 2026-01-13
4
+
5
+ ## 🎯 New Features: Tempo Validation Utilities
6
+
7
+ ### Added Validation Functions
8
+
9
+ This release adds comprehensive tempo and duration validation utilities to ensure conversion accuracy.
10
+
11
+ #### 1. **`validateKarTempo()`** - Validate KAR File Accuracy
12
+
13
+ ```typescript
14
+ import { validateKarTempo } from '@karaplay/file-coder';
15
+ import * as fs from 'fs';
16
+
17
+ const karBuffer = fs.readFileSync('song.kar');
18
+ const validation = validateKarTempo(karBuffer);
19
+
20
+ console.log(`Valid: ${validation.valid}`);
21
+ console.log(`Tempo: ${validation.tempo} BPM`);
22
+ console.log(`Duration: ${validation.durationMinutes}`);
23
+ console.log(`Warnings: ${validation.warnings.length}`);
24
+ ```
25
+
26
+ **Returns:**
27
+ - `valid`: boolean - Overall validation status
28
+ - `tempo`: number - Tempo in BPM
29
+ - `duration`: number - Duration in seconds
30
+ - `durationMinutes`: string - Formatted as "M:SS"
31
+ - `ppq`: number - Ticks per beat
32
+ - `trackCount`: number - Number of tracks
33
+ - `noteCount`: number - Total notes
34
+ - `format`: number - MIDI format (0, 1, or 2)
35
+ - `warnings`: string[] - Non-critical issues
36
+ - `errors`: string[] - Critical issues
37
+
38
+ #### 2. **`compareEmkKarTempo()`** - Compare EMK vs KAR
39
+
40
+ ```typescript
41
+ import { compareEmkKarTempo } from '@karaplay/file-coder';
42
+
43
+ const emkBuffer = fs.readFileSync('song.emk');
44
+ const karBuffer = fs.readFileSync('song.kar');
45
+
46
+ const comparison = compareEmkKarTempo(emkBuffer, karBuffer);
47
+
48
+ console.log(`Format: ${comparison.format}`); // "ZXIO" or "MThd"
49
+ console.log(`Tempo Ratio: ${comparison.tempoRatio}x`); // 1.24x for ZXIO
50
+ console.log(`Expected: ${comparison.expectedRatio}x`); // 1.24x
51
+ console.log(`Match: ${comparison.ratioMatch}`); // true
52
+ ```
53
+
54
+ **Returns:**
55
+ - `emkTempo`: number - Original EMK tempo
56
+ - `karTempo`: number - Converted KAR tempo
57
+ - `tempoRatio`: number - Actual ratio applied
58
+ - `emkDuration`: number - EMK duration
59
+ - `karDuration`: number - KAR duration
60
+ - `durationRatio`: number - Duration change
61
+ - `format`: string - "ZXIO" or "MThd"
62
+ - `expectedRatio`: number - Expected ratio for format
63
+ - `ratioMatch`: boolean - Whether ratio is correct
64
+
65
+ ## 📚 Enhanced Documentation
66
+
67
+ ### New README Section: "Tempo Handling & Duration Accuracy"
68
+
69
+ Added comprehensive guide covering:
70
+
71
+ 1. **Understanding EMK Tempo Conversion**
72
+ - ZXIO format: 1.24x ratio
73
+ - MThd format: 4x, 8x, or 20x (auto-detected)
74
+
75
+ 2. **Validating Conversion Accuracy**
76
+ - Using @tonejs/midi for verification
77
+ - Duration and tempo checks
78
+
79
+ 3. **Troubleshooting Tempo Issues**
80
+ - Common problems and solutions
81
+ - Format-specific ratios
82
+
83
+ 4. **Best Practices for MIDI Playback**
84
+ - ✅ Use Tone.js for timing (accurate!)
85
+ - ❌ Don't use karaoke-player's getTickResolution() (can be wrong!)
86
+
87
+ ### Example Usage
88
+
89
+ ```typescript
90
+ import { Midi } from '@tonejs/midi';
91
+ import { convertEmkToKar, validateKarTempo } from '@karaplay/file-coder';
92
+
93
+ // Convert
94
+ const result = convertEmkToKar({
95
+ inputEmk: 'song.emk',
96
+ outputKar: 'song.kar'
97
+ });
98
+
99
+ // Validate
100
+ const karBuffer = fs.readFileSync('song.kar');
101
+ const midi = new Midi(karBuffer);
102
+
103
+ console.log(`✅ Tempo: ${midi.header.tempos[0].bpm.toFixed(2)} BPM`);
104
+ console.log(`✅ Duration: ${(midi.duration / 60).toFixed(2)} minutes`);
105
+ ```
106
+
107
+ ## 🔧 Technical Details
108
+
109
+ ### Why Use @tonejs/midi?
110
+
111
+ **Problem:** `karaoke-player`'s `getTickResolution()` can calculate incorrect timing:
112
+ ```
113
+ karaoke-player: 5,208 ms/tick ❌ (660x too high!)
114
+ Tone.js: 7.87 ms/tick ✅ (correct!)
115
+ ```
116
+
117
+ **Solution:** Always use `@tonejs/midi` for:
118
+ - Accurate tempo event handling
119
+ - Correct duration calculations
120
+ - Reliable timing information
121
+
122
+ ### Tempo Ratios
123
+
124
+ | Format | Original BPM | Ratio | Converted BPM | Duration Example |
125
+ |--------|--------------|-------|---------------|------------------|
126
+ | ZXIO | 64 BPM | 1.24x | 79 BPM | 4:43 ✅ |
127
+ | MThd | 160 BPM | 4x | 640 BPM | Auto ✅ |
128
+ | MThd | 142 BPM | 8x | 1136 BPM | Auto ✅ |
129
+
130
+ ## ✅ Testing
131
+
132
+ **Test Results:**
133
+ ```
134
+ Test 1: validateKarTempo()
135
+ ✅ Valid: true
136
+ ✅ Tempo: 87.00 BPM
137
+ ✅ Duration: 4:16
138
+
139
+ Test 2: compareEmkKarTempo() - ZXIO
140
+ ✅ Format: ZXIO
141
+ ✅ Tempo: 64 → 79 BPM (1.24x)
142
+ ✅ Expected: 1.24x, Match: YES ✅
143
+
144
+ Test 3: Duration Accuracy
145
+ ✅ Expected: 283s (4:43)
146
+ ✅ Actual: 283.5s (4:43)
147
+ ✅ Difference: 0.5s - PASS
148
+ ```
149
+
150
+ ## 📊 What Changed
151
+
152
+ ### New Files
153
+ - `src/kar-validator.ts` - Validation utilities
154
+ - `tests/kar-validator.test.ts` - Test suite
155
+ - `RELEASE_v1.5.1.md` - This file
156
+
157
+ ### Updated Files
158
+ - `README.md` - Added "Tempo Handling & Duration Accuracy" section
159
+ - `src/index.ts` - Exported validator functions
160
+ - `package.json` - Version bump to 1.5.1
161
+
162
+ ## 🚀 Migration from v1.5.0
163
+
164
+ No breaking changes! Simply update:
165
+
166
+ ```bash
167
+ npm install @karaplay/file-coder@1.5.1
168
+ ```
169
+
170
+ New validator functions are optional - existing code continues to work.
171
+
172
+ ## 💡 Key Takeaways
173
+
174
+ 1. ✅ **Automatic tempo correction** - no manual adjustment needed
175
+ 2. ✅ **Use @tonejs/midi** for accurate timing
176
+ 3. ✅ **New validation utilities** for quality assurance
177
+ 4. ✅ **Comprehensive documentation** for tempo handling
178
+ 5. ⚠️ **Duration decrease is normal** - faster tempo = shorter playback
179
+
180
+ ## 📖 Documentation
181
+
182
+ - [README.md](./README.md) - Main documentation
183
+ - [EMK_TO_KAR_WORKFLOW.md](./EMK_TO_KAR_WORKFLOW.md) - Conversion workflow
184
+ - [RELEASE_v1.5.0.md](./RELEASE_v1.5.0.md) - Previous release (ZXIO fix)
185
+
186
+ ---
187
+
188
+ **Status:** ✅ Ready for Production
189
+
190
+ **Recommended Action:** Update to get validation utilities and improved documentation
@@ -0,0 +1,238 @@
1
+ # Release v1.5.2 - High PPQ File Support
2
+
3
+ **Date:** 2026-01-13
4
+ **Type:** Bug Fix
5
+
6
+ ## 🐛 Bug Fix: Incorrect Tempo Ratio for High PPQ Files
7
+
8
+ ### Problem
9
+
10
+ The file `Z2510006.emk` (Move On แบบใด - โจอี้ ภูวศิษฐ์) was incorrectly converted with:
11
+ - **Tempo Ratio:** 20x ❌ (should be 1x)
12
+ - **Duration:** 0:12 (12.83 seconds) ❌ (should be 4:16)
13
+ - **Tempo:** 87 BPM → 1,740 BPM ❌ (should stay 87 BPM)
14
+
15
+ **Root Cause:**
16
+ The system calculated tempo ratio as `PPQ / 24`:
17
+ - Z2510006 has `PPQ = 480`
18
+ - Calculated ratio: `480 / 24 = 20x` ❌
19
+ - But this file already has correct tempo and doesn't need adjustment!
20
+
21
+ ### Solution
22
+
23
+ Added special handling for **high PPQ files** (PPQ >= 480):
24
+
25
+ ```typescript
26
+ if (isZxioFormat) {
27
+ ratio = ticksPerBeat / 77.42; // ZXIO: 1.24x
28
+ } else if (ticksPerBeat >= 480) {
29
+ ratio = 1.0; // High PPQ: No adjustment needed ✅
30
+ } else {
31
+ ratio = ticksPerBeat / 24; // Standard MThd: 4x, 8x, etc.
32
+ }
33
+ ```
34
+
35
+ ### Results
36
+
37
+ **Before Fix:**
38
+ ```
39
+ Move On แบบใด (Z2510006.emk):
40
+ - Tempo: 87 → 1,740 BPM (20x) ❌
41
+ - Duration: 0:12 ❌
42
+ - Status: Incorrect
43
+ ```
44
+
45
+ **After Fix:**
46
+ ```
47
+ Move On แบบใด (Z2510006.emk):
48
+ - Tempo: 87 → 87 BPM (1x) ✅
49
+ - Duration: 4:16 ✅
50
+ - Matches reference KAR: 100% ✅
51
+ ```
52
+
53
+ ---
54
+
55
+ ## 📊 Impact
56
+
57
+ ### Files Affected
58
+
59
+ **Z2510006.emk only:**
60
+ - This is the only file in our test set with PPQ >= 480
61
+ - Other files (PPQ < 480) are not affected
62
+ - All 9/9 tests pass ✅
63
+
64
+ ### Tempo Ratio Distribution (Updated)
65
+
66
+ | Ratio | Format | Count | Files |
67
+ |-------|--------|-------|-------|
68
+ | 1.00x | MThd (High PPQ) | 1 | Z2510006 ✅ **NEW** |
69
+ | 1.24x | ZXIO | 3 | 001, 001_original, failed01 |
70
+ | 4.00x | MThd | 4 | Z2510001, Z2510002, Z2510004, Z2510005 |
71
+ | 8.00x | MThd | 1 | Z2510003 |
72
+
73
+ **Old (incorrect):**
74
+ - 20x: 1 file ❌ (removed)
75
+
76
+ ---
77
+
78
+ ## ✅ Testing
79
+
80
+ ### Test Results
81
+
82
+ ```
83
+ $ npm run test:emk
84
+
85
+ ✅ Passed: 9/9
86
+ ⚠️ Warnings: 0/9
87
+ ❌ Failed: 0/9
88
+
89
+ 🎉 All tests passed!
90
+ ```
91
+
92
+ ### Specific Test: Z2510006
93
+
94
+ ```
95
+ Testing: Z2510006.emk
96
+ ✅ PASS: All checks passed
97
+
98
+ Comparison with Reference KAR:
99
+ Converted Tempo: 87.00 BPM
100
+ Reference Tempo: 87.00 BPM
101
+ Match: YES ✅
102
+
103
+ Converted Duration: 256.64 s (4:16)
104
+ Reference Duration: 256.64 s (4:16)
105
+ Difference: 0.00 s
106
+ Match: YES ✅
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 📝 Changed Files
112
+
113
+ ### Core Library
114
+
115
+ 1. **src/ncntokar.ts**
116
+ - Updated `fixEmkMidiTempo()` function
117
+ - Added PPQ >= 480 check
118
+
119
+ 2. **src/ncntokar.browser.ts**
120
+ - Updated `fixEmkMidiTempoBrowser()` function
121
+ - Same PPQ >= 480 logic
122
+
123
+ ### Documentation
124
+
125
+ 3. **EMK_REFERENCE_DATA.json**
126
+ - Updated Z2510006 expected values
127
+ - Tempo: 1740 → 87 BPM
128
+ - Duration: 12.83 → 256.64s
129
+ - Ratio: 20x → 1x
130
+
131
+ 4. **SONG_LIST.txt**
132
+ - Updated Z2510006 information
133
+ - Fixed duration statistics
134
+
135
+ ---
136
+
137
+ ## 🚀 Migration
138
+
139
+ ### From v1.5.1 to v1.5.2
140
+
141
+ **No Breaking Changes!**
142
+
143
+ Simply update:
144
+
145
+ ```bash
146
+ npm install @karaplay/file-coder@1.5.2
147
+ ```
148
+
149
+ **All existing code continues to work.**
150
+
151
+ ### What Changed
152
+
153
+ If you were converting `Z2510006.emk` or similar files with PPQ >= 480:
154
+
155
+ **Before (v1.5.1):**
156
+ ```typescript
157
+ // Would produce incorrect 12-second file
158
+ convertEmkToKar({
159
+ inputEmk: 'Z2510006.emk',
160
+ outputKar: 'output.kar'
161
+ });
162
+ // Duration: 0:12 ❌
163
+ ```
164
+
165
+ **After (v1.5.2):**
166
+ ```typescript
167
+ // Now produces correct 4:16 file
168
+ convertEmkToKar({
169
+ inputEmk: 'Z2510006.emk',
170
+ outputKar: 'output.kar'
171
+ });
172
+ // Duration: 4:16 ✅
173
+ ```
174
+
175
+ ---
176
+
177
+ ## 🎓 Technical Details
178
+
179
+ ### PPQ (Pulses Per Quarter Note)
180
+
181
+ **Common PPQ Values:**
182
+ - 96: Standard (ratio = 96/24 = 4x)
183
+ - 120: Standard (ratio = 120/24 = 5x)
184
+ - 480: High resolution (ratio = 1x, no conversion needed)
185
+
186
+ **Why PPQ 480 is different:**
187
+ - Higher temporal resolution
188
+ - Usually means the file is already properly timed
189
+ - Common in professional MIDI editors
190
+ - Doesn't need our EMK tempo correction
191
+
192
+ ### Detection Logic
193
+
194
+ ```typescript
195
+ // ZXIO: Always 1.24x
196
+ if (isZxioFormat) {
197
+ return ticksPerBeat / 77.42;
198
+ }
199
+
200
+ // High PPQ: No conversion
201
+ if (ticksPerBeat >= 480) {
202
+ return 1.0; // ← NEW in v1.5.2
203
+ }
204
+
205
+ // Standard MThd: Calculate ratio
206
+ return ticksPerBeat / 24;
207
+ ```
208
+
209
+ ---
210
+
211
+ ## 📚 Documentation
212
+
213
+ ### Updated Documentation
214
+
215
+ - [SONG_LIST.txt](./SONG_LIST.txt) - Corrected Z2510006 info
216
+ - [EMK_REFERENCE_DATA.json](./EMK_REFERENCE_DATA.json) - Updated test data
217
+ - [RELEASE_v1.5.2.md](./RELEASE_v1.5.2.md) - This file
218
+
219
+ ### Related Documentation
220
+
221
+ - [TEMPO_TRICKS_SUMMARY.md](./TEMPO_TRICKS_SUMMARY.md) - Tempo handling guide
222
+ - [EMK_TEST_SUITE_README.md](./EMK_TEST_SUITE_README.md) - Test suite guide
223
+ - [EMK_SONGS_INFO.md](./EMK_SONGS_INFO.md) - Song information
224
+
225
+ ---
226
+
227
+ ## ✨ Summary
228
+
229
+ **Fixed:** Z2510006.emk now converts correctly with proper 4:16 duration
230
+ **Added:** Support for high PPQ files (PPQ >= 480)
231
+ **Status:** All 9/9 tests pass ✅
232
+ **Breaking:** None - fully backward compatible
233
+
234
+ ---
235
+
236
+ **Recommended Action:** Update to v1.5.2 if you're converting files with high PPQ values.
237
+
238
+ **npm:** https://www.npmjs.com/package/@karaplay/file-coder