@karaplay/file-coder 1.5.0 β†’ 1.5.1

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/DEMO_ENHANCED.md CHANGED
@@ -1,168 +1,241 @@
1
- # ✨ Demo Enhanced with EMK Analysis & Comparison
2
-
3
- ## 🎯 New Features Added
4
-
5
- ### 1. **EMK File Analysis** (Before Conversion)
6
- When you select an EMK file, it now automatically analyzes:
7
- - βœ… Title and Artist (Thai encoding)
8
- - βœ… Format type (ZXIO or MThd)
9
- - βœ… **Original Tempo** (BPM)
10
- - βœ… **Original Duration** (seconds and minutes)
11
- - βœ… PPQ (Ticks per beat)
12
- - βœ… Number of tracks
13
- - βœ… Number of notes
14
- - βœ… Lyric and cursor data size
15
-
16
- ### 2. **Comparison Table** (EMK vs KAR)
17
- After conversion, see a detailed comparison:
18
- - πŸ“Š Format changes
19
- - πŸ“Š Tempo ratio (e.g., 2.78x for ZXIO, 4x for MThd)
20
- - πŸ“Š Duration changes
21
- - πŸ“Š Tempo verification (βœ… or ⚠️)
22
- - πŸ“Š Track and note count
23
- - πŸ“Š Visual indicators for increases/decreases
24
-
25
- ## πŸš€ How to Use
26
-
27
- ### Step 1: Open Demo
28
- ```
29
- http://localhost:3000/demo-simple.html
30
- ```
1
+ # Demo Page Enhanced - MIDI Player
31
2
 
32
- ### Step 2: Select EMK File
33
- - Click on any EMK file
34
- - **Wait for automatic analysis** (1-2 seconds)
35
- - See original EMK info displayed
3
+ **Date:** 2026-01-13
4
+ **Version:** v1.5.0 with MIDI Player
36
5
 
37
- ### Step 3: Convert to KAR
38
- - Click "Convert to KAR"
39
- - Wait for conversion
40
- - See converted KAR info
6
+ ## 🎡 New Feature: MIDI Player
41
7
 
42
- ### Step 4: View Comparison Table
43
- - Automatically displays after conversion
44
- - Compare original vs converted values
45
- - Verify tempo ratio is correct
8
+ ### Added to `demo-simple.html`
46
9
 
47
- ### Step 5: Download & Test
48
- - Click "Download KAR" to save file
49
- - Test with external karaoke player
10
+ #### 1. **UI Components**
11
+ - ▢️ **Play Button** - Start MIDI playback
12
+ - ⏸️ **Pause Button** - Pause playback (currently restarts on resume)
13
+ - ⏹️ **Stop Button** - Stop and reset playback
14
+ - **Progress Bar** - Visual playback progress
15
+ - **Time Display** - Current time / Total duration
16
+ - **Status Display** - Shows player state and messages
50
17
 
51
- ## πŸ“Š Sample Comparison Table
18
+ #### 2. **Libraries Used**
19
+ ```html
20
+ <!-- MIDI Parser -->
21
+ <script src="https://cdn.jsdelivr.net/npm/midi-parser-js@4.0.4/src/main.min.js"></script>
22
+
23
+ <!-- Soundfont Player for audio synthesis -->
24
+ <script src="https://cdn.jsdelivr.net/npm/soundfont-player@0.12.0/dist/soundfont-player.min.js"></script>
25
+ ```
52
26
 
27
+ #### 3. **Features**
28
+ - βœ… **Auto-initialize** - Loads instrument on first play
29
+ - βœ… **Parse MIDI** - Converts base64 KAR data to playable MIDI
30
+ - βœ… **Tempo-aware** - Respects MIDI tempo events
31
+ - βœ… **Real-time progress** - Updates every 100ms
32
+ - βœ… **Multi-track support** - Plays all MIDI tracks simultaneously
33
+ - βœ… **Note scheduling** - Uses Web Audio API for precise timing
34
+ - βœ… **Piano soundfont** - Uses Acoustic Grand Piano (MusyngKite)
35
+
36
+ #### 4. **How It Works**
37
+
38
+ **Step 1: Initialization**
39
+ ```javascript
40
+ await initMidiPlayer();
41
+ // Creates AudioContext
42
+ // Loads soundfont from: https://gleitz.github.io/midi-js-soundfonts/
53
43
  ```
54
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
55
- β”‚ Property β”‚ Original EMK β”‚ Converted KAR β”‚ Change β”‚
56
- β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
57
- β”‚ Format β”‚ ZXIO β”‚ ZXIO β”‚ Same β”‚
58
- β”‚ Tempo (BPM) β”‚ 64.00 β”‚ 178.09 β”‚ Γ—2.78 (increase)β”‚
59
- β”‚ Duration (seconds) β”‚ 351.56 β”‚ 126.34 β”‚ Γ—0.36 (decrease)β”‚
60
- β”‚ Duration (minutes) β”‚ 5.86 β”‚ 2.11 β”‚ 64.1% shorter β”‚
61
- β”‚ PPQ β”‚ 96 β”‚ Same β”‚ Unchanged β”‚
62
- β”‚ Tracks β”‚ 25 β”‚ Same + Karaoke β”‚ +1 (lyrics) β”‚
63
- β”‚ Notes β”‚ 6313 β”‚ 6313 β”‚ Same β”‚
64
- β”‚ Tempo Ratio β”‚ - β”‚ 2.78x β”‚ βœ… Correct β”‚
65
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
44
+
45
+ **Step 2: Parse MIDI**
46
+ ```javascript
47
+ parseMidiData(base64Data);
48
+ // Decodes base64 β†’ Uint8Array
49
+ // Parses with MidiParser.js
50
+ // Extracts tempo, PPQ, notes
66
51
  ```
67
52
 
68
- ## 🎯 What to Verify
53
+ **Step 3: Schedule Notes**
54
+ ```javascript
55
+ // Converts ticks to seconds
56
+ ticksToSeconds(ticks, tempo, ppq);
57
+
58
+ // Schedules note events
59
+ instrument.play(midiNote, scheduleTime, options);
60
+ ```
69
61
 
70
- ### ZXIO Format (001.emk, failed01.emk)
71
- **Original EMK:**
72
- - Tempo: 64 BPM
73
- - Duration: ~5.86 minutes (351 seconds)
62
+ **Step 4: Playback Control**
63
+ ```javascript
64
+ playMidi() // Start playback
65
+ pauseMidi() // Stop all notes
66
+ stopMidi() // Reset to beginning
67
+ ```
74
68
 
75
- **Converted KAR:**
76
- - Tempo: **178.09 BPM** (2.78x)
77
- - Duration: **~2.11 minutes** (126 seconds)
78
- - Tempo Ratio: βœ… **Correct (2.78x)**
69
+ ## 🎯 Usage
79
70
 
80
- ### MThd Format (Z2510001.emk)
81
- **Original EMK:**
82
- - Tempo: 67 BPM
83
- - Duration: Variable
71
+ ### 1. Convert EMK to KAR
72
+ 1. Select an EMK file from the list
73
+ 2. Click "πŸ”„ Convert to KAR"
74
+ 3. Wait for conversion to complete
84
75
 
85
- **Converted KAR:**
86
- - Tempo: **268 BPM** (4x)
87
- - Duration: Adjusted proportionally
88
- - Tempo Ratio: βœ… **Correct (4x)**
76
+ ### 2. Play Converted KAR
77
+ 1. After successful conversion, MIDI Player appears
78
+ 2. Click "▢️ Play" to start playback
79
+ 3. Use "⏸️ Pause" or "⏹️ Stop" to control playback
89
80
 
90
- ## πŸ” New API Endpoint
81
+ ### 3. Monitor Playback
82
+ - **Progress Bar** - Shows current position
83
+ - **Time Display** - Shows current time / total duration
84
+ - **Status** - Shows player state (Playing, Paused, Stopped)
91
85
 
92
- ### POST `/api/analyze-emk`
93
- Analyze EMK file before conversion
86
+ ## πŸ”§ Technical Details
94
87
 
95
- **Request:**
96
- ```json
97
- {
98
- "filename": "001.emk"
99
- }
88
+ ### MIDI Processing
89
+
90
+ **Tempo Calculation:**
91
+ ```javascript
92
+ microsecondsPerBeat = (data[0] << 16) | (data[1] << 8) | data[2];
100
93
  ```
101
94
 
102
- **Response:**
103
- ```json
104
- {
105
- "success": true,
106
- "emkInfo": {
107
- "format": "ZXIO",
108
- "title": "ΰΈ„ΰΈ™ΰΈΰΈ£ΰΈ°ΰΈˆΰΈ­ΰΈ",
109
- "artist": "ΰΈšΰΈΈΰΉŠΰΈ„ ΰΈ¨ΰΈΈΰΈ ΰΈΰΈ²ΰΈΰΈˆΰΈ™ΰΉŒ",
110
- "tempo": "64.00",
111
- "duration": "351.56",
112
- "durationMinutes": "5.86",
113
- "ppq": 96,
114
- "tracks": 25,
115
- "notes": 6313,
116
- "hasLyrics": 3456,
117
- "hasCursor": 3742
118
- }
119
- }
95
+ **Time Conversion:**
96
+ ```javascript
97
+ seconds = (ticks Γ— microsecondsPerBeat) / (ppq Γ— 1000000)
120
98
  ```
121
99
 
122
- ## πŸ“ˆ Visual Indicators
100
+ **Note Events:**
101
+ - **Type 9 (Note On):** data[0] = note, data[1] = velocity
102
+ - **Type 8 (Note Off):** data[0] = note
103
+ - **Type 255, Meta 81:** Set Tempo event
104
+
105
+ ### Audio Synthesis
106
+
107
+ **Soundfont:**
108
+ - Source: `https://gleitz.github.io/midi-js-soundfonts/`
109
+ - Format: MusyngKite (high quality)
110
+ - Instrument: Acoustic Grand Piano
111
+
112
+ **Web Audio API:**
113
+ - Uses `AudioContext` for precise timing
114
+ - Schedules notes in advance
115
+ - Supports dynamic gain (velocity)
123
116
 
124
- ### Tempo Ratio Status
125
- - βœ… **Correct (2.78x)** - ZXIO format with correct tempo
126
- - βœ… **Correct (~4x)** - MThd format with correct tempo
127
- - ⚠️ **Unexpected** - Tempo ratio doesn't match expected value
117
+ ## πŸ“Š Testing
128
118
 
129
- ### Change Indicators
130
- - 🟑 **Yellow badge** - Increase (tempo, duration)
131
- - 🟒 **Green badge** - Decrease (expected for ZXIO duration)
132
- - βšͺ **Gray badge** - Same/Unchanged
119
+ ### Test File: `001_original_emk.emk`
120
+
121
+ **Expected Results:**
122
+ ```
123
+ Format: ZXIO
124
+ Tempo: 79 BPM
125
+ Duration: 4:43 (283 seconds)
126
+ Tracks: 25
127
+ Notes: 6313
128
+ ```
133
129
 
134
- ## πŸŽ‰ Benefits
130
+ **Playback:**
131
+ - βœ… Should play piano notes
132
+ - βœ… Should follow correct tempo (79 BPM)
133
+ - βœ… Should complete in ~4:43
134
+ - βœ… Progress bar should update smoothly
135
+ - βœ… Time display should increment correctly
135
136
 
136
- ### For Testing
137
- 1. **Before/After Comparison** - See exact changes from conversion
138
- 2. **Tempo Verification** - Confirm correct ratio is applied
139
- 3. **Duration Accuracy** - Verify music length is correct
140
- 4. **Format Detection** - Ensure ZXIO vs MThd is identified correctly
137
+ ## πŸ› Known Limitations
141
138
 
142
- ### For Documentation
143
- 1. **Clear Evidence** - Shows conversion works correctly
144
- 2. **Ratio Validation** - Proves 2.78x (ZXIO) and 4x (MThd) formulas
145
- 3. **Quality Assurance** - Demonstrates accurate metadata preservation
139
+ 1. **Pause/Resume**
140
+ - Currently restarts playback from beginning
141
+ - Full resume from pause position requires state tracking
146
142
 
147
- ### For Debugging
148
- 1. **Original Values** - Reference point for troubleshooting
149
- 2. **Detailed Metrics** - Track count, note count, PPQ
150
- 3. **Format Info** - Identify which conversion path was used
143
+ 2. **Instrument**
144
+ - Only uses piano soundfont
145
+ - Does not respect MIDI program changes (instrument selection)
151
146
 
152
- ## πŸš€ Ready to Test!
147
+ 3. **Performance**
148
+ - Large MIDI files (>10,000 notes) may cause lag
149
+ - All notes are scheduled at once
153
150
 
154
- **Server is running at:**
151
+ 4. **Browser Support**
152
+ - Requires Web Audio API support
153
+ - Tested on Chrome, Firefox, Safari
154
+
155
+ ## πŸš€ Future Improvements
156
+
157
+ 1. **Lyrics Display**
158
+ - Show synchronized lyrics during playback
159
+ - Highlight current lyric line
160
+
161
+ 2. **Multiple Instruments**
162
+ - Load different soundfonts per track
163
+ - Respect MIDI program changes
164
+
165
+ 3. **Better Pause**
166
+ - Resume from exact pause position
167
+ - Maintain note states
168
+
169
+ 4. **Visualization**
170
+ - Piano roll display
171
+ - Waveform visualization
172
+ - Spectrum analyzer
173
+
174
+ 5. **Playback Controls**
175
+ - Speed control (0.5x, 1x, 2x)
176
+ - Volume control
177
+ - Seek bar (click to jump)
178
+
179
+ ## πŸ“ Code Structure
180
+
181
+ ```
182
+ demo-simple.html
183
+ β”œβ”€β”€ UI Components
184
+ β”‚ β”œβ”€β”€ Play/Pause/Stop buttons
185
+ β”‚ β”œβ”€β”€ Progress bar
186
+ β”‚ β”œβ”€β”€ Time display
187
+ β”‚ └── Status panel
188
+ β”‚
189
+ β”œβ”€β”€ MIDI Player Object
190
+ β”‚ β”œβ”€β”€ ac: AudioContext
191
+ β”‚ β”œβ”€β”€ instrument: Soundfont instance
192
+ β”‚ β”œβ”€β”€ midiData: Parsed MIDI
193
+ β”‚ └── State: isPlaying, isPaused, etc.
194
+ β”‚
195
+ └── Functions
196
+ β”œβ”€β”€ initMidiPlayer() - Initialize audio
197
+ β”œβ”€β”€ parseMidiData() - Parse MIDI from base64
198
+ β”œβ”€β”€ playMidi() - Start playback
199
+ β”œβ”€β”€ pauseMidi() - Pause playback
200
+ β”œβ”€β”€ stopMidi() - Stop playback
201
+ └── ticksToSeconds() - Convert MIDI ticks to time
155
202
  ```
156
- http://localhost:3000/demo-simple.html
203
+
204
+ ## βœ… Verification
205
+
206
+ ### Server Running
207
+ ```bash
208
+ npm run demo
209
+ # Server: http://localhost:3000
210
+ # Demo: http://localhost:3000/demo-simple.html
157
211
  ```
158
212
 
159
- **Try it now:**
160
- 1. Select **001.emk** (ZXIO format)
161
- 2. See original info: 64 BPM, 5.86 minutes
162
- 3. Convert to KAR
163
- 4. See comparison: 178.09 BPM, 2.11 minutes
164
- 5. Verify: βœ… Tempo Ratio 2.78x Correct!
213
+ ### Test Conversion
214
+ 1. Open: `http://localhost:3000/demo-simple.html`
215
+ 2. Select: `001_original_emk.emk`
216
+ 3. Click: "πŸ”„ Convert to KAR"
217
+ 4. Verify: Tempo = 79 BPM, Duration = 4:43
218
+
219
+ ### Test Playback
220
+ 1. Click: "▢️ Play"
221
+ 2. Verify: Piano notes play
222
+ 3. Verify: Progress bar moves
223
+ 4. Verify: Time display updates
224
+ 5. Click: "⏹️ Stop"
225
+ 6. Verify: Playback stops, progress resets
165
226
 
166
227
  ---
167
228
 
168
- **Perfect for demonstrating v1.4.9 fixes! 🎀✨**
229
+ ## 🎊 Status: βœ… Complete
230
+
231
+ **Demo Page Features:**
232
+ - βœ… EMK file list
233
+ - βœ… File selection
234
+ - βœ… EMK analysis (before conversion)
235
+ - βœ… EMK to KAR conversion
236
+ - βœ… Metadata display
237
+ - βœ… Comparison table (EMK vs KAR)
238
+ - βœ… KAR file download
239
+ - βœ… **MIDI Player** (NEW!)
240
+
241
+ **Ready for testing and demonstration!** πŸŽ‰
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